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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

- u; g0 c( z" h  I3 E/ \8 V
  1. <div id="app">* h) Q! M+ \' t7 a3 E# l. V, n* y* q/ o
  2.     <runoob></runoob>
    ) ?# M& A5 |, G' N+ Y/ `" b) [
  3. </div>
    % Y+ ~% w0 ]; _

  4. , w. G9 f3 v7 ~% W; D
  5. <script>0 T7 D6 a8 H4 r9 F- f
  6. // 注册
    ; l3 X" Y- l- v+ n( i" \8 m, j6 a
  7. Vue.component('runoob', {
    5 Y& k" Q  K3 ?+ p
  8.   template: '<h1>自定义组件!</h1>'5 R7 q( l, Q+ K2 U; J7 X
  9. })5 L7 f  m- N8 F/ x# C0 r% d% M
  10. // 创建根实例5 S& }# k+ }0 d% \) Y6 @
  11. new Vue({4 R+ I2 h  J9 K/ U/ E
  12.   el: '#app'
    % E6 n  C2 C7 d/ W
  13. }): ~- s8 k  L4 D& r/ D3 Y
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
+ T! O; D: U2 _7 t$ U( F  o
  1. <div id="app">/ O* f4 B6 @" J, J& i
  2.     <runoob></runoob>
    9 t( R, z9 n! V6 z8 r+ r4 K
  3. </div>
    & H/ v/ Q" h! X$ B1 P

  4. ! |$ W9 m/ r0 a. ^6 A: a! n
  5. <script>) A7 p7 {6 X# t
  6. var Child = {
    2 t4 r  K! V: \+ S
  7.   template: '<h1>自定义组件!</h1>'& W7 a) r, F3 ~
  8. }! L  Z; O9 o4 \' D
  9. 5 _1 A/ k' I, K% [% r
  10. // 创建根实例
    % ~2 _( t3 j. O  N/ v; e4 }
  11. new Vue({
    8 l6 k. Y8 o3 W1 p+ O
  12.   el: '#app',- }6 S0 S7 ]( c) d
  13.   components: {- \& T. i8 c; R6 V; v7 c
  14.     // <runoob> 将只在父模板可用
    & H7 k6 R, b. b' A% _0 `1 f
  15.     'runoob': Child
    # n- P6 M% N" k
  16.   }9 C: C$ Z8 z) q  z* \+ j
  17. })
    . H7 }( {# P" p3 p4 a6 b8 J
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例! r9 i. U% V( R1 N" ?
  1. <div id="app">
    ( u% X2 W# ^1 w# {- D) |8 {" R9 \
  2.     <child message="hello!"></child>- _. F4 a0 b3 c4 ^7 O6 T" f
  3. </div>. s, R/ Y% h; m# H
  4. 9 |" Y/ [+ Q- [: `' q1 l
  5. <script>
    ; @9 ~# P% ~- f( r, ]
  6. // 注册0 h6 z# Q  ?6 `% H; d9 W
  7. Vue.component('child', {
    % n* a; T% Y/ `! V% `$ Y
  8.   // 声明 props
    . U+ z- \6 ^1 y7 o
  9.   props: ['message'],9 _7 b: s$ w- E/ K1 N# K" S% C
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用' V+ `) E+ h2 L* U$ G& R$ R) T7 q
  11.   template: '<span>{{ message }}</span>': \# _. u5 I; [% G
  12. })8 k3 H1 Z2 |  t3 g5 ?0 s  G
  13. // 创建根实例' e" g3 f) x3 }  d* [+ F" G
  14. new Vue({2 I* |9 O: a$ O6 ^
  15.   el: '#app'
    0 O2 Q2 ]3 ~: q' k
  16. })
    ' h! P2 B8 H# h9 `# B
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
6 q) O2 B# r# Y2 o1 G, a. E* E1 [
  1. <div id="app">
    7 C- E' `9 k7 I& ?7 q- F/ Y$ h
  2.     <div>3 z  |) y8 S- J3 H$ T
  3.       <input v-model="parentMsg">
    . L; I" }$ ^0 g- b
  4.       <br>
    6 g8 w2 X& D  G5 g6 `
  5.       <child v-bind:message="parentMsg"></child># R  u) k9 K; C8 F1 l
  6.     </div>
      e/ F8 l7 `. [4 u
  7. </div>/ g- K6 s# B" R& z; N7 u' x* L
  8. - M- k( P4 h; g2 ]# e4 _
  9. <script>
    * g& D; l0 Z9 e9 o  }* j
  10. // 注册
    ' |* ?( D$ n& a3 R/ b) a' W1 C# D0 ]# {
  11. Vue.component('child', {
      \; Z. b4 \* y/ d; {
  12.   // 声明 props4 Z4 @- ~* |3 b8 O& G
  13.   props: ['message'],
    / B) y6 X+ a( y7 x( c6 K
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    , y' q% Q6 G; Y2 X( |
  15.   template: '<span>{{ message }}</span>'
    & m, X; h- F/ i0 }
  16. })
    , d+ w0 n- p# d0 }
  17. // 创建根实例3 X% [; S& I; E+ |) t. j; o
  18. new Vue({* Y  \3 U/ R& u0 E4 c" e
  19.   el: '#app',) Z- T4 x' }: o8 p' w8 h
  20.   data: {
    - Z. x+ a1 \. _+ `* [1 h
  21.     parentMsg: '父组件内容'  _1 }, V- F9 e5 N) y( v
  22.   }
    ; E* R+ \/ t( B# {
  23. })9 [2 j. H- i, P# {; v
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
) e# D$ n# a* X2 ?* Z# \* [0 k, j
  1. <div id="app">9 B* e/ n4 Z  q/ a: c, N
  2.     <ol>. j/ R; g% F4 n5 a/ g  c/ s" d7 P
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>6 N6 y4 X$ F; T; N1 Y- o  @" ^
  4.       </ol>
    1 A5 ]: s# M. K
  5. </div>
    $ X: S0 _, ?3 R5 q- z  a# E
  6. , B2 a! o0 R, w9 M4 u* H2 s
  7. <script>
    / N1 N: A. h5 z7 t' x0 u( m
  8. Vue.component('todo-item', {) e4 E/ n7 b* o$ J) I
  9.   props: ['todo'],
    4 y2 W3 t! F/ k( g$ O0 F+ z
  10.   template: '<li>{{ todo.text }}</li>'
    & B. L* Y# j6 h% r5 v$ x6 I9 h
  11. })
    * b5 x/ `, e! c! l/ Y# K. _, t7 L) b
  12. new Vue({" w3 t, L5 z; X, N
  13.   el: '#app',4 m( _4 p* |+ V. s$ v% Y
  14.   data: {4 [' s( w. G# E
  15.     sites: [1 l% a: N7 o8 z+ _
  16.       { text: 'Runoob' },
    2 q1 Z) b4 s1 U! B5 W& \
  17.       { text: 'Google' },2 v, k9 W. N/ s3 F6 x
  18.       { text: 'Taobao' }9 U9 M( L1 c' M: U# R$ U
  19.     ]
    7 A, U# X. s8 i' f' }/ k0 X
  20.   }" a/ `3 B9 y$ \
  21. })2 m& m7 k2 ?2 X4 Y3 Q. p
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {* U, r! r& p2 _- d' p; [
  2.   props: {" k. M: m& j" U7 a& ~2 k
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    , U& C- @# M& q0 B* ]6 A+ H* x
  4.     propA: Number,
    % i0 U6 q# g" l  t* {
  5.     // 多种类型( o: K0 L- z0 I' v6 c
  6.     propB: [String, Number],
    7 j  h' U+ n3 |0 L9 {& k
  7.     // 必传且是字符串
    ! H, r) u! A1 P$ l
  8.     propC: {. J/ [; b* D( p+ G# U
  9.       type: String,
    ! K. _: B- g3 @2 _
  10.       required: true7 l* o  V6 \- {4 n  f( M" ]
  11.     },7 @- [9 A7 U2 x4 p
  12.     // 数字,有默认值
    8 ^/ a  L( F$ w3 g
  13.     propD: {+ A8 l( j; m4 e. Y7 f1 _$ o
  14.       type: Number,8 |6 ^9 o, L* r8 ~
  15.       default: 100
    6 ^) g) x& r8 F4 a
  16.     },3 w5 s/ R2 E. }; k
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    * I! d& s6 F$ L2 t  \
  18.     propE: {1 S- Q! R9 u2 j6 v6 O4 l+ Q/ Q
  19.       type: Object,9 g3 \! f( j3 Z$ q8 H) p' u
  20.       default: function () {( X9 S" `( m6 a  L7 s! e
  21.         return { message: 'hello' }4 i! k/ I% e5 e+ U) ?; R8 L" r3 r: {- h
  22.       }5 O- h$ k( w: {4 i. T5 t
  23.     },
    * R7 _, s5 n7 W6 W# U. b- m% _" J
  24.     // 自定义验证函数
    & w1 D! G. M# s/ ~
  25.     propF: {  O) a) c7 U; m9 J2 `9 I% `
  26.       validator: function (value) {
    3 M+ x9 r1 ~' ?6 f. P( o) t
  27.         return value > 10
    7 W( L1 s- g# d- N" e- j1 S
  28.       }- Z$ W0 X" U- j7 C- ?$ R) [
  29.     }
    1 I1 @) e  S: U1 w1 h
  30.   }
    3 X( C2 E& F( d: b6 i
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array- u) Q9 t, R+ I1 {, M2 c! M4 j* z% z
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件" i- ]9 k) H! q: o: K6 p! ?
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例$ @6 |6 ~/ e4 g0 r. g
  1. <div id="app">
    / R. \* P3 w- ]
  2.     <div id="counter-event-example">
    % L2 B9 T$ @* Y4 T
  3.       <p>{{ total }}</p>
    ( N2 U) L  w' i8 [
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>7 ]$ B* C' `6 ?( I2 _2 G1 l: q- o6 G
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>" d" W- ~* p, r) z( f
  6.     </div>9 H2 D0 K; r7 t* p
  7. </div>" E! Y5 {' D% ?6 E7 i$ i: A
  8. 7 F8 r4 J% ~# v& E0 M! J$ N- }" k
  9. <script>$ h. f4 k: E# g/ ]2 f
  10. Vue.component('button-counter', {/ i+ ]  N2 P# G+ ?
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',3 b: _+ ]& T* r* p
  12.   data: function () {
    . P) e  P8 `8 D7 g- H5 S
  13.     return {
    5 A0 _/ O  v9 ]8 t9 H4 {
  14.       counter: 0
    : D9 x7 z, ^* V; w" ]+ F8 G
  15.     }
    8 F1 g" K  R5 N8 T& C
  16.   },
    5 s3 e) B: `6 B, j) p
  17.   methods: {
    + Y6 M' v* o; n7 t" d- T4 ~
  18.     incrementHandler: function () {
    8 g/ p5 \2 X/ P
  19.       this.counter += 1) H' E- X* e3 E! Z; ?2 I, Z& b0 B
  20.       this.$emit('increment')
    3 x; ]8 c2 ^1 x& c' u1 C
  21.     }
    1 @, z$ ?& `/ ~5 t
  22.   },9 E/ U. n& t! Q& \3 F. i' c- `; Z3 l
  23. })
    8 u" G7 m; I6 R0 V- d! E2 W, d. [
  24. new Vue({5 p& E  ~1 e5 ^4 d/ P+ ]
  25.   el: '#counter-event-example',
    & h, i* l5 y8 L5 O9 h' K  t
  26.   data: {
    : t5 }2 m# Q; w3 c, }
  27.     total: 09 \; k+ [$ L' h0 M
  28.   },  Q$ n9 m4 ~% R
  29.   methods: {
    / c9 O, F5 ?7 p0 I1 c
  30.     incrementTotal: function () {- s# ]( F1 N5 R. A: W
  31.       this.total += 1
    + z5 r0 ]9 u9 W- x/ r- j# [
  32.     }9 s0 U, \1 o7 A( X% f9 _
  33.   }
    4 l- f. ?8 S. y
  34. })3 G% }- M( T  T6 j! Y. W* E
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册3 y4 t8 |& o! l! b0 F7 I' _" f
  2. Vue.component('child', {
    : B5 z4 t1 {+ S# u1 Y
  3.   // 声明 props1 [; r" G: K* ]$ D* ^  m# S
  4.   props: ['message'],) R, _8 X# N$ U& o7 w
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    & c) t8 K& x- T& W
  6.   template: '<span>{{ message }}</span>'
    % b0 D9 x% w) T+ Q# D
  7. })2 k# a" z+ C( d
  8. // 创建根实例* B: {. ~( \. G2 M
  9. new Vue({+ S) ~* b. K+ _  C, L0 n: |
  10.   el: '#app',
    3 I. x# J# ?8 O7 P+ V, F- m
  11.   data:{
    , ~/ |% z) G+ a+ p' n4 {/ U
  12.     message:"hello",/ t  \. g0 g9 F9 \# Y4 ]- [) r% h
  13.   }8 q8 L1 [9 M! E8 e
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    4 X' H2 Q% f3 R1 }
  2.     incrementHandler: function (v) {
    5 ]' H1 J: f7 w- f3 I  X3 D. F
  3.         if(v==1){
      ^0 i2 e6 m% A8 }/ z
  4.             this.counter -= 1
    ! A$ q. U1 @. ]# o8 [
  5.             this.$emit('increment',[1])' Q# L3 L! C1 d6 M/ d- A8 E
  6.         }else{, g/ `- @( F* V+ b2 X) ~" ?. A
  7.             this.counter += 1
    : Q8 |) i+ n5 t3 u! C1 T
  8.             this.$emit('increment',[2])
    ( ~4 E/ J: K( @
  9.         }
    ! o4 H- O. F! j3 @; j
  10.     }
    # _1 m' w. A+ e6 J7 G! k
  11. }
复制代码
; W4 J: _* a* o) K: U
+ v2 c- X% X4 K$ [7 A/ k! z2 g
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-8-4 12:23 , Processed in 0.050965 second(s), 23 queries .

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