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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

/ {0 k# o% t6 z! @+ [: D% p( Y; R
  1. <div id="app">
    1 x* c% r9 |- h
  2.     <runoob></runoob>1 K3 y3 L2 Y* _
  3. </div>
    7 f6 H3 f. v, k, H5 s

  4. + G" [' w% I7 @6 d7 l5 t
  5. <script>) c+ w* m5 b. y
  6. // 注册% C- ]/ {4 K, a9 W" I
  7. Vue.component('runoob', {
    0 `4 e  Y- K% m
  8.   template: '<h1>自定义组件!</h1>'
      C' J8 r5 Z6 y! @/ h
  9. })0 _0 w' W7 _5 B5 l( d
  10. // 创建根实例$ c9 a5 \% L. V' u/ L, v1 M
  11. new Vue({8 z* v9 }3 z9 A: ]' m7 n/ L
  12.   el: '#app'
    & x: {  S5 R' c" ^
  13. })% L0 F2 D# C. @" p& {9 O6 F* O
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

* O% ?( O0 z* t4 B3 n) \/ ?% ~. ~
  1. <div id="app">
    % J! G7 i4 z, A/ f# g% g/ I$ l
  2.     <runoob></runoob>
    + `3 @0 z. Q! p5 }
  3. </div>+ |" b5 |9 i" T2 I( B, O

  4. ' B) B, S' k; C* v% M+ T7 Q* l5 Z( ?
  5. <script>' F8 Q4 g9 `. z# [
  6. var Child = {5 W- U( M, R$ q" X/ l& k/ g
  7.   template: '<h1>自定义组件!</h1>'
    " I# p- u+ \+ K8 W1 {$ z" k/ J# E
  8. }5 v& j3 R$ F, y& ~0 d) d
  9. ) o: O) _" C9 l1 Z1 W
  10. // 创建根实例2 i6 }  o9 H0 d+ I
  11. new Vue({
    8 ^: v  x) V- a' Z% }
  12.   el: '#app',
    . ?) H( `5 E5 q( Y
  13.   components: {
    $ d& p' C% ?2 G" S4 ]1 |$ I
  14.     // <runoob> 将只在父模板可用/ z0 A) K8 z2 ?
  15.     'runoob': Child
      Z1 s& x, V) y0 C
  16.   }
    0 v% _- I% l$ m- E8 o
  17. })6 n, _1 c: H" L5 `2 c
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
2 O% C' N+ w- J! `
  1. <div id="app">
    7 D. o/ @4 W6 @0 b  s
  2.     <child message="hello!"></child>
    7 O2 m2 O. t* c/ }
  3. </div>" x- Y! h" o, n! [+ T

  4. 3 E3 h3 d1 T$ u& ^5 h: f9 B
  5. <script>% i' D$ x  `9 @; ^
  6. // 注册
      S- d0 p& O0 R! ^
  7. Vue.component('child', {# }) b  ~5 V# _0 `2 t. s
  8.   // 声明 props6 a! h% ~; E5 N9 o4 v1 _0 a3 y) y% q
  9.   props: ['message'],0 `( i" Y* s& F& z
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    2 q- V  F' p" ^" \1 H0 D3 Q
  11.   template: '<span>{{ message }}</span>'6 [6 r0 @$ U# f0 g
  12. }), I; ^+ n0 F( v, M1 l
  13. // 创建根实例
    : ~( ~( h. E/ O
  14. new Vue({
    8 f' w; h; m# p9 E; x, C( z
  15.   el: '#app'# K9 |+ m" l4 Z" s& F
  16. })+ A+ u  W$ K. s& ]7 x4 m
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
6 e/ E: ]$ {+ o" K' f% z
  1. <div id="app">
    8 n; l! i1 V6 j# @" i! w( Q
  2.     <div>3 x" P' b% x% H6 p
  3.       <input v-model="parentMsg">! A  ]6 l9 [. y
  4.       <br>/ }- Y3 I2 S4 H7 _: Y9 h, k* Y
  5.       <child v-bind:message="parentMsg"></child>: Q8 X' Q$ e3 k/ h# s6 ^
  6.     </div>
      |% r; o/ Z) V3 O" W
  7. </div>
    : U& |5 l7 D4 c, T  N8 ?- w
  8. / o5 g4 V6 Z0 _
  9. <script>8 f4 P! N& _! {
  10. // 注册% A$ Z( w8 Q- ?* C: m  l" N
  11. Vue.component('child', {( a$ x6 b7 O; X( @  E# u, u
  12.   // 声明 props
    9 s: V* c# g2 M. j
  13.   props: ['message'],
    2 T# B" ~' J/ d& A4 t6 |+ W
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用0 B7 f3 n+ x7 y, E& J) {4 ]: S- ]
  15.   template: '<span>{{ message }}</span>'
    # `  \) A  i7 n9 u, z2 O! k/ X& q
  16. })8 F- d# p  h" f4 ^8 X
  17. // 创建根实例) B. p& l9 n' T) m  P+ w: `5 o  V
  18. new Vue({
    9 r( E6 }6 C7 \
  19.   el: '#app',
    6 U! d6 E* S3 p$ r1 U8 P
  20.   data: {4 x+ R8 F( H. }1 w* p  P
  21.     parentMsg: '父组件内容'
    . {# b8 r0 ~* l5 E4 K% ]7 Q1 X
  22.   }
    5 G5 E& x! y7 g, |
  23. })
    + T% t( y) [' q: \1 W2 y7 N
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例% m$ ?3 H1 W. z
  1. <div id="app">( I. a& q+ i# h. H2 f, k+ u2 P
  2.     <ol>( M) h  Z, L  r. X" D8 k0 J- N' b
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    " e# g6 ^% w0 D, _: ?
  4.       </ol>& m" [0 Z8 W) d. {5 r
  5. </div>
    # O# Q. D5 A2 L: \& Y: ]

  6. 5 P: ]5 O; v  t8 K2 f1 F
  7. <script>% v" j7 Q' u9 Y7 k9 B
  8. Vue.component('todo-item', {* K9 V8 j% L. W
  9.   props: ['todo'],
    - e! U* b/ p. x% w% S* W6 {  q
  10.   template: '<li>{{ todo.text }}</li>'7 }/ z  g1 E6 y- p1 @- Y
  11. })
    9 ~7 o/ K9 X6 _1 L4 }, m
  12. new Vue({. Q3 G, E& n! F' L
  13.   el: '#app',
    2 E9 [8 Y  Q! q9 f% H: Q
  14.   data: {
    , k/ U7 o" k$ v* {: E- x
  15.     sites: [
      E1 D, {" s: s* c' M  o" x; N( t% S6 i
  16.       { text: 'Runoob' },
    $ T" t. `3 }8 B3 p+ t( x
  17.       { text: 'Google' },
    3 @& F  h5 O" {# b: r
  18.       { text: 'Taobao' }
    $ X9 [" W. _% ~% b
  19.     ]0 s' O6 p2 }$ l; [& `; j4 \% J) U
  20.   }
    1 R0 b4 M* t: e8 ?( V, b; q) I
  21. })
    : B& G* N: \$ N
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {2 z% v( i2 p3 Z- L. ^1 C
  2.   props: {
    : T  Y' \, }2 C9 i) H
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    1 v; ^9 ?  W9 c
  4.     propA: Number,
    3 s* o( _$ S  k' l/ y" k# l& X, x
  5.     // 多种类型& n& c9 I) n/ E- p2 \
  6.     propB: [String, Number],
    6 |; X6 U) j' t& y, `
  7.     // 必传且是字符串& f) T9 t, h, k: L/ c
  8.     propC: {+ l% A) d- W- I5 \4 z7 l1 ?8 i0 P; I, |
  9.       type: String,
    : \* L9 M8 Q7 \
  10.       required: true' N4 y3 I* ~: K: \2 a
  11.     },
    0 Z3 p6 `7 a. K5 O" H% a4 A/ s
  12.     // 数字,有默认值
    , c" r* b' s/ a" M
  13.     propD: {
    4 g% O' S3 v  [* k: K
  14.       type: Number,
    . E( }5 c* D& `
  15.       default: 100
      L; G9 [6 ]( n& ^1 o- k2 I4 s7 r
  16.     },
    , c9 `# W/ I! ^5 j7 I7 [+ y
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    ' h$ j# D4 {" [% s* O( q
  18.     propE: {
    1 y/ r: H& J* \: u
  19.       type: Object,
    . L& m- ~# i: H/ T3 _5 o
  20.       default: function () {+ G" |3 r% v# }4 `/ y, ~
  21.         return { message: 'hello' }
    $ s  D& ]5 Y% H7 j  ~
  22.       }; N) |  k$ X7 S# k4 n; P+ i
  23.     },4 |6 @7 a2 N4 A  D$ o- R* X/ `
  24.     // 自定义验证函数
    ) r( Z0 I" U3 m5 J  v: D- {
  25.     propF: {
    : U" z6 K2 i/ ]9 f/ _1 _
  26.       validator: function (value) {2 R! A  \6 y' G1 l8 t- |( T. V% J- W
  27.         return value > 10; q7 J% X3 L  l+ q+ f# W
  28.       }
    0 N& @1 C" _& n# m, o' U
  29.     }( h6 g4 U  C' h. i% J  H; ^, ^
  30.   }
    $ L% M5 q4 Y$ M2 Z
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array* X3 B8 u4 X/ W0 Z7 a
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    2 m  K7 H' ], o$ g
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
8 H# i& _; k- x% b( s
  1. <div id="app">
    - r/ p, Y, s% d/ C- h# a8 f/ z
  2.     <div id="counter-event-example">7 w' h& J* G5 J
  3.       <p>{{ total }}</p>
    : V# X. g: S& t+ a
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    ) h7 A: d' V/ \. \5 n
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>3 w+ A! L9 L! y
  6.     </div>
    , j. B5 N& e* c6 n
  7. </div>, T7 h1 m& h% N5 @+ ]( X) b

  8. 1 O3 n4 M1 H: f
  9. <script>
    $ _; ]& m3 v+ j6 f, s1 t8 g
  10. Vue.component('button-counter', {
    8 z/ H+ R5 e; u% _9 }9 Z9 o, J
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    9 f) |" X# ~" g4 B  d. {
  12.   data: function () {
    - ~7 F' o) W2 O% D- V0 q6 u
  13.     return {
    9 _! J/ Q+ z5 ~0 m
  14.       counter: 0
    . }9 I3 x) t# @" t) _
  15.     }1 A2 S' j( Y& B0 Y, @
  16.   },
    2 \1 f) \9 o% T1 x. @, h! l
  17.   methods: {2 `3 H  E8 @& n: O7 G. t
  18.     incrementHandler: function () {
    8 ?) F! ~  D: }2 H, n: y
  19.       this.counter += 1
    # M9 R4 ]7 E; v3 a! J) [$ {
  20.       this.$emit('increment')
    % e4 K/ g; P% X6 R& v9 u( k
  21.     }8 a5 {  d% |- n8 i
  22.   },
    , `. {' q7 i- T1 g
  23. })
    9 Z$ E8 n/ f) }0 B
  24. new Vue({* S; [+ M6 G, W# C7 o, \
  25.   el: '#counter-event-example',
    , D" [0 d6 I6 N* \9 G! y! b0 C
  26.   data: {" ~+ E! Z5 u9 q, o+ ~3 }* B
  27.     total: 0
    - Y2 }2 w% T8 k* q( f5 f# {8 J, @
  28.   },
    . n1 ?: X/ F3 G
  29.   methods: {
    ; Y% N" c/ {; b; a7 `9 Z6 U+ {
  30.     incrementTotal: function () {
    ' J" p% v! `$ z3 d
  31.       this.total += 13 K& {% y* u  }0 K! {
  32.     }
    # Q2 y" m8 \$ E  ]
  33.   }
    # P+ d3 h/ f: ~  X
  34. })7 A% P0 O" A% C
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    ; O# K4 F: _7 c. k5 n# x. H
  2. Vue.component('child', {7 Z( }" d: x; G
  3.   // 声明 props
    : G7 G; V1 @- |( |( v
  4.   props: ['message'],  [7 _+ h" |7 i1 E& m- p2 c
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用7 o" T& G9 R# Y; l( C
  6.   template: '<span>{{ message }}</span>'
    5 b1 r$ t, j. P" y) P3 ]
  7. })
    5 S2 D& k, S. @. E2 v, H- a: j! U( Z7 g
  8. // 创建根实例
    ; V) s: }' a* n& l6 N1 {# s$ Z# q
  9. new Vue({9 H& d* V+ d1 I% e
  10.   el: '#app',
    ) e/ z4 U# t4 R7 W  R! W! c
  11.   data:{# e8 k3 x& l/ ?; J4 T- ?8 C6 }
  12.     message:"hello",
    % i) Y* i6 c/ g
  13.   }
    & L3 i' d9 N) s% F! G4 E
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    : F* U4 a8 [5 Q8 X5 `1 @, x' D5 e
  2.     incrementHandler: function (v) {
    . Y. e* @) r' Z
  3.         if(v==1){$ C1 S3 V4 m; S- L4 C& i9 w
  4.             this.counter -= 13 Y0 C% O2 D% ?9 t
  5.             this.$emit('increment',[1])
    , B  `! O1 @0 a" l9 M+ V: A+ h
  6.         }else{' K+ ^5 Y' F3 I4 G
  7.             this.counter += 1# s. u% q+ ]' l! F% `6 F5 ]: L9 w/ R+ t
  8.             this.$emit('increment',[2])2 z* N9 j/ ]1 Q
  9.         }$ F0 N& D0 T# |) H( \- ^/ D2 U9 D2 N
  10.     }
    8 E: F! L; \( r, K9 Q
  11. }
复制代码
6 ~  _+ ^5 _4 ?8 n( C

/ p; N7 o) _4 K! c; I* |8 i
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-18 18:15 , Processed in 0.134531 second(s), 22 queries .

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