您尚未登录,请登录后浏览更多内容! 登录 | 立即注册

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15207|回复: 0
打印 上一主题 下一主题

[Vue.js] Vue.js 组件

[复制链接]
跳转到指定楼层
楼主
发表于 2018-7-4 11:28:06 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
组件(Component)是 Vue.js 最强大的功能之一。
组件可以扩展 HTML 元素,封装可重用的代码。
组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树:
注册一个全局组件语法格式如下:
  1. Vue.component(tagName, options)
复制代码
tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件:
  1. <tagName></tagName>
复制代码
全局组件
所有实例都能用全局组件。
全局组件实例
注册一个简单的全局组件 runoob,并使用它:
) h- ]7 w* N/ M$ K/ m! A  ?8 o
  1. <div id="app">
    6 e6 n$ ?' c+ I: H7 I. s8 f1 ?
  2.     <runoob></runoob>
    6 m4 q* v' G1 \8 O& H
  3. </div>
    7 D1 `1 r" B( w( _. u
  4. 9 X! d, a2 W% B7 t
  5. <script>; n* G$ d, H& e; v- T* e
  6. // 注册
    # b  z( G5 Z5 Y4 E) }$ A
  7. Vue.component('runoob', {/ z  L% V" L1 Z6 d/ E8 I6 E
  8.   template: '<h1>自定义组件!</h1>'
    / K" ]6 O/ Y% V( y3 [
  9. })
    0 v) n! _; m% a
  10. // 创建根实例; V! C8 {) J7 l! L( z
  11. new Vue({
    % J8 f+ q. l5 i  C- q8 O" [* [
  12.   el: '#app'' Z3 E/ R2 H: f" ]' l: u
  13. })
    - O' @9 x# b, T3 Q4 g) @/ W
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

. h. j3 Q) \/ Z
  1. <div id="app">
      T) B  B+ k9 u  H- M# M3 v2 j' L
  2.     <runoob></runoob>& D( J- Y- a" ^3 ~* ?* C& i/ B
  3. </div>8 t- T7 j, j$ `- G: h

  4. $ u1 b4 Y; }+ M( ?* i% \
  5. <script>
    ' d4 K* C# e# W0 S2 n, [
  6. var Child = {0 J2 h( T5 _! T0 L" j+ `0 C+ E* }' e
  7.   template: '<h1>自定义组件!</h1>'
    8 b8 j& |8 e5 r1 T1 V( B
  8. }
    + a+ {( C$ v) ^, k

  9. 2 o) n! x0 X, g
  10. // 创建根实例$ i5 u" o. \  f8 U. P/ E
  11. new Vue({
    - o4 p2 v1 ]3 b% @
  12.   el: '#app',
    6 Q; L7 }7 D) d& \
  13.   components: {
    - m) j, O( Y6 R; F
  14.     // <runoob> 将只在父模板可用
    4 D4 _# d4 ~8 [; A+ e: r
  15.     'runoob': Child
    6 y; ], r+ ^* U+ [, G2 n2 V* A
  16.   }
    5 b  P3 @( T: |6 u! A
  17. })3 h% M& G+ n4 X& s0 q1 D! U% [: t9 z- c
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例* _# S+ P4 f( Y- U7 V+ n
  1. <div id="app">4 g  N' U0 ?. \0 m  g
  2.     <child message="hello!"></child>
    ) c* R% K& Z  H" i$ f3 _8 F% N! w7 i
  3. </div>8 M; w8 x. B2 `0 s4 T/ r  k! w

  4. ) \0 X8 V: I9 V& |3 s& A3 V" U9 r
  5. <script>
    . e+ s, t/ k. H7 |1 ?( S6 y2 j( ?
  6. // 注册6 J, T/ E: C7 E! i4 w
  7. Vue.component('child', {; R) _$ k3 R. y& i5 k2 |
  8.   // 声明 props" B5 f' [8 G! K# k* [6 ?4 m% k4 X
  9.   props: ['message'],
    % h' i- l- H0 o
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用! ~7 m$ a# V4 f* \( d
  11.   template: '<span>{{ message }}</span>'  w# G2 \8 y: N0 q/ k7 {  u0 H: p
  12. })
    2 q* V, t( W4 a( t
  13. // 创建根实例
    # r" Z5 ~, x. w* y( j3 y" j1 Z" @
  14. new Vue({
    $ l* v+ z# H2 c/ Q$ E& w
  15.   el: '#app'
    ! c- l& e; k$ \4 V# u
  16. })
    3 U( s7 }5 o' Y
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
' Z- P) J8 b7 L; u1 P
  1. <div id="app">
    9 g; O/ \+ n' L6 }7 j
  2.     <div>
    0 v/ g' U. l& s0 Y. U
  3.       <input v-model="parentMsg">
    / x5 P6 F5 a2 S4 O0 q8 I% J
  4.       <br>* t8 I- |" }0 n1 H
  5.       <child v-bind:message="parentMsg"></child>
    5 @9 g2 @; a* N. K, t: Q# r
  6.     </div>0 J) _1 d/ r6 _2 J9 `. W
  7. </div>
    ) L; F- H# V$ H+ }4 l  w

  8. # a# L* S6 Z/ h! R6 I+ ^
  9. <script>7 k/ L, l% p& J/ E, n: W! D
  10. // 注册
    5 P' u! M: f2 b( E
  11. Vue.component('child', {( S. l; z% o: G* P3 f7 _
  12.   // 声明 props  g$ ~, I- W; e( g, D* E! X7 z- h
  13.   props: ['message'],% I0 n3 e9 a' L3 y+ O# W0 g
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用1 ~( ]* V5 J8 s) T$ N; m% l
  15.   template: '<span>{{ message }}</span>') n) O; t8 V: N7 Y8 \2 P( G: l
  16. })
    1 C9 M( z% L9 t! O' w9 }
  17. // 创建根实例; H- D0 K" `1 N
  18. new Vue({
    & Y- v+ k: Z$ `* n
  19.   el: '#app',
    6 Y$ Z0 Z! E& u) ?! h. \
  20.   data: {
    1 I. C/ L. w) ~2 h
  21.     parentMsg: '父组件内容', `" _) O4 }" _& F
  22.   }
    ( _2 P9 Z+ p' z' Q, ~
  23. })
    / B5 Q% V' Y" L$ [
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
: L+ \" W  q8 h' `  M' v
  1. <div id="app">7 \  u- B6 q7 t7 o* ^$ z9 f4 k! R/ _4 h
  2.     <ol>) E: g7 M- d$ u) S3 U4 c0 E
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>! H* D6 j5 K) I/ C& S" N! Y
  4.       </ol>
    0 C( {. B. L$ a( W9 `. H
  5. </div>4 x; t6 c/ ]2 L2 ^: y) v
  6. . V4 Y; S9 O% V8 z1 _/ ^) X
  7. <script>
    & e8 Q7 H1 E" X+ t+ m
  8. Vue.component('todo-item', {4 g( c. x$ h$ `* H* s+ e4 G/ {) ?8 ^0 t
  9.   props: ['todo'],
    8 X6 a4 j1 r; _& T% h" E; B
  10.   template: '<li>{{ todo.text }}</li>'
    * b6 X6 M& O+ N- {' Z# X
  11. })1 x$ z- x* K. \- C- s; m) C8 |
  12. new Vue({2 r7 K6 o  F9 h8 ?
  13.   el: '#app',% V# A$ T& O2 U; x1 J, P/ N
  14.   data: {* d6 j6 u8 r  T9 e3 t: u
  15.     sites: [
    ( J1 ~: ?$ Y9 g3 q8 O2 `. ?
  16.       { text: 'Runoob' },
    3 y# B* o2 M6 C" X: i. u* f% l
  17.       { text: 'Google' },
    ( u$ `6 q8 p$ S. K$ o! I- v& O/ r
  18.       { text: 'Taobao' }
    . j/ l4 h( Q- s) }7 D* E( a* O5 U
  19.     ]
    ; I9 F5 ]  G, T/ H* o. W# U
  20.   }
    + y6 N6 u- S9 t3 A* |' k/ Z: x
  21. })
    + E! h9 e# L* v1 e4 R( Y5 q" h9 J
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {3 W3 @& Y2 G  N" E8 y- K; i& d2 }
  2.   props: {5 X4 H( o- H! Z% D; t
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)6 h" n% u0 h, R5 W
  4.     propA: Number,
    1 F& P% D$ L& Z; q. i* p" O6 P: M+ Q
  5.     // 多种类型
    ! q- Q8 q! }0 _8 A6 y' \3 D
  6.     propB: [String, Number],7 V: b: z% r& O8 t& S8 o* h) B2 ~, W: y
  7.     // 必传且是字符串' i' c+ j- w/ o8 R
  8.     propC: {
    8 g3 ]1 L3 a+ C8 g. h8 W
  9.       type: String,
    ) c- Z) m  G5 X" w8 _
  10.       required: true3 g8 K! |0 a' l0 a$ H, X
  11.     },
    - F; m9 }8 C  d) |$ r
  12.     // 数字,有默认值
    ; K2 W* w6 r# t8 ^
  13.     propD: {
    1 N& z) \* s7 S8 T$ F
  14.       type: Number,
    ; f) {% w, x' f0 e& d
  15.       default: 100
    , C4 \  s, D: J4 L' n$ O
  16.     },) d, S6 t7 M9 M, f- w
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    ! l* S: w+ G/ i& O4 O4 {
  18.     propE: {7 {- ?9 p7 P  _. A, L& ?+ L
  19.       type: Object,
    ' z; q  t# A$ R, d  R* [5 M- v
  20.       default: function () {
    " k- W$ k3 X0 Z" j- y' Y
  21.         return { message: 'hello' }  \! x, {6 y* E/ P
  22.       }5 o1 e( V, f# A! f$ V# M
  23.     },
    9 f9 q7 _7 A7 \- d/ f
  24.     // 自定义验证函数
    & R# x+ P/ I! X; y# u6 A
  25.     propF: {, n7 [3 ?5 b: q% o$ K  w& ~
  26.       validator: function (value) {7 n6 t! P+ G: {; S% i8 w
  27.         return value > 10( r$ _0 p2 m1 m; i
  28.       }
    , y" \* D( _- X! R/ \, c1 p
  29.     }
    + N/ x  ^5 V% p- G. q+ w6 i
  30.   }9 \0 ?- q. z) u; ~3 p6 S
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    ' `; D$ |( Z! @' n% x! t; \& o% P
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
      ~4 I8 u- A5 `
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
% T$ q) Q; Z; Y  r4 P
  1. <div id="app">1 n# F# A# V& Q; a4 v2 _% n  _
  2.     <div id="counter-event-example">$ W2 B2 W) i6 h2 M+ y
  3.       <p>{{ total }}</p>. W4 ~, [7 A* W/ B! P' \6 p: v2 o
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>% Y5 C3 r6 `% j$ x4 ]
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    8 ]7 y. t, |7 ]5 i- d4 n; w0 \& k
  6.     </div>4 C- }: m5 `+ h5 O# l) K: O
  7. </div>
    6 j5 ^) b- o% u9 J+ V; \& |
  8. : V: {- L: j" _+ n7 j
  9. <script>: J; g5 S' u' [: U; T) Q/ v3 ]6 E
  10. Vue.component('button-counter', {5 y: @7 A6 |; P, B" K7 q3 h
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    % e3 s! W5 Z' d4 ^
  12.   data: function () {8 l- q; i1 h  d* G
  13.     return {2 U& l' B+ q; l$ e* U
  14.       counter: 08 M. n% _: g2 O" N# P
  15.     }1 y  p5 h! k/ t: o( I3 d  Q  I
  16.   },# }6 t0 x1 l4 E6 x- ^9 g1 e% a
  17.   methods: {
    ; h0 A" S6 T4 T' e6 l' \- F8 b
  18.     incrementHandler: function () {
    8 L  w) b( \) \5 ]3 ?4 j, y
  19.       this.counter += 1. q  V) S* d- O. x. l
  20.       this.$emit('increment'); E8 K1 _$ A0 n7 Z. d
  21.     }# J' x  O* `3 h( V
  22.   },
    / c% h: w0 g9 E9 z
  23. }); O+ O& J& x( K) L( M" L# |, ]+ I
  24. new Vue({1 e1 g+ A7 J/ V- V- z& d
  25.   el: '#counter-event-example',3 b' M! J) B8 G+ S9 C7 [
  26.   data: {+ J* j: s" I  S* b
  27.     total: 0( F) p8 B9 u( V
  28.   },
    ! k2 b1 n' t* L  W
  29.   methods: {2 ^/ \8 T8 ^) c& K! @
  30.     incrementTotal: function () {
    3 H5 B$ f/ _9 L
  31.       this.total += 1. q. y* S8 D4 q! }4 ?4 a8 d! n
  32.     }
    : Y5 A$ @8 c) A4 X3 m
  33.   }
    % c6 _, A. M/ d8 `
  34. }): \) i* T& V& c
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册9 z( Q7 N+ V4 C, P& x' I2 X
  2. Vue.component('child', {
    8 v" W. r8 m8 I
  3.   // 声明 props$ N/ v+ ]) ~$ g2 U% ^% O% _
  4.   props: ['message'],- s7 G; c* u2 Q  a* G+ n8 T
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    7 N0 l8 q, t. U9 s* y+ ~
  6.   template: '<span>{{ message }}</span>'+ V3 b6 j$ s* @- ]5 w
  7. })" Y3 s. J( z: h0 w* q7 j8 C
  8. // 创建根实例- G( \1 j" \1 o" k5 w8 I* [
  9. new Vue({/ c# u- y* t6 ~3 r* L
  10.   el: '#app',1 @. Y9 s& }; X$ G& ?5 K% t
  11.   data:{, M. b7 V: N# u% Z7 [
  12.     message:"hello",- ]7 @% [. I- B- N4 U; M1 J+ e
  13.   }# n, \- v. c! F2 G1 E# c+ p
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {: W3 l' F$ i: P, J
  2.     incrementHandler: function (v) {% {3 C4 T5 S8 }+ t5 X+ E/ p
  3.         if(v==1){+ J5 m: N% }2 M8 J
  4.             this.counter -= 1
    , B/ a  I  W( U+ i/ D7 g
  5.             this.$emit('increment',[1])
    + U/ m- C% d" b. ^# c9 ?
  6.         }else{
    ! W  V$ I: C" p, T7 R+ \" q  M+ p7 H9 a
  7.             this.counter += 1
    # K' G  r" W# v* U
  8.             this.$emit('increment',[2])3 f% Z: v% s1 @7 D2 t
  9.         }
    8 |- L9 b1 b( ?4 ]
  10.     }
    0 \9 D! `* Y6 H0 O4 |  H
  11. }
复制代码

( H( f$ {+ F+ v% J; b
9 b, @; ?# Q3 q% v
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 14:42 , Processed in 0.069296 second(s), 22 queries .

Copyright © 2001-2026 Powered by cncml! X3.2. Theme By cncml!