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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

3 q/ F7 W+ D* L3 t
  1. <div id="app">% |; j4 q6 f: X, c$ o! z
  2.     <runoob></runoob>. y* Q8 {3 v2 w* V+ D
  3. </div>
    # s; n  u+ C% [  R: I) g/ h! @

  4. % ]( ~7 e& J# V2 n+ T
  5. <script>) l; Y/ Y! G/ |7 h
  6. // 注册3 H) K9 f5 C+ C, S' m9 i0 ~
  7. Vue.component('runoob', {4 `, {2 M/ o! F/ O# U8 ?
  8.   template: '<h1>自定义组件!</h1>'
    0 g& y  m; F0 [) j. Y8 H- v
  9. })
    ) S$ c: V5 N1 \
  10. // 创建根实例
    ( J! G  B) o+ P) O: D$ C
  11. new Vue({
    6 A* n" O* V7 @+ Z
  12.   el: '#app'
    9 \) u. n9 g  @
  13. })
    5 O9 o6 g; Q1 k, W% u* m& Q( @
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

! R2 O- Q2 o. y
  1. <div id="app">
    % S) h: S# v2 C
  2.     <runoob></runoob>
    9 X# S, F$ |+ L; w- Q
  3. </div>5 {7 v' T* e) V- b8 N" [$ T0 h

  4. , s2 L4 X6 p7 _. B- ?
  5. <script>/ I: |3 `6 z' U4 V" v5 S" b
  6. var Child = {& P' r0 a, b4 U3 u! I) b+ S1 u4 t- f
  7.   template: '<h1>自定义组件!</h1>'. V. v- u: q2 [7 D. b
  8. }: r. K( U- l& N
  9. - U- V& l1 J% c+ ]" R- K/ l. Y( K
  10. // 创建根实例
    ' r5 g: V4 N: R, w" G$ [7 P
  11. new Vue({9 `" b6 n3 L: n! x( s# L
  12.   el: '#app',8 k4 e& T8 ~5 B# S- q
  13.   components: {
    $ @/ b+ }7 k9 l  p& V
  14.     // <runoob> 将只在父模板可用
    . G' w/ _4 ~$ a
  15.     'runoob': Child- t# E$ _  ?8 L- O
  16.   }
    ( c6 Q% F, T" i! G0 s
  17. })5 K9 y* k6 y, p7 S# E/ n
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例& p+ U9 n; ~4 D: B& [, T7 z( r  l
  1. <div id="app">
    - Q- G1 o2 h1 \) \& S6 Q  G3 P
  2.     <child message="hello!"></child>- v3 L) \& T3 P4 q$ [
  3. </div>
    , C& q2 A- V! [3 a, U+ K

  4. 0 n1 m9 Q  O" T. V$ A  h0 _
  5. <script>
    - K0 t% t9 g* S
  6. // 注册& ]* Z3 d+ a7 W! c7 Q
  7. Vue.component('child', {
    : S4 ]- f0 q( u# P1 I
  8.   // 声明 props
    3 D. k' \% z' p
  9.   props: ['message']," A( Q7 \) V, H& n
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用: Y0 x6 B) S6 t$ W
  11.   template: '<span>{{ message }}</span>'2 G4 P1 {9 ^4 Z
  12. })4 t: q7 l4 a5 ~1 R
  13. // 创建根实例
    8 _  Y" L& N. A  y
  14. new Vue({; }7 e0 n) B5 n* X  u. `1 U
  15.   el: '#app'
      i6 [# t: _4 x
  16. })
    5 j! q6 n, N5 {- }) L+ x! p' w  w
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例9 Q1 v. k( J* L" I
  1. <div id="app">
    / j8 O9 t8 k+ |( c2 }
  2.     <div>
    6 S5 u0 D8 Y* R# v- M: w
  3.       <input v-model="parentMsg">
    7 `$ Y0 ]+ B4 z; N/ i2 n( s5 R3 ]
  4.       <br>2 h0 x* o: g$ X' }4 n
  5.       <child v-bind:message="parentMsg"></child>2 X7 h) u- g/ d1 P1 B( k; [( ^
  6.     </div>3 l/ Y% j, v( N0 a! r; F6 E; w' T
  7. </div>+ x/ L1 @+ y/ ]8 h, i- `' B; T

  8. + m" L7 [# H; q/ F) k6 K9 j
  9. <script>* y  ?. Q/ O2 ^, b, {0 H0 q" b
  10. // 注册
    8 Q, |1 {8 s8 m+ |; F
  11. Vue.component('child', {* Z. O" G! E- [, p8 G
  12.   // 声明 props8 b& A  ?: j- M- Z, e( L/ j) E
  13.   props: ['message'],; e# W' G* o& a, e! _! V# ^3 _
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用5 Z# J& @+ X' U  P8 O  Z1 t: F  [
  15.   template: '<span>{{ message }}</span>'
    4 [  K5 Y$ T3 p% L/ C" |
  16. }); R( b, ~9 b5 C; N  m8 Q& b- Q
  17. // 创建根实例
    ) X. D# L9 K% Z( A: e! g4 n
  18. new Vue({
    % F" Z7 c% g% f$ @
  19.   el: '#app',
    ! J4 \/ r( t1 S1 I" x5 S4 W
  20.   data: {
    & g' m4 a1 F$ H) _# Y  j+ }% S
  21.     parentMsg: '父组件内容'+ F, ]. T1 a" G% a6 y
  22.   }
    ' [( z; k, Y4 f- a$ I# }" W! i( v
  23. })- x  l, ?8 U$ m' f, K
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例# \" u% E6 a, g4 m) w8 v
  1. <div id="app">1 D5 e8 p1 o( K  Z* j  r, d
  2.     <ol>
    8 {. {/ U" Z7 K) B$ ?0 j
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    - u7 p) h) t8 Y. r( M4 J( r
  4.       </ol>
    / u% R+ d6 C( }- ~
  5. </div>
    - r) d+ e  w+ W8 s, Q. z

  6. ; |8 M! m. M, J% ?0 X) O
  7. <script>* e5 X. m* G  n1 o3 e
  8. Vue.component('todo-item', {, h+ F) w) h: x5 [7 z* u4 r6 O3 Y
  9.   props: ['todo'],
    - N1 Y5 j2 K' ]  J# F% \1 n
  10.   template: '<li>{{ todo.text }}</li>'
    9 c+ W1 {/ z! o2 T7 T& T
  11. })
    / Z7 b* P! j1 j5 \
  12. new Vue({
    4 ~4 z2 J$ T; s1 e
  13.   el: '#app',
    , ~/ a9 I. d: O& X" E
  14.   data: {
    6 s5 ^5 R* t# Y1 @/ {. y
  15.     sites: [
    , v; ]% `. w. _
  16.       { text: 'Runoob' },, k$ v2 t' @5 [& D
  17.       { text: 'Google' },+ W4 `( k/ A- K0 Z3 x8 }! t1 Y2 F
  18.       { text: 'Taobao' }
    * ^2 G6 I1 Q: K4 t
  19.     ]) R8 i5 l  g  l+ y
  20.   }
    3 V6 c& R9 c5 i5 b0 p) H/ r# }
  21. })
    & {5 U# Q, ~% U
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {9 c. `3 R2 f, ]/ Y; X7 J
  2.   props: {
    " I- Q/ a# \; a0 x
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)  m  q, t. C9 I. S; k
  4.     propA: Number,
    8 L* Y& V! y! W1 L
  5.     // 多种类型
      l2 y. C* h& v1 Z8 s$ c
  6.     propB: [String, Number],
    9 N; {  d! c6 `8 N' S+ G6 ~5 y7 M
  7.     // 必传且是字符串
    4 F- q/ Q% Q" Q
  8.     propC: {
    3 ^' U) y6 C; |" a8 N2 U2 E  z3 y
  9.       type: String,
    8 u# G2 y, g0 R
  10.       required: true- D8 m# N3 q3 y' M
  11.     },% b" Q9 |9 m' E
  12.     // 数字,有默认值
    - r; Q# F) t$ o4 `
  13.     propD: {) ?* Z$ Y) i8 v9 Z
  14.       type: Number,# r1 G% W' d' I3 I
  15.       default: 100
    ( Z6 S: }6 a4 _6 P
  16.     },
    4 \0 {) Z( [0 a1 [: V0 A; ^
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    1 }) R* Z+ b6 j# n
  18.     propE: {0 X9 f" @1 U0 ~( z; u8 B
  19.       type: Object,3 a) G$ P, i3 I6 {$ b* K, ]1 k5 z
  20.       default: function () {
    $ [& w1 ?* X( v8 H. ?3 L
  21.         return { message: 'hello' }
    2 x8 p7 A+ v' ?
  22.       }
    ; }9 N) e0 {# X$ q3 g
  23.     },
    9 s% V/ |2 d( [3 ]0 @
  24.     // 自定义验证函数* l. T6 }7 G) }2 ~1 n2 n
  25.     propF: {0 F/ A; F* f0 _/ `
  26.       validator: function (value) {
    : a  r8 O) {& N/ z8 ]' R
  27.         return value > 10
    1 w* M) z! x, j" d* j; q
  28.       }
    + K; Q9 w. @* P- [* b! I
  29.     }
    % i$ a( L$ c, R4 K& |7 G5 Z& m" {
  30.   }, z  \# q, Q5 d5 J
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    - n: y% J3 U& I, Z# U9 }
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
      o1 o" o. G7 v# _3 H) }1 `
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例% K2 c  w6 T# V# \( t
  1. <div id="app"># D& Q7 Y. ]- E5 K7 ~4 E' K- @
  2.     <div id="counter-event-example">9 b) T6 E# Z* o
  3.       <p>{{ total }}</p>
    & j2 }  u3 [  j0 |- O* m
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>2 O( A  ]1 O  Z; O4 R5 i( G
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>2 ^( l1 E% L5 i
  6.     </div>
    4 t; d; y( ]! z/ u' X
  7. </div>& Z) ?* B1 }; G3 m: v9 d2 z: V

  8. * ]5 p) {. z6 F. C+ Y: R
  9. <script>
    . s9 Y, a2 |2 z% X4 D3 }
  10. Vue.component('button-counter', {% r7 j9 E' B& o4 L
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',0 I) O: s; Y/ S1 q, o; |
  12.   data: function () {
    ( ?0 d- l2 M% o$ f8 r1 W4 d
  13.     return {
    ( Y% b) `8 l( j* s# U' H7 n5 @& T
  14.       counter: 01 z. H9 N- d+ ?" V% f. }1 |3 h
  15.     }
    9 L! a8 I5 U" \* P# ]
  16.   },
    & b. \* ?+ Q- r
  17.   methods: {, A1 r/ Z" D) C8 a8 n5 U
  18.     incrementHandler: function () {
    6 j% ^4 Q$ u3 k# i* i7 s
  19.       this.counter += 1
    2 |! x' O6 a# G1 z+ X4 C
  20.       this.$emit('increment')
    5 R1 O1 g' l# B2 s( u6 C
  21.     }
    - L# e( t- x, p# L! O
  22.   },/ A, p4 z% c* Z
  23. })
    ! `: ~. G3 W9 x# m4 _, t. o: p
  24. new Vue({
    2 M' |% F& t% j+ S
  25.   el: '#counter-event-example',0 b  p8 {& M, [" W
  26.   data: {
    $ B( M- T# v8 U1 b; {4 n
  27.     total: 0
    ) _/ y; t1 o3 k# \
  28.   },
    $ I& Q( i8 s- m0 l- b' R/ t: _+ V
  29.   methods: {
    , c+ e0 q. D# H3 Z. |! D% d
  30.     incrementTotal: function () {) b, `4 F" p- I1 T0 D( s
  31.       this.total += 1! ]& |0 S8 U, h7 z, j% ?: U# b: ]
  32.     }$ z1 A3 b/ r- b# U% F$ X
  33.   }4 ?: E0 s( n- l" [: w6 p; B
  34. })  ]) x, G7 \4 E& g6 q
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    ) F' r0 r% t' o
  2. Vue.component('child', {& f+ H5 w2 h4 ]
  3.   // 声明 props4 v+ J: E% ~: F" G6 ^) D
  4.   props: ['message'],
    * k! V: W0 a2 x5 K* k3 f# h
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用% B: m9 J, m- ?, @7 t
  6.   template: '<span>{{ message }}</span>'
    ! B- S+ `+ j( W
  7. })7 Y, U+ R- e% u+ ^4 R
  8. // 创建根实例& R% B) e  W% M$ t3 E/ ^+ Q; w
  9. new Vue({; Q: u) p9 F) K
  10.   el: '#app',
    + Q. w' u+ a6 E
  11.   data:{: v+ ]% s3 D2 B4 `5 G) `' R- i
  12.     message:"hello",( ~( x4 f/ k1 G7 i
  13.   }
    % C" L7 j4 i4 K' T) z& u3 q9 h% D' t
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    ! j6 z1 G' l8 e. T$ ~2 j
  2.     incrementHandler: function (v) {
    + Y6 C* U7 I, J
  3.         if(v==1){
    4 |- s, T' y0 [, t8 f5 Y7 C( \
  4.             this.counter -= 1
    5 q$ F( I/ ~1 E; \# W/ B2 C6 l
  5.             this.$emit('increment',[1])2 x$ K! Z* ?; ^; `# `& j
  6.         }else{; u( p" G4 i6 O# Y
  7.             this.counter += 1
    ) Z" g" F6 O1 N% c
  8.             this.$emit('increment',[2])
    - y9 i5 F) b  V  k# S! F
  9.         }+ M& Q+ {1 b; X/ a( |3 k0 t
  10.     }+ }$ m4 w( t) U' O8 k( M! K  P3 n
  11. }
复制代码

2 ?. X$ Z! @4 B# F% [5 B* Z
9 n8 }. F- R1 _8 D
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-18 19:49 , Processed in 0.162747 second(s), 23 queries .

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