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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

. k* E/ H! S" L
  1. <div id="app">
    5 E2 A1 l& B3 G2 }. s6 J
  2.     <runoob></runoob>
    ' \+ S+ v" O$ \. q/ _5 X8 G9 C. D
  3. </div>& v% o% i) L( T7 g6 e
  4. 0 ?. ?0 _7 T" f9 @$ Q/ }
  5. <script>7 R9 s/ N! U9 c9 U- q
  6. // 注册
    ; X6 b; e- d; B3 J$ ~
  7. Vue.component('runoob', {& j% M! [0 |4 f8 f8 b: R6 B
  8.   template: '<h1>自定义组件!</h1>'
    # y7 u! G  m) H3 l
  9. })2 p% ?2 a3 c9 O; g
  10. // 创建根实例
    $ u: X! o; ]& s
  11. new Vue({: l7 S3 {9 Z+ B7 h
  12.   el: '#app'+ m; F6 K4 u  ~" S% T
  13. })
    & G( R$ W6 y9 X: }1 j
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

: u1 `9 ]# U& O1 r6 [  N  y
  1. <div id="app">
    # t( u. z* R, ~8 g4 M; V* N
  2.     <runoob></runoob>
    ) q9 Y  x2 W0 ]7 Y& n" Z+ v
  3. </div>5 {9 b' z) f( v# \

  4. ' J, i5 X" e9 N9 Q
  5. <script>
    4 }5 g* x9 S( i+ Z4 J" M' [
  6. var Child = {! K- G- o: r9 L  x! Q, y1 g9 _" Q
  7.   template: '<h1>自定义组件!</h1>'% W9 V7 r7 M" p$ Y# m
  8. }6 Y" H# I/ j( x

  9. 5 p6 @, u$ W/ N! M% ~& H/ K6 m& I
  10. // 创建根实例
      \9 u: D# Q- x- |  G" x
  11. new Vue({* a7 W* _- h: V8 ^' y% q% i8 o
  12.   el: '#app',3 B7 ]6 Z' E0 y
  13.   components: {' R( C# E; }& W. m+ m. s4 s- h
  14.     // <runoob> 将只在父模板可用
    " l# j9 |' C0 Y. h$ K
  15.     'runoob': Child
    " W% r: e! T) a9 Y
  16.   }
    * k2 d1 I) Q' Q" E* j
  17. })! m9 s! {' U* M9 ^2 H% m4 N
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例) g0 l. N5 J( p3 @2 N2 H" |
  1. <div id="app">9 ~5 d+ b; D8 J; o  W
  2.     <child message="hello!"></child>  m5 n( e1 q, o1 l
  3. </div>
    ) r' I5 N+ A8 J) y7 P" n4 _
  4. / G2 n3 F, z2 F/ @7 N( M
  5. <script>- j! b3 g$ d% R  P
  6. // 注册
    - |$ g: J7 b  I( k# f% a
  7. Vue.component('child', {
    & E  I2 X7 v! |( j+ @5 U+ m2 v
  8.   // 声明 props5 b6 g! O3 R- A% R$ C
  9.   props: ['message'],$ q6 T7 {, u! S
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用) \' f1 Y7 R( V1 E! N: t
  11.   template: '<span>{{ message }}</span>'
      x1 U! \) r) f& n6 `; P. l6 P0 b
  12. })
    8 Q" Z/ h, H$ M  S0 L* ]
  13. // 创建根实例
    3 v/ j1 I0 [  ~# w
  14. new Vue({2 a1 z1 R( y. D
  15.   el: '#app'  L9 V5 O2 M$ U9 ~) Z% p8 m7 h
  16. })9 j" l- r4 ~" k/ l" l7 k" e' O
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
$ d, J; @0 ~2 p8 c8 c
  1. <div id="app">
    6 ^5 Y- A# I% t5 \* ?! k
  2.     <div>
    ' |' ?1 F0 w0 U6 r) T2 P1 J7 L
  3.       <input v-model="parentMsg">% }! f0 F$ c3 [  p1 @. [
  4.       <br>
    9 p3 _1 O& B0 t, x
  5.       <child v-bind:message="parentMsg"></child>
    2 \  T9 a. I/ k; `4 l* f6 V
  6.     </div>5 H! S/ N% k# k$ I# n: x- C+ c  D1 w
  7. </div>$ V! S3 D& ^# s& ?
  8. * b* `' }8 }) K- d, q, s
  9. <script>
    * L' S, }! ^0 m7 T! G8 J. v
  10. // 注册
    # @- T( S- k3 V" d7 s1 }
  11. Vue.component('child', {1 Y; _& _. {5 T
  12.   // 声明 props
    $ ?3 d5 H# R- G. A2 M
  13.   props: ['message'],
      p! g3 k3 n7 L0 Y7 B
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    2 H, J0 E: g0 f0 U6 {$ Y
  15.   template: '<span>{{ message }}</span>'
    " a4 K" Y' C! _: P
  16. })
    ) h# g# A& b7 v
  17. // 创建根实例' z5 d* F9 T" l
  18. new Vue({
    & f( U, Q& E7 B; q
  19.   el: '#app',
    - c1 Q- W$ p$ P& w
  20.   data: {  k& g7 U/ d5 |& {& q, ?
  21.     parentMsg: '父组件内容'
    # t; B) @0 k* f0 x* `6 O7 R; @
  22.   }( v0 m4 A* q: d) l
  23. })
    ( o9 r( E1 h9 B
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
; e6 r; M+ S# U- E9 o
  1. <div id="app">
    5 u  N' M: u5 F8 N
  2.     <ol># Z9 V, a6 R6 A: @+ b5 z) f+ f' d- m0 U
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    1 @) w. z) {- {+ O
  4.       </ol>
    ; o  `5 v8 C; x( K  y
  5. </div>
    7 Q. y! S" I2 y8 e
  6. ) B, o( K. P/ }1 @: v
  7. <script>0 \" X: o8 M$ X5 L
  8. Vue.component('todo-item', {
    % u6 P- e) H# v" K% p: u4 Y% S
  9.   props: ['todo'],
    9 @2 K0 a# j8 Q2 U8 b7 h2 m
  10.   template: '<li>{{ todo.text }}</li>'
    % C9 p7 H( b' q: ~8 r
  11. })% M6 n& ^0 ~- ~0 u" s* p6 [& u* W. [9 @
  12. new Vue({
    & x! J0 o9 h; G" a) N3 Z; r1 @2 Z
  13.   el: '#app',2 |, w5 }" _) }& q7 r. i* x$ R& E
  14.   data: {% C4 I$ m0 M$ x- M: n) ]
  15.     sites: [
    2 h2 N8 O0 F; `% Q+ P; i
  16.       { text: 'Runoob' },! [' i! \- V  r) X- w
  17.       { text: 'Google' },6 J7 g  N( h/ X; b+ [+ d+ }
  18.       { text: 'Taobao' }- \9 w3 m" Z! K8 x# l
  19.     ]
    0 S1 I" W& N0 H* Y- z
  20.   }2 @7 y  E2 m3 J; ?* N: M# U' W4 F' R
  21. })" v& z% a) T7 u4 z  h: ]) a
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {9 f$ X( B% f  W0 X
  2.   props: {
    & @5 J2 o# \: J' p9 h  f" D
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)/ u$ U+ B. p& V& Y  l# a- [9 A
  4.     propA: Number,
    ; k+ q+ p2 j3 p  _3 q
  5.     // 多种类型4 Q5 ]# F7 i7 Y
  6.     propB: [String, Number],
    $ ?$ J+ ~( B& P2 r0 R/ l
  7.     // 必传且是字符串+ l/ m- }+ b  C. v1 R
  8.     propC: {
    9 s6 j& b! H& ~! R, x! u
  9.       type: String,
    1 {2 ]% v" c$ |' W9 T/ P8 H
  10.       required: true
    ( g' F. V' _- d8 [6 q7 I# E& v$ Q: e
  11.     },1 ~* R& k6 E& f- F0 F8 `, ~* {3 v
  12.     // 数字,有默认值
    8 y* U4 g  e2 M% F$ D' p
  13.     propD: {8 |) w- l9 y  _1 S
  14.       type: Number,4 _. A- ]; l# ]( K, l, O0 F) V  ?" j
  15.       default: 1003 P2 H; S! w/ t/ o4 J  T
  16.     },
    4 W. u* I" \2 c
  17.     // 数组/对象的默认值应当由一个工厂函数返回- ?( [" Z8 K; o
  18.     propE: {
    0 `; F* j" O, k8 X' J
  19.       type: Object,* t; Q# s5 L: A' r) W0 d
  20.       default: function () {
    ( O! u% Q0 E" s$ n/ _. h9 p& V
  21.         return { message: 'hello' }5 V1 |+ P0 Z; [6 w9 m
  22.       }
    9 _6 U% [& `( k' j# R7 m& E: u
  23.     },
    , p; b: z4 `0 E) A
  24.     // 自定义验证函数. W" k7 g& q9 j1 {2 W8 V( k
  25.     propF: {4 o' n* J5 F3 J4 W
  26.       validator: function (value) {
    , s6 M9 n! F) m0 T( m# o
  27.         return value > 106 f8 x7 `1 f% d2 o3 d
  28.       }6 J$ S6 d% b4 V4 `1 v
  29.     }; D; V) c" u0 X$ ]) T7 q
  30.   }
      W( P, L1 ^2 Q5 {: m- q: D
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array1 d( ]  e' y. Z! H4 H: Y! [
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    + z2 v) `6 |1 U2 [; N& W
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
0 J2 S9 \. U: L4 o
  1. <div id="app">
    ( \5 G4 u3 e  W3 a
  2.     <div id="counter-event-example">
    2 i4 B) F5 r0 ]( O
  3.       <p>{{ total }}</p>! B! T! z8 x4 |( I% }
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    9 W: m4 M4 H" J! _& W, N9 j
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    ( L4 m4 H0 x( m. {6 e4 s: H- k
  6.     </div>2 i( S( A+ ~' k6 s+ @) B
  7. </div>
    6 u$ y; ~$ [4 k

  8. . I3 J$ E0 m$ E7 K# z3 w
  9. <script>
    ! P+ M+ T5 q' ]/ H/ A# h& \
  10. Vue.component('button-counter', {, \1 Z7 S, I( z! ?
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>'," b% x( K/ {' q5 d9 }
  12.   data: function () {$ k$ z3 y/ `% p) {! m2 r
  13.     return {
    # _" X" y  s$ L4 U3 U+ Q- s
  14.       counter: 05 r6 ]) v6 u  ?9 O
  15.     }
    7 ?# ~' a; |! K! h6 N0 U
  16.   },
    % O* T; f! g6 A4 \5 D& r, X2 q# w
  17.   methods: {" x3 r/ i0 e  ]! Q2 l; M5 b
  18.     incrementHandler: function () {
    , P& g+ G1 j8 X+ u$ V
  19.       this.counter += 1) M/ t% R- J; |- b
  20.       this.$emit('increment')! ~& ]0 U5 [2 j8 m
  21.     }
    ' U, C5 M2 A" i/ u$ X- v
  22.   },
    $ a9 ]) v, A7 o. ~
  23. })
      g- P. B( J5 r, K: [
  24. new Vue({/ `9 w9 [9 t" _* d0 W
  25.   el: '#counter-event-example',
    " N' u4 R. ~# S' [' y9 v. K
  26.   data: {4 w( E; ]2 u0 k7 l6 O% ]: @. c
  27.     total: 0
    ) M, h. a6 ?0 l
  28.   },: f2 x% q! h# G0 l! ^. d' }
  29.   methods: {
    2 ]6 B9 X. p1 Q4 H6 C* ]& ?
  30.     incrementTotal: function () {
    ) d' R/ |6 O9 n6 B9 L" A
  31.       this.total += 1
    ; F& r$ w. y* g/ D: \) k0 Q. K
  32.     }- P, f" f" E, h7 p/ _* N, f( _) F
  33.   }- Y. G6 q4 m& f( \2 q1 V' ~; X
  34. })" @( P5 r; d, D9 u: f, `2 u
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    & |1 h# k+ ]/ {6 K: w: n  Z
  2. Vue.component('child', {: ?; ]; q+ \& ~9 ]+ v) J
  3.   // 声明 props
    # \3 S5 m* Y6 x3 t; D
  4.   props: ['message'],
    $ c9 Y  j" a" ~8 }
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    3 ^$ ]. [8 B9 w0 u, U$ \/ b
  6.   template: '<span>{{ message }}</span>'* P8 |8 q. x5 n9 e4 p1 v2 f
  7. })
    6 @% w4 ]/ z+ ]# G* O
  8. // 创建根实例; X' i) T- K0 y% l2 G  S
  9. new Vue({# I: D1 J0 u. ]3 ^; f3 M4 y3 d
  10.   el: '#app',4 t  Q9 X3 I8 G+ F
  11.   data:{' n; o3 t0 `1 }+ `9 ]
  12.     message:"hello",% l1 E3 H1 a/ l( @; [) l+ v, J
  13.   }# c/ @: [. s5 ^
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    ! s5 Z3 T2 b  s. c$ |2 g
  2.     incrementHandler: function (v) {3 b$ j5 I( P; q; y9 M
  3.         if(v==1){
    , q0 h! s4 H! W, A
  4.             this.counter -= 1
    ' q/ v: J# ?, g6 f0 ?+ T- F6 n
  5.             this.$emit('increment',[1])
    0 i6 Q( _7 ^, B; r/ |- @
  6.         }else{
    3 }6 Q) m( Y' O: W" d1 U: t) l
  7.             this.counter += 1
    ) p% K7 {  x8 X$ @$ n
  8.             this.$emit('increment',[2])
    ) o2 W: H# E+ v  Q% F* z
  9.         }" y+ n3 m$ L0 J6 P  J1 D  }
  10.     }
    ) p6 c* y: p# E1 h" ?  {$ b2 _
  11. }
复制代码
& J' A/ V; U- z
8 }3 o) F6 U: K+ M# G+ e
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-4-30 19:05 , Processed in 0.057562 second(s), 22 queries .

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