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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

) L/ P9 y) b" U8 ]8 K$ x
  1. <div id="app">
    ! v* z/ _! \3 Q( F1 u
  2.     <runoob></runoob>
    * e6 W; v# a# e) ~; Q5 ]* n& ?  ]
  3. </div>$ h% E1 m0 Z! u0 B; t
  4. 5 s" v, ?: G3 o2 F! @! H
  5. <script># Y% J( K( w$ B& p' G" }
  6. // 注册
    # \! g! [. Z# {  ~! M% _
  7. Vue.component('runoob', {2 R- J# s) S% D: q1 y
  8.   template: '<h1>自定义组件!</h1>'( Q, I. n" Y$ r5 U* e1 O: G, U3 I
  9. }), @# e0 Z( y& s) {
  10. // 创建根实例: n! W$ @5 h) K: B  W. j/ z
  11. new Vue({  s( R$ ?+ I; w2 o+ I8 |
  12.   el: '#app'  `# d% f; g: R( ], c. Q
  13. }); G8 `" G3 M8 |0 g. `; p( r
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
$ ?' B1 s: i& v# a
  1. <div id="app">% P9 t  t3 e6 D2 T$ r: ~5 c2 j1 |
  2.     <runoob></runoob>( K4 |/ P3 Y# y, P3 E
  3. </div>
    5 A+ o6 c  V# J& d) t: ~& z

  4. , r1 U' J$ y' y- @5 q1 O
  5. <script>
    4 {( z$ d3 G$ h) @; I) B7 `5 r/ c
  6. var Child = {
    $ a; `  |6 h, |$ e' R0 o/ f
  7.   template: '<h1>自定义组件!</h1>'
    " u, y3 y+ K, h
  8. }) _" `; X- V8 l# p
  9. ! |8 ~$ n) d4 S' A# }# |; n/ g
  10. // 创建根实例2 y) c( W7 `: C# \- L6 u
  11. new Vue({; J  S; i6 s' ?- S, W9 i
  12.   el: '#app',- q' i) ~7 l& J% G2 P/ m& e- G2 i
  13.   components: {0 J5 d. q9 W* A6 b
  14.     // <runoob> 将只在父模板可用
    # b6 T/ H1 G$ P5 M
  15.     'runoob': Child
    * j+ P) F& E7 R. t# L; ~& Q
  16.   }4 m% ~- F7 }* U3 f+ j: I- e
  17. })
    ! t2 g+ W# T- f* `, }
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例# v2 c$ Q7 K) f
  1. <div id="app">
    5 W+ @& U7 f' @4 v" \
  2.     <child message="hello!"></child>( W9 S: Y  t( ?7 v+ G
  3. </div>
    / n% G+ G+ _. M% x  q' k5 G# |! U

  4. % P6 }2 G# c6 |; _
  5. <script>
    ) A1 \1 i0 {2 q; Q: Y
  6. // 注册( f( a% `' `) h" `( M0 R0 l; P
  7. Vue.component('child', {4 I7 O. ^: Y" N" R
  8.   // 声明 props
    ; q9 R( |; q; ]) E
  9.   props: ['message'],
    ) v  n# ]( z, |
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    $ |* R0 K9 H) h1 i' \; n% o
  11.   template: '<span>{{ message }}</span>'
    0 M; C0 n+ m* a, ~: D
  12. })8 |5 [* i- d$ P, {3 A0 Q
  13. // 创建根实例
    * V# ?- b6 b7 {/ L3 c& b' I
  14. new Vue({" d, P! H8 w1 ^- M3 b
  15.   el: '#app'
    7 h$ _& B$ k2 P) Z4 z' y" j& s
  16. })
    * W2 e) l. {. w# ~
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例% ~% `4 {4 y* |2 ?6 {4 E
  1. <div id="app">
    2 i" o) L, A+ D0 l5 S, H
  2.     <div>( C: T1 ]6 c+ @$ r, Z9 `
  3.       <input v-model="parentMsg">% M2 z4 u" Q2 k1 ]/ i7 F
  4.       <br>
    6 {8 C3 b8 F! M/ Q0 k/ R& a$ D
  5.       <child v-bind:message="parentMsg"></child>" k8 k% m: D( q& ~1 O( `$ d' R9 N4 E
  6.     </div>5 `5 @0 _$ g# Y& x! x7 x
  7. </div>2 E7 n9 N3 J) w" V. S6 f; l. Z! b6 f
  8. ' a7 B# ?) [  T4 T% h
  9. <script>& e4 m8 Z, K2 q" [, t: q! s
  10. // 注册
    ! |. i4 T5 h7 n+ v  \& A0 S9 ]! V
  11. Vue.component('child', {+ V. y* U( O& p5 C
  12.   // 声明 props
    ( h* d7 d# p' y; G  e! r- y
  13.   props: ['message'],
    ! K6 f1 [* Y  V4 G8 }, P5 X, b
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用7 u7 l2 ], H4 {# g
  15.   template: '<span>{{ message }}</span>'0 j) g& [1 |9 t& `
  16. })$ \! h; p% k# c4 x9 _( [
  17. // 创建根实例+ L6 D8 R" u: g2 V3 c5 G
  18. new Vue({
    2 I0 W! v& V% B5 t
  19.   el: '#app',
    . b/ B2 F/ Z$ e/ O: E
  20.   data: {
    : H" E3 `# {  ~% @$ \/ Y
  21.     parentMsg: '父组件内容'
    1 F4 u, K1 p+ ]- n; m5 m
  22.   }
    % f/ |3 [% C' \0 n; U
  23. })
    , C- h$ f' q/ J
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
7 [/ q" w" O. a, u- [( _4 \
  1. <div id="app">
    2 L3 B4 o# z+ z  |
  2.     <ol>
    ; v5 T5 P. L+ r6 c
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>5 n0 d# D, \6 p5 _1 f. v: ]8 x
  4.       </ol>
    % O, x) i- ~' [7 q( W* W
  5. </div>% z3 U& ]5 E# P

  6. / J1 i' s2 P; i  l
  7. <script>
    ) n; N- ^2 T8 e' m' _( {2 g- C
  8. Vue.component('todo-item', {0 b7 u/ d' |7 L6 {! S9 }1 l0 D
  9.   props: ['todo'],
    3 j1 ]  d  W* a. h4 Y8 Y. N& h
  10.   template: '<li>{{ todo.text }}</li>'6 c) W8 h. i! l! t4 M% K4 m
  11. })
    2 B* v9 `: Y% ?
  12. new Vue({
    2 H( M# \" c  h& H* t
  13.   el: '#app',+ E$ E' p. C7 E0 E& C# m- w- K
  14.   data: {
    * S3 y3 L/ t, x
  15.     sites: [1 l  ?) y5 X% J1 ?) P
  16.       { text: 'Runoob' },
    ; ?' b# ^$ N) t. h! ?, P
  17.       { text: 'Google' },3 D) W5 _/ F9 y1 c* v6 Z
  18.       { text: 'Taobao' }
    + M. {/ x% z  Y7 E3 V
  19.     ]  `5 Z8 P" ]% C+ }( W2 k
  20.   }
    & b# y& f3 K1 B- B$ W- F, [
  21. })
    / H8 Q) V" A  p3 a% W* O2 b9 g6 M
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    # ~; b- V+ R& y8 s( \; H2 r3 @' \6 b
  2.   props: {& `, V, q& F8 C* j2 H  s
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    8 z1 K% ^: \+ h# Q- t
  4.     propA: Number,- \. K3 O% p0 c. w. d
  5.     // 多种类型& X: G' W& K/ N/ [* i' t. G
  6.     propB: [String, Number],
    3 [0 f8 t3 m; l6 c: \, O
  7.     // 必传且是字符串7 K2 X% u( \: R# n
  8.     propC: {/ U& b3 D* n7 D4 x# R4 A
  9.       type: String,
    - {: R4 s. Q/ i
  10.       required: true
    , _' T  a8 P, H7 X! ?2 D
  11.     },5 a5 e7 z/ B" R( Z
  12.     // 数字,有默认值( s% y9 Z" z* l% B
  13.     propD: {
    * P% T: `; b4 o" w) t- P' k
  14.       type: Number,- q, B0 H) V& C
  15.       default: 100
    9 P) t( @& Y; u6 R; a& C0 D
  16.     }," q. Z; E; t! Z, b+ p9 v" N9 k6 C
  17.     // 数组/对象的默认值应当由一个工厂函数返回1 j- h1 a! K3 p
  18.     propE: {0 U0 \/ K0 d9 Q) ~1 O; ]
  19.       type: Object,
    $ M0 {+ C2 o6 n& d: _: e
  20.       default: function () {8 [) M) Y$ }, }7 Z% S& G6 g# Y( S
  21.         return { message: 'hello' }8 W  `4 t4 {6 m
  22.       }
    7 Q0 b8 ]/ v8 M7 U  }" n1 g# H
  23.     },7 M8 G5 M2 J( t. w* R5 {
  24.     // 自定义验证函数/ t4 Z" P9 A# ^# Z, W
  25.     propF: {. y" w* {5 d2 T
  26.       validator: function (value) {
    9 E* }( b; j! E7 U
  27.         return value > 10
    % W# Q" b' |: Y1 }8 L
  28.       }
    # s  J/ ?7 B0 f2 E! Y3 _) t' s
  29.     }
    $ f' C1 E  v! c5 a1 F& A
  30.   }; ~7 {4 [; N+ ?0 U! C* P  B
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    - J6 U* `+ L& ]9 C5 f" ]( [, B
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    : b/ |6 O6 |4 Y( L
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
. c5 N' _7 [) J; |& y
  1. <div id="app">( |9 m$ m' Y2 F  z" c0 X. s
  2.     <div id="counter-event-example">
    / x& v, F+ L: F* Z/ J! `
  3.       <p>{{ total }}</p>
    - f+ E7 ]4 I: H
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    2 }/ O8 O) m0 W$ F( o9 k% {, j
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>- K. |2 z3 n# B9 `- _$ H
  6.     </div>1 m- T3 w' z/ o4 J$ A. B
  7. </div># i8 G- s" F. h+ }6 S( [
  8. + p& {! ~4 I, U( p) L$ a$ O% S+ x" v
  9. <script>1 R2 y6 @8 a7 X' k' E# B. L
  10. Vue.component('button-counter', {
    $ W0 Z  Q* ]7 J
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    * }/ S- Y( }9 o
  12.   data: function () {
    8 C5 C4 f% f5 a' o
  13.     return {
    ( m3 G8 J8 p( O2 s; F  B6 x# _
  14.       counter: 0+ E" M+ b# X$ n0 R4 t# K
  15.     }- n' B. G0 o0 }. g6 O( f( ]: h
  16.   },
    ! H2 p: D0 e5 ^6 W5 W
  17.   methods: {
    , F1 _1 u6 p- u( C$ D4 J
  18.     incrementHandler: function () {
    * G( U2 ]) S3 ]) D; A
  19.       this.counter += 1
    ) Y, a2 G2 }7 `% S; W1 I
  20.       this.$emit('increment')! l/ A7 ~  a+ r( o% r0 I
  21.     }
    5 D$ S: P' c; p5 Z( `5 U' C# N
  22.   },
    - g9 H3 I: U3 o' {+ d8 C
  23. })
    - K) y# p* U- I6 F: d
  24. new Vue({
      r# ~3 V4 {: Q7 p' J  c2 v& i( e
  25.   el: '#counter-event-example',( K( c0 v3 x0 G% a5 Q0 K6 v
  26.   data: {2 J8 i& ~3 u( Y* c3 |0 B
  27.     total: 0
    - T: l5 N+ |. Y2 I5 W0 r
  28.   },1 }6 T+ d# H! K' ?# K$ @* v: h
  29.   methods: {
    # k% r( N5 K2 |* J% B1 X0 x
  30.     incrementTotal: function () {0 R/ i* Y0 H; P/ j7 ~  \
  31.       this.total += 1
    . {, B0 R0 @) S, t& h6 a
  32.     }
    " b# j! y/ ]$ a4 y% z; o2 x6 `+ \
  33.   }' M  f" }, d4 W) m1 M6 [1 a
  34. })7 r3 d0 X9 b3 \" P- h
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册9 G0 m4 c/ c! t4 D  I* ^- w  a
  2. Vue.component('child', {
    9 s5 }" c8 S5 w  C3 c: Y9 t1 m3 a
  3.   // 声明 props
    9 n- }6 N/ T" ]5 n8 t3 U9 D
  4.   props: ['message'],
    4 B$ }* i$ J+ r% Z% {* N
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用6 n2 ^& F* n3 h5 G
  6.   template: '<span>{{ message }}</span>'9 A( D& C! d9 f: \: I
  7. })% s6 X0 w, u/ M4 g3 z3 `
  8. // 创建根实例
    7 ?, Z( @0 V3 Y$ p4 m# n+ m
  9. new Vue({
    + z- ~6 b% ^. s* y  {  D
  10.   el: '#app',  R5 a' A8 m7 I# ^+ x# K
  11.   data:{
    5 W( U1 p& F9 ~# L: N  N# s
  12.     message:"hello",
    * V' k$ _1 c3 c  Q9 F* ^
  13.   }% ~7 a  Z* ?3 l% X
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {9 d$ E& g2 [9 R) H- \
  2.     incrementHandler: function (v) {
    ) ?' J% {$ P- X
  3.         if(v==1){
    2 G% ~9 g6 o, t# c
  4.             this.counter -= 1
    / W, k% S# s3 e' ?0 t. l' {
  5.             this.$emit('increment',[1])
    5 w/ l' V' q0 M0 M( u/ ]5 G
  6.         }else{5 ?. _+ b( e4 E& \
  7.             this.counter += 1
    & m! v& r9 {! {2 l. U
  8.             this.$emit('increment',[2])" T: W7 C1 h5 p/ r+ G* @
  9.         }
    6 Z" G, [. n' d$ `) k$ p
  10.     }
    " P2 t0 A# V( @8 ^" k, y/ M
  11. }
复制代码

7 B" b0 M- X8 G. ]+ D& |4 d
( n. o; `# e! C5 Q
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-8-4 11:36 , Processed in 0.056763 second(s), 23 queries .

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