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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 16303|回复: 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,并使用它:
0 A, ]  G: k4 E, F
  1. <div id="app">
    8 M. s! W) r5 L6 f8 m! M7 D8 |
  2.     <runoob></runoob>
    3 q  @# T4 D8 L) D
  3. </div>
    . U1 W, z0 s; D8 ~( ~: |& C

  4. / E5 m$ T4 r% O) n2 P, ~4 d, Y9 R
  5. <script>
    ) B9 `, A+ a# ~9 R7 V2 w- T
  6. // 注册' {, k, A: ]9 V
  7. Vue.component('runoob', {- [$ ~# z  H' o3 q: j+ X- D. K" u
  8.   template: '<h1>自定义组件!</h1>'
    0 f# F9 b- @( P
  9. })% e1 F0 Q+ P; [5 s7 F! s
  10. // 创建根实例5 l% h6 [! w  |+ R' W% `6 G0 K' ?
  11. new Vue({( p  U' v, x4 I0 E
  12.   el: '#app'
    5 r5 w6 j6 c8 ]/ d( M- r6 y4 Q
  13. })8 z/ T: \) ]  g" u3 B2 b
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
8 P, ]9 Z, x& A* [7 y# {
  1. <div id="app">
    . v2 m: p/ w0 a5 E1 W
  2.     <runoob></runoob>. n% Y0 S' b0 v* _0 O
  3. </div>
    - v% X* R+ a+ A3 }% \$ K8 _1 q

  4. * X) |# o. t& \# {+ e
  5. <script>% n; d6 c' ~9 o" j6 X: L' s$ n
  6. var Child = {
    7 y* B# V' q) j3 ]3 Y5 L* [0 E
  7.   template: '<h1>自定义组件!</h1>'
    # h' r, F( F3 V* G$ x. a
  8. }
      p2 V* r* S0 h* G

  9. 6 c1 x2 C4 k2 ]+ a
  10. // 创建根实例
    # b( g0 ?! l% R/ }$ m% l
  11. new Vue({
    / x6 g5 s& S& _3 A  T
  12.   el: '#app',
    + I- A4 g& i6 S) y
  13.   components: {
    4 o2 i7 o% Y1 E/ V& p) a
  14.     // <runoob> 将只在父模板可用
    # Q3 m* J8 C# J: t
  15.     'runoob': Child
    - d. s; S; Q9 ~7 u. x9 g
  16.   }% |2 [4 R2 S) Q; ^5 |# A2 m
  17. })) y( W5 t& U7 o5 G  ]8 l5 h1 b9 Z( V
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
3 Q: s4 D: P+ b& A" r& r
  1. <div id="app">
    1 H- _2 x% V, M
  2.     <child message="hello!"></child>6 r5 ^$ [& k: Q
  3. </div>
    ) y0 R/ T& _4 v7 k, @
  4. ) n3 H# r6 i: E, I9 R
  5. <script>
    6 E) |. L7 B- A  y+ `
  6. // 注册) Z& S  b# s# }& j( J
  7. Vue.component('child', {5 }4 f6 r! B7 Q  m" ~2 {0 M7 P+ `
  8.   // 声明 props
    ) ~) @! G. A: v6 K) @( ^
  9.   props: ['message'],! u: ~9 B$ k& \" X* C, J
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    " U( H3 }9 {" X% t! O6 B8 j
  11.   template: '<span>{{ message }}</span>'
    ( n% O9 @7 O% W; J3 G
  12. }), o2 S- L1 R: }
  13. // 创建根实例
    1 h9 L/ l2 {# v6 ^' c' z. t, A
  14. new Vue({; u6 y, W8 k0 I, Z4 \0 H, B
  15.   el: '#app'
    " i5 I" F/ {( w4 I2 J9 ]
  16. })
    6 R1 ~$ w7 U& D4 T! c+ o
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例! d. {$ O* ?5 n/ I+ Z3 b
  1. <div id="app">* S2 W8 z% U  w  Y. l
  2.     <div>, H$ k1 q- g- f( J4 Z
  3.       <input v-model="parentMsg">
    , t- _0 r& ?& p" Q; m1 m
  4.       <br>
    . X  ]. c. H  B% |! t
  5.       <child v-bind:message="parentMsg"></child>. D2 Q2 K6 O9 f& Z( n& v
  6.     </div>
    8 `  q, f  K  {: O' S
  7. </div>' M. k+ \3 c& t3 r7 v
  8. ( d9 i3 O4 ?/ E
  9. <script>
    ! D& m& v- W, ?: |- J8 Z
  10. // 注册5 L" }1 P! Q+ A& ?% a9 U8 }8 Y  S
  11. Vue.component('child', {3 x# t7 n+ B- v. g2 U
  12.   // 声明 props: q$ @  u1 f8 t" ?
  13.   props: ['message'],
    ! z$ q/ j) O' @) [: k
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ! m# B% G4 V4 I( y
  15.   template: '<span>{{ message }}</span>'
    ( Y/ _# C/ m" |
  16. })) Z4 V- u( `% }& ~0 D
  17. // 创建根实例
    / Z! @+ E, f+ Q; g1 L) L7 p* M
  18. new Vue({: T3 b( ~1 y" K, B
  19.   el: '#app',5 U' O- g" w$ f' I, @; w
  20.   data: {, g/ ~9 E( m7 g
  21.     parentMsg: '父组件内容'+ n; |2 |/ _2 e+ s+ O# S0 `3 v
  22.   }' j. d/ s5 I; l  s) {$ k3 V* U  T
  23. })
    7 ]9 F# r& k( j6 h
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例+ E0 A$ _  i, z
  1. <div id="app">
    " g6 e) q- h, D! l0 \1 B
  2.     <ol>
    & M6 A( p( a/ e4 b  e/ P
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
      I" d3 W+ r7 w% {/ p* N
  4.       </ol>9 y7 x9 X; \5 e4 |! t
  5. </div>. a0 }7 }+ }8 Z) X
  6. $ }1 j% C: O  ~$ A
  7. <script>5 u& w5 F6 D  |  M# a. i; B
  8. Vue.component('todo-item', {, w( ?- V. l: L' ?. I, R  |
  9.   props: ['todo']," M3 [1 r9 O( v5 |
  10.   template: '<li>{{ todo.text }}</li>'
    $ E9 ~% |* i5 I/ @9 a
  11. })
    $ i' g0 D7 E0 r' ~9 P! T! b" v8 Q8 X
  12. new Vue({9 Y3 S, V4 r. l, u
  13.   el: '#app',
    5 R& [5 g4 H/ S) }& z
  14.   data: {
    ; |2 [8 Q% I) d7 R5 {3 Q- S
  15.     sites: [1 [0 b4 }* \: |( n
  16.       { text: 'Runoob' },
    5 g( |, U8 j0 i6 [; R9 X7 o+ ~* Z
  17.       { text: 'Google' },* _# a1 g3 e$ W
  18.       { text: 'Taobao' }+ {- F9 \. b9 k6 W( t1 v: E' a
  19.     ]
    - L) O5 V9 ?6 A  ?6 T, r
  20.   }: K8 y4 w* F) r( G
  21. })
    & k5 z: u/ h: I7 t% G
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {' H* d- q, y) X- V
  2.   props: {
    $ L. V  f2 g/ O3 A, O  `
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)* m  I8 J  h$ }5 g) a6 c( L" n, J1 |
  4.     propA: Number,9 \' {% Q7 e# ~& J3 @0 ~
  5.     // 多种类型" F9 @3 F; v5 h* d+ E$ v$ T1 e
  6.     propB: [String, Number],1 K# E9 v9 v/ G9 F) E: W. |0 ?1 O
  7.     // 必传且是字符串9 A+ x# v& {/ _
  8.     propC: {
    6 N' E) H1 o' u5 }3 L$ E
  9.       type: String,
    3 G( _( T+ u1 X% w3 o
  10.       required: true! }0 r# g4 ~% d7 E) @
  11.     },) Q7 }; a3 o7 N4 v" ~( H% G. d
  12.     // 数字,有默认值
    $ D- J' R( B$ E! o. o
  13.     propD: {# \6 q2 v4 |5 I( H$ z* r
  14.       type: Number,: z' w" x- O% ?6 G
  15.       default: 100
    ! N" ]5 L7 G' q$ J' ~3 _
  16.     },: \- m. z$ c# ]) w$ s' u
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    9 J3 f) a- g6 `3 [; Y: K5 c% o0 Q- Z+ B
  18.     propE: {
    ) H. E3 n* g2 b% D& r$ Y
  19.       type: Object,& t: i% P- u; v+ x- f7 f% @
  20.       default: function () {
    ) _& Q$ p( w) O- R$ ~& S  O; I
  21.         return { message: 'hello' }+ w& i( E( `4 V% b6 g: a3 F
  22.       }
    4 B* r( t4 u3 |" M& |; T
  23.     },8 k; q0 v. ?6 R9 C; \8 O' N
  24.     // 自定义验证函数
    , U8 G4 l& \9 r) j
  25.     propF: {
    ' i" Q. y5 w1 o8 K1 }
  26.       validator: function (value) {% P4 Y( h" ~9 x) v# W6 d& X
  27.         return value > 10
    % i3 w/ W# _+ a' ^
  28.       }. C8 n0 `. c+ H
  29.     }
    % d8 _+ L/ _+ p
  30.   }' _6 B) @4 I4 k# t% v! Q2 _: a
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    2 s# Z1 g$ ?  y
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    4 S3 j# L9 n  B4 }- X. L6 z9 {
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
' U2 s: d6 |1 l. x$ Y
  1. <div id="app">1 N& x& W2 K/ w0 W
  2.     <div id="counter-event-example">7 K7 k& w0 L8 m) s- |  a* K
  3.       <p>{{ total }}</p>% K$ H( g) Y4 n$ K
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    5 Y$ ?2 C$ c  m2 H
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    4 x  n# e7 \# x* m% l. \* J
  6.     </div>( E2 X% |# z0 j8 ~  X, ?
  7. </div>6 y; H1 i& T" q0 K6 r7 p

  8. 9 N# j! |0 j0 Q* ]. p4 U* R$ ~5 L. q
  9. <script>
    9 T/ D/ s, n  l7 ^
  10. Vue.component('button-counter', {
    - t( {( b1 o1 S) s1 W" F) b4 Y, o
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    0 D, q, B! Z/ G1 T% p/ `
  12.   data: function () {
    ; z, {+ k. W# H/ |1 e( e; P
  13.     return {7 n  w; s, C# ~2 Y7 v% V0 w0 S  }& L
  14.       counter: 0
    / X6 z- e2 T! {+ s6 Z: y
  15.     }
    * Q: R4 \& g4 w
  16.   },( Z4 x8 K, A* D% p" P
  17.   methods: {8 k4 k3 X. U0 p; K) J# l
  18.     incrementHandler: function () {
    5 S% N) o/ U  w! e7 k, K% g/ K5 _
  19.       this.counter += 1. t3 V- ]$ s+ c2 D7 G
  20.       this.$emit('increment'). ?- ~: u' I* Y' j
  21.     }
    5 D7 k. z) z9 O, q. m: }
  22.   },: ^# w; V4 \# C9 T' J
  23. })1 `$ k1 s4 c" x% B, ~+ Q- t8 q
  24. new Vue({
    + W3 p( C7 i' b
  25.   el: '#counter-event-example',
    5 i2 }- Y. U7 a) ?/ P
  26.   data: {1 m2 e" Y; e+ f  ~* M+ x) F
  27.     total: 0
    . W6 |+ h! N  v
  28.   },  ]2 [( W' l/ @1 s4 m' C
  29.   methods: {
    + J# e, T* u$ Z
  30.     incrementTotal: function () {
    4 Q/ o' p/ k2 `! l
  31.       this.total += 1
    . h0 W: a- a. Z* m  h
  32.     }. P6 f' G  [7 Z5 z' k
  33.   }. K4 ]# g; S2 A0 q
  34. })3 f9 ^6 ^$ x* B) {, X  s1 d1 n
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    , N: L) }' m2 o/ A5 c  I$ e
  2. Vue.component('child', {
    5 Z& j1 N3 J& G+ W
  3.   // 声明 props! i- [  y- @, ^/ w- s
  4.   props: ['message'],* G# J: }5 R6 @, ?+ f  o  u
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    # l; s' p, {0 n% P1 I
  6.   template: '<span>{{ message }}</span>'
    ; ?0 b. T: T: O" Z) I5 x
  7. })
    6 w: a8 w4 }" d0 h4 j* j
  8. // 创建根实例* {/ N2 H, @% w$ t, t4 x2 ]
  9. new Vue({
    . Y5 D1 D2 C8 }6 B& Z+ \1 W& w
  10.   el: '#app'," _5 {, D8 [! m& Y
  11.   data:{; n; Q; Y9 ?+ u; P% y% a6 n
  12.     message:"hello",
    $ S  `2 f$ B# r5 b' J+ D
  13.   }
    , ~  z3 }: G) [: N/ B9 ^  t
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {1 ^) z3 H" g" ^5 B
  2.     incrementHandler: function (v) {
    8 [8 L2 B/ `5 P* p+ @& T, u; ^
  3.         if(v==1){1 s% `3 |4 C0 P5 Y# H! [
  4.             this.counter -= 1
    $ B/ h) j$ P6 A7 A3 m, E
  5.             this.$emit('increment',[1])$ C) m% s% r8 ~# i0 r
  6.         }else{  H' i+ N3 O8 g' d
  7.             this.counter += 1
    - X  X  j+ L' y* c$ {$ Y8 q+ ~
  8.             this.$emit('increment',[2])# S; Q4 I6 A" Z' ^" V  X
  9.         }6 f$ E: T. R7 y0 W' q/ Y5 `
  10.     }
    2 ]3 F0 P- I; K1 n- W  g$ i* j9 x
  11. }
复制代码

8 g# i6 ~. _7 T4 y
/ B0 n2 ^9 C( {" [
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-8-4 14:22 , Processed in 0.051803 second(s), 23 queries .

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