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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15825|回复: 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,并使用它:

/ Y7 D: [& I; T% o6 p8 s$ r
  1. <div id="app">. Y7 A- K' X: U* J
  2.     <runoob></runoob>: W/ b/ b9 q" p/ ]
  3. </div>
    1 [5 ]- u1 J% C: }/ i

  4. ! g. {0 x2 q: a7 l% I
  5. <script>
    4 d- T' V5 P! y
  6. // 注册
    : i6 I- h; A7 ]5 `" R9 o
  7. Vue.component('runoob', {
    * w0 ]* n" W* x+ M4 U
  8.   template: '<h1>自定义组件!</h1>'7 ?3 u  I6 |# c0 f
  9. }); y# N$ N) H( C1 ?4 w) j
  10. // 创建根实例% D" j% E  N# d% K- ^+ |
  11. new Vue({
    5 b& S0 n5 y+ Y0 i; i/ J
  12.   el: '#app'
    ; l; j9 a/ `6 R, h/ ?: H6 c
  13. })
    2 S9 G) F- C1 Q7 ]
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
8 s' b7 ~4 `" o9 j! r
  1. <div id="app">% P1 d- n* _: d6 ~7 c
  2.     <runoob></runoob>- l+ A  F% c$ _7 n; l: {
  3. </div>( _+ ^9 @1 B6 D) P4 e& C' E
  4. - C2 U8 e% ?" p  z& C8 x0 w
  5. <script>
    * P0 ^9 ]; A- h7 i6 L7 J5 U" A
  6. var Child = {" I2 H' }  J( v$ X
  7.   template: '<h1>自定义组件!</h1>'
    8 B2 x! V; E( y- V
  8. }4 |) J( u0 L% ?  x" V# \

  9. " _9 p" G  X& {7 g5 q& U$ q; d
  10. // 创建根实例! h9 o% W+ Z& Q6 ]2 u
  11. new Vue({
    + c+ A, N' }# {  f: q4 m+ q
  12.   el: '#app',
    0 H: P" }: L9 b2 T
  13.   components: {
    7 \' H9 N  F7 |- i- {3 {
  14.     // <runoob> 将只在父模板可用
    3 f, o8 E( {; D% S. ~
  15.     'runoob': Child9 d( h2 d3 ~" E2 V* F8 D
  16.   }
    . Q! P7 X/ {3 x' ^, j5 F  N
  17. })  P6 T# d7 t; t5 K
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例6 j' g5 L4 Z9 i! K4 E  O6 |) x4 S
  1. <div id="app">! h  s" _# R% [* _: ^
  2.     <child message="hello!"></child>7 {4 q5 ~5 K4 I( e9 t& n# J
  3. </div>
    1 |( X4 F' A' Z5 n* @& |" g

  4. ' p  {: U" c# \! |
  5. <script>- p* d0 T. H8 h1 j/ \! `: p! ]2 b
  6. // 注册. {$ M3 ?5 m: o. z+ @6 h
  7. Vue.component('child', {7 ]1 @, T* ?1 J# H
  8.   // 声明 props! T- f' n8 ]9 }& {* H
  9.   props: ['message'],- \/ K. A* c- z' e; n
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用# n! g6 @/ F( H0 t" X
  11.   template: '<span>{{ message }}</span>'  a  I1 M) p* n0 U$ Q2 p
  12. })5 h5 `9 u8 T5 G
  13. // 创建根实例, O9 U) x" {( |/ j( I
  14. new Vue({/ o6 j5 p  y8 V* x' i
  15.   el: '#app'- n& C! b, Y5 J! h
  16. })
    ! M) u: x8 F4 S
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例6 r9 {. Z. ^0 `3 _" r& o
  1. <div id="app">
    : B& I5 @* y2 `
  2.     <div>
    " ?$ f, b; [7 V6 G
  3.       <input v-model="parentMsg">
    ! Q) V/ I) q+ `% j0 |
  4.       <br>
    # t4 y* x$ _$ c2 P5 P3 s- i
  5.       <child v-bind:message="parentMsg"></child># b) x  M* S: G& X5 X
  6.     </div>5 @  c5 c) @+ z% P1 F
  7. </div>- _" u# {" ]$ }% i/ W- n: Y
  8. 0 _! x0 Q3 A; l% r/ Z! V, q% O
  9. <script>
    ' B4 P5 h0 a% e( r- N
  10. // 注册
    : b8 h1 I5 D1 |: ~
  11. Vue.component('child', {
    * I) _) n+ n3 w2 ~
  12.   // 声明 props
      f* v0 j6 `- L$ s
  13.   props: ['message'],
    6 J7 W- @- z1 r4 U9 g
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    , J: W5 ^. J; o8 ?. [9 k0 _
  15.   template: '<span>{{ message }}</span>'& q! i; c' K' x; b! Y* U5 b, g3 w4 x
  16. })
    ) J( K" L$ G' }8 x3 R
  17. // 创建根实例
    2 X" T' s4 j/ Y
  18. new Vue({
    , D/ f+ q0 e$ O9 \# [* f- P, a0 X
  19.   el: '#app',
    ; V0 A( r8 z* P5 P
  20.   data: {
    + s: ?3 d  k3 [5 h, |" B& b  P
  21.     parentMsg: '父组件内容'
    2 s5 C* b" I. y, ~4 H: |6 x
  22.   }9 J9 M6 e; A, z% I* }: v7 l
  23. })
    0 E$ I0 Y' U+ g& J2 |; o* n8 n
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
* v* b' C9 h  R9 [# g* P
  1. <div id="app">  I4 {2 W1 S. b. C) g
  2.     <ol>  P& h- N; g+ q1 v: B
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>$ u1 P( m0 J, j- b
  4.       </ol>
    * _2 Z& ~. m1 [' Y: @8 M7 R
  5. </div>  j& q5 ^) G6 C9 P# Q; @7 i8 x
  6. ! u$ e$ V: r2 O2 n; Z
  7. <script>+ f+ V6 U" ?6 m7 N/ O$ Z0 f
  8. Vue.component('todo-item', {% P8 F6 p# h; z
  9.   props: ['todo'],9 N9 a( _( y$ R; ~
  10.   template: '<li>{{ todo.text }}</li>'. x1 d/ _: }" B8 ]7 k4 w
  11. })
    7 \/ t; i8 Z" d4 ?9 [" m. G
  12. new Vue({8 w& |. R  M6 C: s
  13.   el: '#app',- P7 ~; l& _% g  G; O. o1 J7 F
  14.   data: {
    + a; F! c+ ?9 f: l. ~; \
  15.     sites: [  [6 A$ m+ G! D
  16.       { text: 'Runoob' },
    1 \7 y; q! u3 I% }+ n- M
  17.       { text: 'Google' },
    4 @: K/ R4 q; ]
  18.       { text: 'Taobao' }- H, g9 S) v  @! G( v2 {5 `) U
  19.     ]
    5 u& J1 _3 V* F
  20.   }' D2 e3 f2 m9 d; L# J& j8 k0 W
  21. })( s! M* V. v( L3 B
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {. S+ r. J) F2 m9 i# I
  2.   props: {
    + N: _; y/ o' A; g% V
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)0 ?5 o/ W$ _) o+ _* Q: h$ f4 K
  4.     propA: Number,
    ( p: B/ U' @9 S9 Q/ E/ r& b
  5.     // 多种类型: P; `3 P9 K% I, K
  6.     propB: [String, Number],
    6 q2 c: K  Q: j* O1 Z3 C- r
  7.     // 必传且是字符串& h. j  q0 F/ {
  8.     propC: {
    8 f4 p( b* M1 k7 k/ A! ~( d4 \
  9.       type: String,
    - J: u5 w$ O$ H; o: o8 t
  10.       required: true8 ~! ~! F- g: M5 w% I
  11.     },
    8 F1 W" N8 P5 F% T9 b2 p5 h
  12.     // 数字,有默认值) |2 q5 U5 K2 H9 _, K
  13.     propD: {
    " L+ h4 T3 L" s- ~: v" [) F
  14.       type: Number,
    4 w1 n) J; P. V+ a! I! L( D6 j; C
  15.       default: 100# N: l" R/ `  b% S
  16.     },
    - \+ W/ b2 \+ A6 u
  17.     // 数组/对象的默认值应当由一个工厂函数返回6 |- S* z( K8 G' Q& D5 e+ L
  18.     propE: {, K+ l# z% ^$ r2 }0 X8 b# T* H
  19.       type: Object,% s0 a$ F6 z7 P. M5 f% d5 j
  20.       default: function () {+ G0 ~8 N+ A0 V6 y
  21.         return { message: 'hello' }2 W5 d# [+ Y+ C- R8 B) ~7 n- |
  22.       }- ?1 g# F' X9 I* Y+ T6 y
  23.     },
    ( X: k! u4 B7 d7 s, y, v" ^
  24.     // 自定义验证函数- Q: z: ?8 c% K) H5 p# g
  25.     propF: {. H* @& S, b% F! [+ I7 D
  26.       validator: function (value) {
    7 m1 V6 l$ I8 A
  27.         return value > 10
    ; A+ M0 a  p  i: ^
  28.       }. J# F; a/ `, X) |
  29.     }% n: Q5 P  _- e, @" p) P, b$ k
  30.   }
    & w( X: d7 H7 ~) b  M4 s
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    ) e( b" p& G1 `: ^
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    / `0 K/ c3 E( l
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
5 Q7 m8 {% s# O
  1. <div id="app">5 }! y, [& ?- ?, k5 y
  2.     <div id="counter-event-example">* d7 t1 [7 x' ~5 K  g
  3.       <p>{{ total }}</p>
    & B: p* Y- }1 \! J& q9 H8 }
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>  f/ ^& @7 C; n3 j" t$ ^6 N* l
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    ) N  d* n0 y2 |- |0 Q2 {
  6.     </div>4 }4 A5 x3 _/ ?# j0 @2 L
  7. </div>
    * F! A# ^! [/ b5 h
  8. 2 b( T9 C% d) C8 I+ _
  9. <script>% A& b) p4 @: J$ @: Z8 A3 j
  10. Vue.component('button-counter', {/ {- c% j& }/ C. d
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    5 \3 y/ u- @: Y$ G9 h( K
  12.   data: function () {; z0 v/ i/ d- }1 D( c# m+ [! O
  13.     return {) l+ n0 z) K. @, w' B, a: u" _+ M; K
  14.       counter: 0
    + Z" l0 `' D# _, h/ ]
  15.     }
    $ B) K; z, K; r. q- N8 q
  16.   },
    : L& {+ j8 v, c9 O4 h. @8 a) w$ n
  17.   methods: {
    , p! T2 N+ g1 K4 B" C
  18.     incrementHandler: function () {
    3 o! F6 f3 k2 b
  19.       this.counter += 1; y% V) z" ]6 L, r. ?
  20.       this.$emit('increment')
    ( Y$ i; g2 J1 y4 \7 A2 v
  21.     }
    - _+ E$ s; q9 w% _8 N# L# z
  22.   },
    + ^9 t; @, S/ w; `% K% @
  23. })# z$ c' X# ^1 H+ T; Z: S. n# l
  24. new Vue({5 E! _6 n$ E1 F, F, P! |& Q
  25.   el: '#counter-event-example',
    5 f0 g; k; J& i* h2 v
  26.   data: {
      ]; \, V8 _2 M- c) V: k" r
  27.     total: 0) q1 }: d( E# s" {. Z6 Y
  28.   },, [4 x& L' c/ Q: s3 D
  29.   methods: {$ I0 j6 H8 K; R+ L" u  C
  30.     incrementTotal: function () {
    7 G% d% S7 D' y
  31.       this.total += 1( S9 U" d  s# `# `
  32.     }2 c& N- O+ U* Y" p0 q" b
  33.   }
    9 r, ^0 h0 y: K
  34. })" {" N* K1 W# {  x$ L* c
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    8 w2 b( c  G3 o# N4 |+ M
  2. Vue.component('child', {1 u+ h! x' `% G7 S! u7 r
  3.   // 声明 props1 D& P- ]8 q: c1 o7 l
  4.   props: ['message'],
    1 P( |, p* G- l& C8 @
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    , y* ]2 s( S: G% ?2 J1 g0 @
  6.   template: '<span>{{ message }}</span>'. H( i9 L6 p/ v6 f2 d: s8 D
  7. })& }0 [+ |0 W: P5 q5 A
  8. // 创建根实例
    6 S6 \; Z" [7 Y
  9. new Vue({
    : {7 O) ?3 Y9 L1 y1 U- w8 y. \
  10.   el: '#app',
    3 U8 c/ S6 ]& G4 b8 S# V( T
  11.   data:{
    2 g( ^8 s7 o  e: j( @
  12.     message:"hello",
    / [; b) B! |3 f5 R  R# o% X0 J
  13.   }
    5 N: _+ ^& g: Y
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {* e# a1 R) h4 U3 c8 b8 C  N
  2.     incrementHandler: function (v) {
    6 {& `  d9 {/ F
  3.         if(v==1){
    4 L! u, D9 A7 N5 _3 f" s0 B
  4.             this.counter -= 1
    5 j1 i' _) C4 a  w
  5.             this.$emit('increment',[1])0 l: _) J( R& }2 T
  6.         }else{& U! Z( X6 x4 S- d
  7.             this.counter += 1# Z+ n; U0 v; ~
  8.             this.$emit('increment',[2])
    . ]" k4 F. l8 i0 ]+ `) \
  9.         }0 o9 Y5 {3 Z) ~% ]* G: i8 a- P5 I5 }3 @
  10.     }& r& Z4 w# z( P) u; w. m% V4 O( D" L
  11. }
复制代码
; p/ [2 k& ?! Y4 c
% A+ \$ g* |. W- Z) T! h
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-19 22:41 , Processed in 0.057360 second(s), 22 queries .

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