设为首页收藏本站| vip购买 |

cncml手绘网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 209|回复: 0

[Vue.js] Vue.js 组件

[复制链接]
发表于 2018-7-4 11:28:06 | 显示全部楼层 |阅读模式
组件(Component)是 Vue.js 最强大的功能之一。
组件可以扩展 HTML 元素,封装可重用的代码。
组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树:
components.png
注册一个全局组件语法格式如下:
  1. Vue.component(tagName, options)
复制代码
tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件:
  1. <tagName></tagName>
复制代码
全局组件
所有实例都能用全局组件。
全局组件实例
注册一个简单的全局组件 runoob,并使用它:
) [; ?! {# S! P; }& r/ A! B9 p
  1. <div id="app">; D% C% `2 q! p$ o& }0 C8 R: R; O
  2.     <runoob></runoob>4 D9 _6 V5 w9 ~
  3. </div>
    $ R8 i4 q7 u9 r) p( D2 E# i& O! I
  4. 9 S7 ]9 @: s% k1 `9 q' ~3 |
  5. <script>( e! Y3 N% Q1 \* `5 c( r1 F  ]
  6. // 注册
    4 ^9 D# o4 z: j- W
  7. Vue.component('runoob', {
      W- d  p# @8 j$ E; i$ v
  8.   template: '<h1>自定义组件!</h1>'6 e$ j" l5 R8 h
  9. })
    , s4 G" `; k4 }" `: Q) U
  10. // 创建根实例2 w0 ?6 S& W) D4 N- m
  11. new Vue({
    - H( z9 I& c3 m) W
  12.   el: '#app'
    & w+ I8 i- k; b& {% M+ G4 `
  13. })8 p/ g/ @& A6 ~
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
. o  b' |- U7 I1 H  D
  1. <div id="app">2 r6 U1 I. l8 p0 i: g
  2.     <runoob></runoob>
    : Z6 d5 k) H- k7 z) h' J
  3. </div>. e5 p4 ^+ o  o0 h7 w

  4. & c' f8 n( s. N6 k. w& \$ }
  5. <script>; g% L& S( c3 W/ a2 v
  6. var Child = {
    $ F) ^$ u' S4 s0 s+ {
  7.   template: '<h1>自定义组件!</h1>'
      b- d5 d8 [! \
  8. }
    + S7 f7 ?! B9 V2 Z& n

  9. 1 X7 S8 z: y' `, x
  10. // 创建根实例
    ) z) ~9 a' r! \) B
  11. new Vue({
    % Q( t/ b$ v( r% x. {
  12.   el: '#app',/ o3 a1 o. c$ ]1 X) g4 j, ^
  13.   components: {
    8 V) ]  X5 U& {, l- ?9 J2 p
  14.     // <runoob> 将只在父模板可用
    + E  N- I! A6 F) @7 e3 K$ }
  15.     'runoob': Child
    2 K* x# Q- }8 V4 Q  n* l- \, Q
  16.   }6 y! Y5 m! _' O9 {
  17. }). V( p2 j$ s3 e2 Z( u
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例1 y0 q! O) p* v' A( m& I9 g+ ~" i
  1. <div id="app">, n: }8 H: n+ [
  2.     <child message="hello!"></child>
    ) m7 m+ z* X' L; L
  3. </div>2 a9 L/ a$ v9 R4 E) d" S7 F

  4. % v0 v- I" i+ x8 D
  5. <script>
    # @& ~% L: ~8 ]& Y1 m" P% j$ H
  6. // 注册6 d- b6 c9 t( z. A, P3 y( l0 ^
  7. Vue.component('child', {  v5 V7 r! @1 b' y. V; C) b
  8.   // 声明 props" D+ E5 _- P1 v( s% E
  9.   props: ['message'],
    2 c- E8 C$ A, |- U$ x, F4 v' z
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    " b, ]# G+ I, s
  11.   template: '<span>{{ message }}</span>'
    ! F, S" K6 n9 v
  12. })
    : G) Y4 c/ x/ Y# l5 ]+ e8 M
  13. // 创建根实例- x* i/ H& ]# C; h
  14. new Vue({
    1 }& `5 [1 B7 ~; B1 ]" G6 T' h
  15.   el: '#app'* h! D! @9 p, ^: j$ h
  16. }), |( z8 b. m% |/ ]% J& l
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例( F$ D  C. U6 E) T9 i2 ]
  1. <div id="app">6 X5 `* |" J: p; R0 |/ I5 [
  2.     <div>
    9 C( i6 e2 L% m2 P, ?
  3.       <input v-model="parentMsg">
    ( N* I3 s) h7 P3 [! h! M0 g
  4.       <br>" ~% F+ ?! {+ c" I6 z# ~  ]. j: z/ k2 `
  5.       <child v-bind:message="parentMsg"></child>
    3 t0 j; {( M( H
  6.     </div>
    ' ^- i. X+ i+ n- A* C+ |
  7. </div>( ]$ P7 L7 [8 J3 f# ?2 `/ L4 ~
  8. " L2 _" ~  O* u9 H4 L
  9. <script>! E, |5 `/ W6 ^; m2 e, n
  10. // 注册
    8 U+ {; X6 c4 j5 X" J9 Q& Q
  11. Vue.component('child', {4 F- e- A* x( |8 _% O9 B* G- q
  12.   // 声明 props
    ! Q9 ^, h/ v4 K1 e3 I' o
  13.   props: ['message'],
    3 m6 O3 n4 ~# g+ ?& H7 B* a1 X
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用9 I4 z% ^4 i& ]" U( d$ G: d7 m
  15.   template: '<span>{{ message }}</span>'
    4 @5 O6 ^2 T) J1 v
  16. })
    ( c; l; Z! W3 `2 h5 Q
  17. // 创建根实例3 J& p* n& n' v8 z4 }1 B' Q" \
  18. new Vue({$ q. t0 q! t  R7 G. x9 Z
  19.   el: '#app',' O5 D0 K  q( u# K
  20.   data: {7 O+ Z5 U8 ]& F3 b# `
  21.     parentMsg: '父组件内容'+ _! o# r# k/ B, x
  22.   }
      k8 r! q  z, w# M8 ~
  23. })
    $ G) z) C9 S0 Q4 V% D" u: p' e
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
4 p/ H( j  {3 d9 V9 P1 s
  1. <div id="app">
    / {4 d) Z6 K% n( E0 v* x) j
  2.     <ol>
    2 t* v" t* R$ u* o7 `
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    0 t# Z3 P, w/ A0 g
  4.       </ol>
    " f  G' w: N: O* w# N  d  |
  5. </div>
    # {2 `3 Z4 d) t( h; i: e2 X
  6. + H8 _  v' K) C) @. _* l) r
  7. <script>; q6 t& P: N  b* {' P
  8. Vue.component('todo-item', {
    % a: ?* J  _" W0 {3 A
  9.   props: ['todo'],3 `4 L5 X6 [% U$ L
  10.   template: '<li>{{ todo.text }}</li>'
    # F7 ?7 ?5 |! x
  11. })
    ( T6 l" q% h  z. [, Q5 \
  12. new Vue({; F. Y' o; ^1 l) C. H7 b
  13.   el: '#app',
    2 |& c1 A9 u: Y% I2 E7 [
  14.   data: {
      _5 X7 ^# n2 o- R. U: r
  15.     sites: [
    & ]4 s) d) ?4 A  a" ^
  16.       { text: 'Runoob' },6 o* m* j1 L. ^+ X- h: K
  17.       { text: 'Google' },
    5 \: w% U0 f4 P  H6 I9 d6 p7 K6 X
  18.       { text: 'Taobao' }: ]! v" a" _/ B% h- ^" j( A( q
  19.     ]+ W+ u$ O' W" {5 k( U; K1 m4 G
  20.   }
    1 n4 A' Y2 Q1 I0 e
  21. }). F" R( p0 v5 A/ F
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {$ g7 n2 [: G: g6 g% [* u2 J' t
  2.   props: {
    " {/ m1 f! N1 t) |5 q' E
  3.     // 基础类型检测 (`null` 意思是任何类型都可以). n+ e  ~% s+ J5 {
  4.     propA: Number,; N# N9 i9 w: t
  5.     // 多种类型
    ! C5 Q4 U( w' k' N
  6.     propB: [String, Number],$ G1 @: T( N3 W, w$ s- `
  7.     // 必传且是字符串
    9 D3 m2 Z! [/ K
  8.     propC: {
    3 {' I: O7 K: B; M4 [
  9.       type: String,
    ( w3 k# s4 T' @. c
  10.       required: true
    & ]- E2 f  D: d) J- A3 `: u
  11.     },
    7 C9 D2 o) D1 A- M% H7 T" o
  12.     // 数字,有默认值
    " S4 @( Q, a0 R8 l, Q  b
  13.     propD: {4 {2 T3 @' o) o( j2 P' p+ I0 L
  14.       type: Number,
    3 E% r8 N' p6 ~+ V6 @4 V% f  R
  15.       default: 100
    4 f! f8 W6 N; D& |( u, I
  16.     },
      @4 x- p+ `( ?; ~0 x
  17.     // 数组/对象的默认值应当由一个工厂函数返回6 H. t: D$ J( ?) v
  18.     propE: {. L8 k5 o' M3 d- M9 t2 X
  19.       type: Object,
    ! s1 v- |; n0 X0 v# ?# y4 R
  20.       default: function () {
    , h0 |+ w( j' b, {/ ?  n# J
  21.         return { message: 'hello' }
    + a3 j" {# V8 E7 p
  22.       }
    5 ?7 ~& `& k" |6 A4 e% g8 o
  23.     },
    . Y- z* F6 j1 @( X# T) Y9 A0 x
  24.     // 自定义验证函数1 t8 O2 D, \" s
  25.     propF: {
    $ R+ W% D1 V5 G! g: V
  26.       validator: function (value) {  M$ y8 _0 v% o& S
  27.         return value > 10
    + M8 g, |/ q6 m
  28.       }, n6 H9 m# _0 [& Q) p) `
  29.     }
    , u* G, c" J3 {4 T+ L: }
  30.   }
    8 s0 `9 `: }" r1 e& r( ]) ]
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array( U: ~' q, @7 e9 s; u7 |- u
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    ' K9 {" j' V# ~4 q+ g
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例3 j5 C- Y6 j0 M* B
  1. <div id="app">
    ' C6 e) H' R: D3 g  e* a2 z, u
  2.     <div id="counter-event-example">) A) q  x5 v6 m$ L# ?7 T* I  [
  3.       <p>{{ total }}</p>: O1 z* i  A! X) U6 i
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>  [: B) B% p$ S# u4 C% I# O3 s5 [1 y
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    * L  {2 t9 q! t* p" _" Y. \
  6.     </div>
    . d1 y8 e* _0 K& _  d+ ^& M2 v$ T
  7. </div>, M+ ~) p# e  f& `: z: d: E
  8. # n+ W) |4 B, i  ^
  9. <script>7 T; u5 D: b  d: t& E6 D) B( Q
  10. Vue.component('button-counter', {; j: l( \4 u% x% b; w8 W0 B
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',, c" a' j; t, v" X
  12.   data: function () {
    % I' d, ~) ?( F/ }
  13.     return {' W# m+ Y$ F/ z  Q& J. S
  14.       counter: 0
    - |; w+ [, I9 C  \" g* |
  15.     }! C( [, A& W5 n' b( c
  16.   },1 X7 d( Z4 ^, `: Q
  17.   methods: {
    . x' z7 T0 z8 d- f* k3 ~( n
  18.     incrementHandler: function () {
    $ h; N, {7 E$ p5 @% T: ^( c6 W
  19.       this.counter += 1
    5 ]9 m( |- R5 W4 }  g
  20.       this.$emit('increment')
    % E8 I0 Q% d* j& _+ l9 `' E* v
  21.     }! E2 E' g- {7 r/ L8 h- }! R
  22.   },
    & h4 g9 E% u) G' F: W+ ~, c
  23. }); }, |& m1 l( {0 O! L
  24. new Vue({
    6 b8 |( b  R2 I5 m8 c. Y
  25.   el: '#counter-event-example',3 k1 o  ~9 H$ W+ l
  26.   data: {
      _. ?$ G, @8 h# X# `0 c
  27.     total: 0
    5 R$ v- O4 S9 ?3 m7 S% Y
  28.   },
    / r7 f' l0 h& m2 D9 K* s6 @( F
  29.   methods: {9 e* F) K  @2 N0 o5 U; ?
  30.     incrementTotal: function () {
    # \. B/ W  F2 l* ]6 l
  31.       this.total += 1+ d0 }& U$ D- c1 d% n
  32.     }
    / D. E5 e2 D+ k' T! Q, B
  33.   }
    . Z1 T; r+ y: o
  34. })% i0 p4 u& q! `7 ^* r
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    * G. L0 P) {1 w2 d8 g& ?" h# @5 T
  2. Vue.component('child', {
    " X* q1 g0 D- t7 W5 g, D
  3.   // 声明 props& B; b. I" n% F* p+ F7 f
  4.   props: ['message'],; M( q9 ^& A% \8 p0 T- p) T' }
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    . I5 V4 [5 @2 q) q7 a0 I
  6.   template: '<span>{{ message }}</span>'9 s( V1 w3 H& p$ N2 w$ E
  7. })1 U+ }* \4 Y0 i' N8 j' E
  8. // 创建根实例/ o! t% a; C4 f$ j
  9. new Vue({5 i+ j! r. l6 c% `: u& o
  10.   el: '#app',
    . j+ y, k5 U; O+ O* H
  11.   data:{
    & p* B4 O- G: V/ L
  12.     message:"hello",7 o  @+ d3 ]3 g
  13.   }
    , P: q, X4 v4 R
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {% |0 S, r# {6 K) y! u6 I
  2.     incrementHandler: function (v) {
    ' f7 E3 C# U; ^, ?4 ^4 q) m6 _4 K
  3.         if(v==1){
    ( \) t3 V( o2 |4 X
  4.             this.counter -= 1
    7 E6 }0 i$ o; n( h( D. F+ V
  5.             this.$emit('increment',[1])
    2 P; `$ \+ u% X2 j6 P
  6.         }else{
      t# u: L: p) d
  7.             this.counter += 1
    5 w5 }* ~0 b2 M" K2 ?  _1 P. V
  8.             this.$emit('increment',[2])
    " T# L1 ^+ _1 ]$ Y6 h6 D: L/ b
  9.         }& r7 j; Y. y3 {% u/ e
  10.     }
    - F9 T6 }" L9 x$ n, U* v" _; H
  11. }
复制代码
% l8 m/ l, E8 [! `; z
" u8 H- p9 D: u, T. Y( d% B9 H
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则