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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

5 s+ n5 X( n" u* j, X
  1. <div id="app">/ R' s$ w9 f7 q4 p
  2.     <runoob></runoob>; R0 H0 c5 E% T6 p
  3. </div>+ G  u; V- s' ~0 W% j8 R
  4. 1 O: w: Y$ e  Q. O. t/ }
  5. <script>
    ; D* {0 \& E$ h
  6. // 注册
    5 \- j) P) l1 C, [: z. h7 W2 a5 L
  7. Vue.component('runoob', {  ~1 V, A9 N: m6 G: r
  8.   template: '<h1>自定义组件!</h1>'
    # J* Q" O& z1 R3 C( @% _: h
  9. })
    7 y: V! U& S% s0 m' J
  10. // 创建根实例6 N9 J# y5 j; u  P  P' _
  11. new Vue({
    1 u, Z, f6 ~" X! U
  12.   el: '#app': m9 D* c! J% a5 y* u
  13. })) E' q7 q* y, W9 d( Y
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

. W5 k. P0 ?1 r: ?% W+ ~+ K
  1. <div id="app">
    : d; l/ t7 C" e' j
  2.     <runoob></runoob>5 x7 N& V! \8 P7 k
  3. </div>
    ) H4 Q8 l7 z% D
  4. : f7 z4 p+ k1 u1 j7 L+ G* _/ c2 _6 ]$ I
  5. <script>" u: v; j5 e0 O3 W
  6. var Child = {
    - P5 ]" B" d8 ]3 |$ X6 [8 E
  7.   template: '<h1>自定义组件!</h1>'; \% W( g  i4 V4 @1 @$ T" Y
  8. }1 H; T# D  n/ d9 q3 f  U* ~

  9.   j" k  d! H6 d/ E, |
  10. // 创建根实例6 ?) j2 w; n* ]
  11. new Vue({
    8 {' h. A% B$ ]% \8 G
  12.   el: '#app',
    $ s6 y1 t# T& y9 n% [& s5 ?. \+ w
  13.   components: {5 W' ?0 k3 l7 {. w
  14.     // <runoob> 将只在父模板可用
    8 s) ?* m' f5 k6 p  o9 E
  15.     'runoob': Child
    , x1 C3 P: M: p
  16.   }
    ! O: h" y- L0 _7 f6 f: r
  17. })
    3 `. \: j& ~) Y* k# M! q
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例) P# q& Q% m# j0 Q9 R' J# L
  1. <div id="app">0 N( Z) A5 V$ O9 d& ^/ g
  2.     <child message="hello!"></child>" S5 S* m% h7 J# K
  3. </div>
    ( }" C9 ^% d  G+ Z
  4. ' k3 n+ T1 _% Q! K% Y: K' o
  5. <script>/ v& y/ S& ?4 N& E0 X  L, ]
  6. // 注册$ H" M8 D& q, d% i- N% a; f
  7. Vue.component('child', {2 R. w% R. `; W1 {7 U
  8.   // 声明 props
    8 @7 `3 G" x) |8 Y
  9.   props: ['message'],
    . q* P( X& S5 G  Y2 |* _
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    5 N# m' b1 q* ^9 A; H/ d) A7 h
  11.   template: '<span>{{ message }}</span>'
    % b% u/ t- }: L  G% G  [
  12. })2 Z$ {, n4 \* P" K
  13. // 创建根实例1 L# r* P6 M/ \" z/ Z
  14. new Vue({, D, [& }4 x, p- Y6 M- X0 b+ r
  15.   el: '#app': E/ R' g! Z1 `3 o: p
  16. })
    + i# t! c( [' u: y' v: ~; n# ~( d1 m
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
: @& \' G6 F" G; v8 N  C8 C+ Y
  1. <div id="app">- o; Q( b9 R" P. z
  2.     <div>
    ' F. h7 q  S7 [8 O7 _; ^
  3.       <input v-model="parentMsg">! w1 T8 z4 |1 a0 m8 Q! B
  4.       <br>, Q! r  x2 l0 x6 w* ^' h* P3 |  p
  5.       <child v-bind:message="parentMsg"></child>
    * r  u' o& H* x+ g
  6.     </div>, H( l( ?6 `$ l) }4 E
  7. </div>
    5 n( c: F3 b  U% L1 o

  8. + X2 m6 m0 N/ m
  9. <script>
    ; [) a0 l8 `/ m% k! P, _6 x6 D
  10. // 注册, r6 @4 u& d: z7 w
  11. Vue.component('child', {# @$ H# A) O4 M" u
  12.   // 声明 props: [7 r! l+ c3 U& E- H9 Q
  13.   props: ['message'],
    % \6 x0 \3 s& Q$ D
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用4 v3 c7 \/ ~: Z  F' V6 R7 q
  15.   template: '<span>{{ message }}</span>'# F6 L3 T" \4 E) T
  16. })
    , }& \, L, R' c; C# S$ h2 U8 J. m
  17. // 创建根实例* G8 {+ f* ?. @
  18. new Vue({( {$ @. R8 @8 I9 h( D: z
  19.   el: '#app',8 C& g5 S- B; L1 s9 ?# m2 a9 I$ r% W
  20.   data: {
    1 P9 z7 ?  ?0 c
  21.     parentMsg: '父组件内容'
    # }9 A7 V0 A" D
  22.   }& V: V6 G  b% Q+ c
  23. })
    - ^- _+ z5 C; t0 @+ f4 h, r
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例# ?1 e: _! @) H! @9 t1 X
  1. <div id="app">
    * p( r, n$ h9 }7 e
  2.     <ol>/ k  G/ X/ E4 |# X, z) q
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>* Q5 J& @* ^+ V  L0 B9 }
  4.       </ol>
    ; g- P! `3 @. e( M& A. Y
  5. </div>  e* t1 M, d" a: }2 k+ H
  6. 9 X1 g, \2 G/ ~3 D% i) W
  7. <script>$ P7 p$ F& x1 q; L
  8. Vue.component('todo-item', {
    ' H; I* l1 R4 x1 X
  9.   props: ['todo'],. F; ~! P/ r0 T* H' w: ~! ~
  10.   template: '<li>{{ todo.text }}</li>'
    9 v3 [& ]. }# N
  11. })1 D$ z9 l4 h/ [$ i4 W
  12. new Vue({
    8 ?: [& r- {0 d7 `6 a$ J
  13.   el: '#app',8 A8 m5 n) u# Z( J- A
  14.   data: {; C! A# f1 n) x. X
  15.     sites: [) M7 o% u. @- R$ ^# ?' U$ h
  16.       { text: 'Runoob' },5 ?3 n" h! |$ _( g, `7 B6 [* [. F
  17.       { text: 'Google' },1 Q+ Q. K: C5 Y
  18.       { text: 'Taobao' }
    1 |, L3 n* x+ U
  19.     ]
    ! S, }% S3 r, |8 d- i% e" ?' E
  20.   }
    1 d9 W" c+ Z; B! R* l$ g& K
  21. })" X7 ~7 B* H. \  u" `
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {4 {- v0 ~; W, q* Q( p5 z5 H
  2.   props: {6 @; I- W$ `# a$ W; |# q, z
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)$ @! j6 T& \: ^2 o. h
  4.     propA: Number,# t3 L+ p7 `; y6 w7 n- H
  5.     // 多种类型
    ; U! O; W; q* ~$ ?' l
  6.     propB: [String, Number],4 p5 n+ a. t7 J  |4 q3 S' V$ ?3 P
  7.     // 必传且是字符串+ H1 K5 ~3 ^; W2 d7 F
  8.     propC: {
    ; }# d: s2 F: B1 w8 o
  9.       type: String,
    7 `  A+ i' w3 \6 h) Y
  10.       required: true9 g3 L8 M! v8 v5 Y
  11.     },8 l5 \2 M9 |9 J0 K1 w# h
  12.     // 数字,有默认值; b9 m% V( l! B( M
  13.     propD: {: }" g/ }  X8 e: p! h: r5 p
  14.       type: Number,/ F+ _) k( }% e
  15.       default: 100
    ; @: G' j  R( {* ^# A0 r' w8 A+ V
  16.     },
    & T6 E1 k/ w. E3 ^
  17.     // 数组/对象的默认值应当由一个工厂函数返回4 R. a! N" ?+ g5 P) g$ k5 k  `! q( I
  18.     propE: {( `2 |% R: j1 k8 x0 P
  19.       type: Object,
    1 s+ J, O; f& |$ ~
  20.       default: function () {
    1 R3 ^1 Y; h' X" q
  21.         return { message: 'hello' }
    2 W! n8 f: f" ]: m
  22.       }5 b! T$ r. o+ u) M9 t) {9 ~) u
  23.     },
    0 Y1 r" V9 x7 N! C: e( j* E( y# ~
  24.     // 自定义验证函数
    % A# f5 q& [' }$ t2 v2 \
  25.     propF: {
    ) a+ n; s; V+ C5 g* u
  26.       validator: function (value) {
    & |% G- [+ P% H5 v$ S
  27.         return value > 10# L: e+ F( C5 [, L
  28.       }
    ( V  G6 ]5 P1 M1 P4 [; p
  29.     }
    : M- M/ @8 ^/ a' f; b5 i3 ~
  30.   }
    " y- r! \, \0 A, [2 n! y
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    ; k. l# c! x4 O9 e& G- P
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    * F7 e; u( V: b: h$ ^
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
9 Q  _1 d9 V: j2 R% m' ~+ b
  1. <div id="app">
    * W0 T' B+ j9 S4 {5 |: Z. x. J
  2.     <div id="counter-event-example">3 F* f2 U5 L* U: x, y' Y
  3.       <p>{{ total }}</p>4 Y6 w8 [, a$ w
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>0 A) l4 @6 B( W' e( p
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>0 t5 Q/ A$ f% Q0 s; K9 u6 A
  6.     </div>
    + U! @: Y7 x4 `2 A
  7. </div>- f1 n+ e, x3 R( g- W1 k
  8. ! t1 L4 Q4 _5 D. @; r" q
  9. <script>
    : ?! V1 \% w; A9 w+ n
  10. Vue.component('button-counter', {
    $ P, Q7 Z) w1 M; w4 r
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    9 V" W  \& g% I' r# N# S. ~
  12.   data: function () {
    2 i$ y: R9 k  {/ Q. }" B. _9 G
  13.     return {
    % I% m6 t# e* J
  14.       counter: 0
    + G- z* B+ Q2 q# G* r: D9 H7 ~" K
  15.     }3 L" U9 f& p4 D1 v& @1 R3 t' X
  16.   },/ R3 q2 Z1 _+ l9 K8 h: {& K
  17.   methods: {
    9 v. Y3 h6 A3 o9 d/ K5 `
  18.     incrementHandler: function () {' q1 E/ s; N" }# h! T
  19.       this.counter += 1% R7 F+ b5 k' ?/ t6 V
  20.       this.$emit('increment')4 N  n! e- n' n0 j3 K
  21.     }1 }* b, [+ P- c$ X; n) g1 \8 y: y
  22.   },
    ) z: @; ]* [9 Y) G4 f% `0 j
  23. })3 z* ~: U0 K" s  F1 K0 T
  24. new Vue({
    / A5 O2 t% }9 b: P/ a
  25.   el: '#counter-event-example',
    + t5 [3 @9 K8 {+ [3 I: X
  26.   data: {
    + S! ]1 j6 s" J- G6 `7 c
  27.     total: 00 f, e+ a5 T) ^2 K5 J" D
  28.   },
    ; n) t' n0 P: L  m/ S
  29.   methods: {8 T( u& U+ Q) k' A( y. X5 y
  30.     incrementTotal: function () {
    - R1 C, O- \) r- v, r2 C% g
  31.       this.total += 1
    0 V" n6 t" P8 L. a8 s% Z
  32.     }
    2 Q+ _& L* O3 o0 J% M
  33.   }! [+ G2 _0 I% S7 J' c2 u8 m1 Y: c
  34. })
    4 @# K$ {6 b/ A6 ?1 o
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册$ a' e% H2 b5 B" L
  2. Vue.component('child', {! B* \1 s7 N8 r" H# [5 Y
  3.   // 声明 props2 Y1 Z2 V( m, ]/ K. H* w9 \
  4.   props: ['message'],
    7 v* I* [/ H+ n$ T3 l
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ! p7 }. r" H* D: d% h
  6.   template: '<span>{{ message }}</span>'" {" g* U# X6 K' K% x
  7. })
    ' b4 g" N* O! ]' J2 |( i6 J6 Z
  8. // 创建根实例+ \/ Y( g/ g9 `# S( T% l. |% [
  9. new Vue({
    . o# H: O2 ^2 U; C! g# S
  10.   el: '#app',1 ~. d3 F5 P$ L5 n/ C
  11.   data:{
    0 j$ z. O4 y9 a' p/ c
  12.     message:"hello",
    ! I: p" O. C" s
  13.   }
    6 y& y0 r( {4 ^. p3 U& P6 D, T0 [4 o
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {; s% Q  B9 J" [
  2.     incrementHandler: function (v) {8 n4 D* [, `' I3 y) j! U7 H' c
  3.         if(v==1){
    ' f/ J" H* ^# G
  4.             this.counter -= 1
    ( u! m+ u# I8 n+ q3 F
  5.             this.$emit('increment',[1])
    0 q6 x8 a& w$ p7 y% W4 M' Y/ D+ b9 A4 a
  6.         }else{
    ) ^6 M) }6 l) K8 S. `6 V+ X7 d
  7.             this.counter += 18 g6 `' o6 j9 v6 `
  8.             this.$emit('increment',[2])
    * L8 k1 ^6 X! E. J( A, I  a
  9.         }2 j& z2 U( x, y- h
  10.     }
    $ V8 w" [$ |/ ]6 x
  11. }
复制代码

$ b$ v/ G9 h4 g8 [8 U
: G6 V4 E, Y7 z" A1 {/ t, X
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-20 02:59 , Processed in 0.072418 second(s), 23 queries .

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