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,并使用它:
9 Q  b+ d( _+ {
  1. <div id="app">
    $ Z7 @& x0 {. ~3 S9 X; x1 {
  2.     <runoob></runoob>7 j8 N8 [! N0 I; H
  3. </div>
    ' ~3 [8 R$ X3 M6 y" J  |" [
  4. 6 [. H4 e9 H4 H8 n4 d8 ], |  h& O- Q
  5. <script>$ T; H& l4 j. b
  6. // 注册8 r; E2 Z3 x" x9 Q9 t
  7. Vue.component('runoob', {/ T2 G2 [8 m5 Y  w5 ~' b7 N# Y
  8.   template: '<h1>自定义组件!</h1>'; @( J5 B4 q1 Z# ?2 l0 S$ K
  9. })5 ?, O1 {/ u) q8 F1 Y: \  `
  10. // 创建根实例
    4 W& O; y3 H7 k, W; P: M' b( _8 L
  11. new Vue({/ d7 V! _0 H6 O6 ]
  12.   el: '#app'/ _8 r% c8 p3 _- [
  13. })
    - W7 w$ f8 `" R( k
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
* u$ z9 y- z) ?# l! J. p6 N% q
  1. <div id="app">
    ! i8 X% M6 W$ \; ^9 l
  2.     <runoob></runoob>
    . P& V% |; _+ N# Y
  3. </div>- p8 p+ G. F' f8 t( k# c
  4. . ^- {6 u" E+ k% \' \
  5. <script>: K+ ^7 C* V+ X" p+ U1 w" N
  6. var Child = {5 b2 n7 p7 `) B
  7.   template: '<h1>自定义组件!</h1>'5 M' q+ [* O/ {" `; l; [! l; O
  8. }6 U  F) B1 ]3 O  n& e

  9. $ i; Q/ a5 Q) o; W
  10. // 创建根实例
    # R% B' S- `7 j. e$ u: r( D
  11. new Vue({0 I2 I; y$ K, m8 x# h
  12.   el: '#app',- Q' O/ @5 z# p& x, ^1 H
  13.   components: {4 D8 ?, s1 a. L
  14.     // <runoob> 将只在父模板可用
    / G' y- U' M: ^; G
  15.     'runoob': Child
    0 `( ~/ j- G, A& U) ?! d
  16.   }- G6 U; b3 e* d0 D
  17. })
    9 F2 O1 ~: V4 U  Z+ d: L
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
, K6 e! w" v# ^& e, W
  1. <div id="app">8 G8 c! N3 a2 X9 {  d( `  x- \, \
  2.     <child message="hello!"></child>* o2 C: B5 N; C
  3. </div>
    9 W9 i) ?. b' `+ ?9 s6 X
  4. ! r( O. w. h* T6 m# x! u6 A9 M. _+ A( }
  5. <script>3 d8 x" r( ~  |
  6. // 注册
    5 S: D# X0 N7 I0 F' J
  7. Vue.component('child', {
    + b( R/ d- Y0 Q* i5 d8 p! T
  8.   // 声明 props& n6 M  P* O+ a3 y0 k. T  P
  9.   props: ['message'],
    ) F# F3 G0 p' g. }7 g. M
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    , f. u. n# s$ {9 F
  11.   template: '<span>{{ message }}</span>'
    9 F1 K$ `' G7 I$ X) z. d' |
  12. })0 |- ?2 z& N; T2 e
  13. // 创建根实例
    & j) ]$ E1 R% f/ b0 V% L! l
  14. new Vue({
    3 B* u/ C8 N; K  O
  15.   el: '#app') p, e" j2 w7 \9 U3 V
  16. })- O+ F9 v) _! }/ H6 o! i
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
' }4 V8 U3 N% o/ x  G
  1. <div id="app">
    . u  A5 M: {7 B/ |
  2.     <div>
    5 a) L; ~4 x: i4 l  I! L
  3.       <input v-model="parentMsg">
    / G* J- D2 u" z1 h( U
  4.       <br>
    : e+ A. p- E6 m* r9 @$ y
  5.       <child v-bind:message="parentMsg"></child>: m( x+ o+ b% ^8 J
  6.     </div>0 J7 @7 Y9 A- J3 e  M' t) l3 [. J
  7. </div>8 N1 r9 K3 ~* m3 G  d. p" ^3 |9 t7 A" G

  8. 7 l0 T8 V0 d* ]$ c
  9. <script>
      M# h  }0 u+ _8 H
  10. // 注册
    - r  }8 M& _3 ?2 J" Q. v
  11. Vue.component('child', {1 V% u4 z4 o! y& p. Z0 }+ c
  12.   // 声明 props) H7 Y" a  i# A4 d4 N* e# e# m( U
  13.   props: ['message'],
    8 F4 ~! q  g, X# [
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    9 i0 h1 I2 z4 V8 b
  15.   template: '<span>{{ message }}</span>'1 v3 q# g& z& M( p
  16. })
    7 V' N. K% z( B& [4 k, c( i
  17. // 创建根实例9 c' n1 X. E- Q; t6 p2 Y; c. r
  18. new Vue({) q5 ~5 B( p8 h% H
  19.   el: '#app',
    / P  G9 d1 I- d% B- Y- n( ?: c3 I
  20.   data: {9 i" I- n2 p. D2 K7 A1 I
  21.     parentMsg: '父组件内容'
    0 f% [8 y* m) Z6 y4 y/ w
  22.   }$ ]" N# [: m+ }
  23. }). q4 G: N5 k- ]
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
; k" W1 I8 V1 w) w/ O" X; t8 Q
  1. <div id="app">
    6 C6 j7 C5 @) J' d" R
  2.     <ol>
    ' v' e( u' T8 r" e! h0 z1 \+ e
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    " x! j) I7 P& Y0 w' ~4 Q
  4.       </ol>9 |4 D# B9 ?! w  N4 I
  5. </div>; r% H* L0 Z: e; M2 X: G1 |
  6. 7 b5 `3 H9 P1 {0 @2 O( x) w) {( U
  7. <script>3 Y; n  w  R; N& V
  8. Vue.component('todo-item', {
    ) E, U% _7 \9 }: S/ N7 }9 Z
  9.   props: ['todo'],
    4 J( N5 j9 [% e$ [
  10.   template: '<li>{{ todo.text }}</li>'& w  p8 Y4 B" k+ P
  11. })' P" D6 z0 M( d+ L, R6 Y+ w$ @
  12. new Vue({0 u! j6 N& a% V
  13.   el: '#app',
    . |) z/ P5 u3 p& W
  14.   data: {0 h' q* V. ?/ V
  15.     sites: [& N% y: [3 R! `- [; @& G) D$ }
  16.       { text: 'Runoob' },
    2 P( ^; z  c1 V% |3 A0 s" w" {* m
  17.       { text: 'Google' },
    0 W8 [; y+ |/ K' b# Q2 M2 K1 j8 z
  18.       { text: 'Taobao' }5 x  c. W% T0 r/ [1 p
  19.     ]* g; C5 U$ F* d4 i; ~! C3 g
  20.   }
    $ Q- n- ^/ d& [/ k8 A. x" S# X
  21. })
    ( G* Z" J) H& q7 k; x
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    + o: ^( u9 c4 v( }
  2.   props: {/ T3 {# w4 S% T) w
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)" n1 {7 \0 ^! G* h4 i8 t% v) X7 ?
  4.     propA: Number,  K% I. |% I5 h8 H$ a) T- k
  5.     // 多种类型  k4 }1 f% k2 R, _( |: `
  6.     propB: [String, Number],
    / x; F* Y7 ?+ ^3 S" Y  o# O7 V
  7.     // 必传且是字符串
    4 r' z) R) P; o* D
  8.     propC: {/ y9 A9 F5 T. h& @
  9.       type: String,% @8 \9 n3 L" c$ h3 [, U0 F# ^7 A9 [2 E
  10.       required: true
    : c4 ?2 V/ q/ w. Y( c' a& y
  11.     },
    . e# p6 {# `6 v3 r0 P6 X, ]- j
  12.     // 数字,有默认值8 w5 T5 Y: y# f1 e4 s( v! z2 ?- C
  13.     propD: {9 ]  K% }! K: O3 I
  14.       type: Number,
    ; {" o% ^/ h$ g" ~+ C$ @  ~
  15.       default: 100) e0 k; N' j# Q0 M, e; Z& y
  16.     }," V/ A/ @) [8 V% K' F4 u
  17.     // 数组/对象的默认值应当由一个工厂函数返回( Q7 n& m% O* F4 U1 u* t6 ]
  18.     propE: {
    1 e' C1 I+ |3 ?) r
  19.       type: Object,
    9 M7 L9 G1 U- |
  20.       default: function () {. Y1 l2 ?* C! G+ D) i. c" n  U* R
  21.         return { message: 'hello' }* Y: w2 o! H+ T: O
  22.       }- @; e  Q8 E$ r; l2 O& j! o
  23.     },! J2 y% k% ?4 ]
  24.     // 自定义验证函数
    3 H8 ?% N% o" k! G! }) ?
  25.     propF: {
    & ~( E8 j# S" g. W! F3 e' Q
  26.       validator: function (value) {8 P1 D+ Z0 @6 s
  27.         return value > 10
    0 B3 j! S6 Q0 X0 M2 v& y
  28.       }
    0 c" f3 x4 |: K4 h
  29.     }
    * s- X" h5 T  r. Q; {2 F7 M8 m% i9 G1 P
  30.   }$ a6 \! q) _5 ?( v& D
  31. })
复制代码
type 可以是下面原生构造器:
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
' U" ]0 X6 |8 A$ _/ L
  1. <div id="app">4 t8 P+ e! J% X9 c
  2.     <div id="counter-event-example">9 S2 L6 T  w3 A! W
  3.       <p>{{ total }}</p>& S; T' Y% v( T, w
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    7 ?( O$ J/ g6 }& l$ n+ _8 M
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>' X" D0 c% I0 p6 u! e! V
  6.     </div>' \4 Z- }+ g5 j
  7. </div>+ ~* j; h8 r+ i4 V
  8. $ Z4 v  W/ }/ a! U; n
  9. <script>& c4 d$ C% M5 [# p9 f( v
  10. Vue.component('button-counter', {: ]6 E. W' C; a2 Y* Q6 S! Z6 s
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    * t  g% i# D7 Z, z$ L* n
  12.   data: function () {
    - X7 k4 d0 |5 J/ x, e( K
  13.     return {
    - R- c; f: J0 _( U# w
  14.       counter: 0
    , ~- s4 q" U6 L, H- ^
  15.     }4 H$ M0 O3 a" t# q
  16.   },5 V/ z) q% e, {) T
  17.   methods: {
    5 T% k; \1 O6 E: u
  18.     incrementHandler: function () {! `. C& T, T; R) s, ^
  19.       this.counter += 1
    # A& I; C& n8 H/ M, u+ u# g* t
  20.       this.$emit('increment')
    5 o4 `/ g( w8 O3 b  I/ a2 f
  21.     }! ^) m# g& @" ~4 A
  22.   },
    1 i1 U, t8 b: c! i. V5 V5 x
  23. })
    & s: x7 h! h* ?; B
  24. new Vue({. r# @1 T6 u  j; {" m) S1 D
  25.   el: '#counter-event-example',
    7 U% K  g  ~6 m; t2 R% a& B8 }
  26.   data: {" \, V8 S' y) T" C5 }% D
  27.     total: 0
    0 ~+ D& B9 ?+ `+ _8 g
  28.   },% P( M- {0 e5 \! ?2 u
  29.   methods: {
    8 X* N: m0 S  C) P5 V
  30.     incrementTotal: function () {
    & F7 P  Z/ E+ g% C$ g0 p3 L' u8 T
  31.       this.total += 1
    : z4 @2 y, d. _) \3 S$ l- T
  32.     }
    % z$ E" c3 E6 G( r& O5 g# X3 L
  33.   }" ~: I& ^# P/ W9 |  H
  34. })
    , a/ d- ^& `4 O; d% x. q5 d% `
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册! R/ g, B+ ?0 ^% L
  2. Vue.component('child', {% }1 I! X4 E- C5 u5 F& v/ G
  3.   // 声明 props
    ! |3 j% x; y+ A* {/ ~# s
  4.   props: ['message'],& l' Z5 p: U) h* E
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用, l/ @; l& |9 @& y- k
  6.   template: '<span>{{ message }}</span>'
      p3 K" z5 [0 e% ~
  7. })
    4 `, f3 U$ ?" W" U! H4 r: W4 F
  8. // 创建根实例
    * E1 ?$ F5 I8 Z) P6 L% a' B
  9. new Vue({
    ; F2 G. U/ y- t8 S3 c3 I6 I( M
  10.   el: '#app',* C! Z3 m  M$ {" R0 }  P3 d
  11.   data:{5 _6 z: Z3 j/ W  p0 A. i
  12.     message:"hello",
    6 b* ]- i9 s( V! {7 H
  13.   }: c! p6 m/ N; l8 J# i! O6 k+ |
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    ' X' f' x$ G$ E, V( {
  2.     incrementHandler: function (v) {
      d( {& K2 t3 K: ]# p1 s
  3.         if(v==1){1 |) |$ p) ?( U) U& ~2 d
  4.             this.counter -= 1
    ; Z" b/ ^' D/ n. z
  5.             this.$emit('increment',[1])6 n1 B9 o4 x% a6 }8 e( f
  6.         }else{3 A5 h) c  g$ a
  7.             this.counter += 1: k- S2 |8 ?* R1 }
  8.             this.$emit('increment',[2])
    ( X: e! H0 f& ^  |+ q" s  P
  9.         }) g9 g* T/ `  _0 e2 \( X
  10.     }
    2 \' Y( w( w& k  D$ \% {# }! o. u
  11. }
复制代码
" v7 }5 }9 ~3 |1 O7 W4 Y0 q7 ~. U

' U0 s4 X) t5 w* g1 M( l4 `




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