cncml手绘网

标题: Vue.js 组件 [打印本页]

作者: admin    时间: 2018-7-4 11:28
标题: Vue.js 组件
组件(Component)是 Vue.js 最强大的功能之一。
组件可以扩展 HTML 元素,封装可重用的代码。
组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树:
注册一个全局组件语法格式如下:
  1. Vue.component(tagName, options)
复制代码
tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件:
  1. <tagName></tagName>
复制代码
全局组件
所有实例都能用全局组件。
全局组件实例
注册一个简单的全局组件 runoob,并使用它:
* i; |( k* C* L# g, C7 C* h  W# t
  1. <div id="app"># j- }( F0 {- U$ I, D
  2.     <runoob></runoob>% @+ B: Q0 i8 \# P, `* e( I
  3. </div>
    ! W" s4 j- t1 B
  4. # W! `6 p& b9 V
  5. <script>0 w2 R" p; Y* m; ^3 j! z$ u# c
  6. // 注册
    % l$ M- ]  P. e) Q+ Q
  7. Vue.component('runoob', {
    1 [. @5 P4 a( C" @$ L- D
  8.   template: '<h1>自定义组件!</h1>'
    , \8 S% C8 D/ V% E" ~
  9. })0 x/ d8 p( Y; a0 H6 Z
  10. // 创建根实例$ u$ [; p4 }! m9 D
  11. new Vue({$ ?  S; Y$ \. H: Z" ]  t$ b9 m
  12.   el: '#app'' d: O8 C* @: j6 p4 N0 i4 l
  13. })
    4 m9 G: r% {4 x* \/ y& X- V
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
/ k  Q: ?' F4 ?5 [0 C
  1. <div id="app">& ]; z5 i3 q6 s! n/ ?
  2.     <runoob></runoob>
    $ r; H$ m* P% I5 U' F$ m2 |
  3. </div>0 F: a# n8 e. I. K7 g; I
  4. & s" K5 F+ t/ k4 q2 U
  5. <script>. U+ r# C) c, E# X
  6. var Child = {% |; a+ N0 ~2 d/ [; L
  7.   template: '<h1>自定义组件!</h1>'0 k; y% o+ H& C4 {5 \& B
  8. }) D5 n  M8 Y1 n
  9. ) A% Z; f% H, u7 H8 {  d
  10. // 创建根实例5 g0 G$ q! \- @9 E7 i
  11. new Vue({4 Q; x+ \3 I: t8 u1 o* P  @
  12.   el: '#app',8 S" Q+ z! ]% q3 [3 z8 L
  13.   components: {+ @) A% W( K( @0 m
  14.     // <runoob> 将只在父模板可用+ g. t2 C  _2 f  K1 V
  15.     'runoob': Child5 V' f  A; Z! m1 u
  16.   }
    * k; x# S( a8 i7 ]
  17. }); v2 P9 L6 A; {7 f
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例2 d. N3 f0 N* y
  1. <div id="app">
    3 `% }: ^: E4 m5 x9 T. \1 d) Z' U
  2.     <child message="hello!"></child>
    ( ?# d0 L5 v! G
  3. </div>& z$ ~) m: }8 [8 M' J* r; k
  4. ; }! y, D) F% s9 j+ I" W& o% d; b
  5. <script>
    ! Y, y. ^* M8 V4 A; I( y
  6. // 注册
    ( m& P5 F9 E# _  d4 ?8 ]0 Y
  7. Vue.component('child', {
    8 m8 _1 Z# m( S: q) B% L
  8.   // 声明 props
    , z3 L+ w2 k8 x" Q6 R
  9.   props: ['message'],
    : B) ?/ j4 H$ \
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    7 W$ j- ?' b. _0 @4 {/ N* d& T
  11.   template: '<span>{{ message }}</span>'
    9 L  D' d. E1 `: J( {9 A. \3 ^
  12. })
    ) h  X# x9 N. U
  13. // 创建根实例2 Q7 Y3 v# ]5 U7 @8 Z; @! n& D& n
  14. new Vue({' T7 c* l4 b4 W& ^- B+ I  a
  15.   el: '#app'. l2 e1 E; w0 K* G
  16. })5 a9 _. z. r- X! e. _
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
! y( `3 Q6 V: l9 J* Z
  1. <div id="app"># C( B7 N+ [: @
  2.     <div>- D. @' Y& S# e4 k
  3.       <input v-model="parentMsg">0 X2 g; I2 a* o/ }( t9 `4 I
  4.       <br>
    ; c$ r2 Z+ r) [* ^
  5.       <child v-bind:message="parentMsg"></child>+ q( C# n0 g, c  c- W
  6.     </div>
    # g8 `) O5 f& j' v0 o, V
  7. </div>5 [# `/ k! P/ ^3 }* K

  8. , i; O  \( T: {& q- l  ?7 S
  9. <script>! q& J9 ^/ M* x: ^' G
  10. // 注册, J/ ]1 K4 a% C1 Q3 P8 G
  11. Vue.component('child', {' [: w; A2 p+ p% L, e9 r! `" @: i3 ^4 m
  12.   // 声明 props  y3 s) B3 Y# ^" O. g: L+ p8 y1 w
  13.   props: ['message'],
    / U/ G- y1 B$ P
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    8 B8 _* u; K8 t- f
  15.   template: '<span>{{ message }}</span>'- I; i* u% M; O! e8 E2 B
  16. })$ Z  g8 Y. S  A  b4 Z  G/ X  _3 j
  17. // 创建根实例
    3 V5 ^; W- p; v& P, f1 ?9 Q, D
  18. new Vue({
    ( K  J$ i, B! L+ J) a
  19.   el: '#app',7 [3 z- L- z5 X& \* G' t/ C: J: p; K
  20.   data: {
    7 m8 E9 i; o  A: U+ Y+ ~0 ?, x
  21.     parentMsg: '父组件内容'
    , T+ K) c$ G. g5 u$ s$ \
  22.   }# L* A% _! h5 u
  23. })! ?, D' A+ y3 m
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
7 t, [# E  d  d: c* h2 U$ T0 L
  1. <div id="app">: F; L% f. {0 R* ?0 @8 s
  2.     <ol>
    9 g' V1 c3 z% c! k4 Z  u- T  U
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>! {8 J+ p" Q1 V: H- F, J
  4.       </ol>
    % @, _, z. @* W* ^6 Q8 G5 t# b
  5. </div>
    8 r( ]* }$ e# s# ^  l

  6. - u$ K0 {% j# R# ^4 _
  7. <script>- N, x4 G: A: b, Y% P
  8. Vue.component('todo-item', {
    6 v7 d. ?0 n' m! [
  9.   props: ['todo'],
    , q3 O) f1 |# ?1 }$ D
  10.   template: '<li>{{ todo.text }}</li>'
    & d) E/ U4 j1 R" b5 ]3 P- X
  11. })
    9 z; p; L/ Q! l
  12. new Vue({! K0 _2 E$ O  L1 G% u* t* |& L, _; m
  13.   el: '#app',: A6 t0 T$ n2 V$ ]  E
  14.   data: {
    - ?. Y3 P: z2 e' `" J
  15.     sites: [
    % L, e2 u( r! h+ Y; E
  16.       { text: 'Runoob' },! p" A; A1 A  Z$ U1 y+ a
  17.       { text: 'Google' },
    1 F. g* ?. J! G6 k7 Q) w" o
  18.       { text: 'Taobao' }, v& |5 W- k5 R# m/ i  a' m6 f/ ~
  19.     ]" L( t, v2 h) Z1 c; m- B, G5 y: p; h
  20.   }
    6 Y4 P% o, R" Y& |) u
  21. })
    3 Z( u' \6 j0 X7 ?/ r* I3 H9 u9 U
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {6 p$ g. T  H2 L' |
  2.   props: {
    " }$ V5 f4 C4 b! f! g
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    5 W: K" N; @  g0 V, I# w
  4.     propA: Number,
    8 |" C7 }) B, Q
  5.     // 多种类型8 h1 X* k- S5 P' `' U, Y; y
  6.     propB: [String, Number],/ r) N% R1 q0 E3 L4 g2 c7 j; O
  7.     // 必传且是字符串+ }; Y$ O' c, W. U- _# E: N
  8.     propC: {1 q1 d* U' v: S8 _4 J( g# h6 t5 y
  9.       type: String,
    - E4 C: I( M4 r1 g+ q, J2 k
  10.       required: true3 O( X4 ]5 d8 s* Q& Z, ^
  11.     },0 Q% V- T; h- h6 Y- K
  12.     // 数字,有默认值: M( [" ]4 U* a  D* T
  13.     propD: {
    & [$ A/ t+ a( I) J7 S. H
  14.       type: Number,( G: q( O+ _' x/ \6 h- Y) s9 }
  15.       default: 1003 J/ u% R  w) \2 s2 A  [9 R
  16.     },3 U& L- P$ ]' {$ L/ z( T8 g& `
  17.     // 数组/对象的默认值应当由一个工厂函数返回8 x  |. x' C) \, o" w) Q$ c9 L" _* P
  18.     propE: {
    $ r" w9 w: d: o) C# ^) d9 I; G
  19.       type: Object,0 y8 \$ F" C9 P- V1 U
  20.       default: function () {# `* b, p' t3 ], U3 ?0 C+ ?
  21.         return { message: 'hello' }: U, a2 e+ X1 R4 n% ?
  22.       }. ]) Y/ S: E8 B2 G4 ]+ V, q
  23.     },
    ! k' g8 @0 f+ ]5 B! \2 G( w
  24.     // 自定义验证函数, p' E" S4 \* J, a
  25.     propF: {
    $ N1 ~7 c" y0 w0 t- n
  26.       validator: function (value) {
    2 z' K9 M# y* [) s; b" Z* N
  27.         return value > 10
    # ~8 a* j, g) h' g3 @
  28.       }
    2 b. s2 V: l! |) Z) v' W3 A
  29.     }
    " I( H! S- K5 [6 Q! d! e
  30.   }
    + ]6 O% S9 i6 ]+ o
  31. })
复制代码
type 可以是下面原生构造器:
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例) ^0 _' X3 b( J( E, E! D  G
  1. <div id="app">; ?5 h* l8 h4 a& H$ i7 t9 W% A
  2.     <div id="counter-event-example">
    ( |( d- v6 M8 a9 a, g( d
  3.       <p>{{ total }}</p>& j8 U/ s8 x: D3 L- i" A0 }+ H# n
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>$ C3 Y( @1 J# g! S0 b
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>2 S: H2 f  @; D: V" i1 n8 Z
  6.     </div>- k' u, {+ g6 A
  7. </div>
    / R7 N7 H& `. G1 l8 t5 n  P% \

  8.   P8 L6 U9 `+ U: W" X, _
  9. <script>
    2 Q$ q; \5 c6 g' W' D- G
  10. Vue.component('button-counter', {% k# [+ U" G7 }, @( n9 ]) P
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    : l7 i' p# d4 I" r, A0 L
  12.   data: function () {
      A; `& d: p6 z( l
  13.     return {
    & T9 X1 q! x0 |9 {9 w. s( a
  14.       counter: 0( f6 E5 z! m, z- T
  15.     }
    5 J: `! L3 ~! r$ H/ F
  16.   },
    4 n* ~- C: R: Y
  17.   methods: {
    3 T! z0 d5 d% v
  18.     incrementHandler: function () {, v$ D6 i7 M' p( T
  19.       this.counter += 18 T6 k& d3 \' K+ Z6 a7 H( a
  20.       this.$emit('increment')
    . _4 y0 U" g. x) F
  21.     }
    1 A* t% O! o. F$ b& T1 `9 t! `* [
  22.   },
    ; S4 Z' b( D0 H- R# w' Y
  23. }): n) ~: g* [" u: b/ b
  24. new Vue({
    . d4 y3 B! ?4 \, v9 {7 C, l# j/ w1 c
  25.   el: '#counter-event-example',
      _: q" @% a5 ~2 q  b5 f4 A" S' [5 J( i
  26.   data: {
    ; F! B: D+ z6 M
  27.     total: 0
    ( @  q0 `3 y  z2 Z$ S2 }* t' S
  28.   },
    8 p( Q. e  h1 L
  29.   methods: {; s  A0 I3 u, o7 {
  30.     incrementTotal: function () {, W$ F. t* U  n; v* }
  31.       this.total += 1+ ~2 i2 N+ }+ [0 X
  32.     }
    $ E- i8 e" u7 G2 W' ]$ q4 `
  33.   }4 [, q- A. Z. J$ G/ O2 d- s/ S
  34. })
    3 f1 c! a4 Q4 f2 u5 k
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    8 H. z9 h1 k) j+ W( U
  2. Vue.component('child', {
    & c+ }# x6 Y4 ~: @
  3.   // 声明 props
    # j# Z6 ?  ?' C+ r
  4.   props: ['message'],  I: w* A; Q+ I) O3 Y2 M* B$ [' t
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
      z" P" B  L: `- J4 |7 b
  6.   template: '<span>{{ message }}</span>'
    5 \  A% F3 Z2 ^- t
  7. })/ o9 i, R% p) N6 s- C# }7 u( ]
  8. // 创建根实例0 k# V2 Y5 C2 S# W
  9. new Vue({
    9 t+ E. v+ ], Z3 H
  10.   el: '#app',+ Q* b# e2 ?9 x3 s; e
  11.   data:{
    & ?( D; K% T' S  R& G5 a+ }
  12.     message:"hello",
    ( C+ g1 K( q% Q+ p* g- |
  13.   }
    5 f0 P+ a3 q8 O" G: S
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    1 l) {" B# c1 ~( U. D) P
  2.     incrementHandler: function (v) {
    ! S; i- @+ x- |
  3.         if(v==1){# Q1 @( ^4 M$ m+ n/ w; q
  4.             this.counter -= 1
    , l( y$ W0 O. ]+ e
  5.             this.$emit('increment',[1])) H+ O& N) F/ K8 T' C
  6.         }else{
    1 y. a- s$ t% k3 `$ [
  7.             this.counter += 17 g! L& B& s) q& N9 h
  8.             this.$emit('increment',[2])
    / i. o9 M6 u, F( x, s1 R
  9.         }
    ( L7 F3 G8 a  _' Z" L( ^0 t
  10.     }4 C- `, ^4 c; Q" r- x3 [! q0 }
  11. }
复制代码
' `* e3 E5 q* `9 N5 G' T9 ?' Z9 p

' i; x# Q9 H5 J) @




欢迎光临 cncml手绘网 (http://cncml.com/) Powered by Discuz! X3.2