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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

( G. E6 s. C  D5 Z
  1. <div id="app">
    ' `0 y. z( P0 k! P! t6 ?
  2.     <runoob></runoob>/ V! U# `1 A% Q  @8 `
  3. </div>" p  S/ ]" Y+ h' m+ }8 q, T4 i

  4. + I) s1 P( c9 F% m! I
  5. <script>
    6 J6 L6 X" K# H- n/ c
  6. // 注册
    - F7 y, a  D5 z, d. a
  7. Vue.component('runoob', {
    / n) q; s0 F0 M# h/ j
  8.   template: '<h1>自定义组件!</h1>'. H' t2 H2 N3 ]6 j3 Y# _
  9. })
    ( J3 q7 e5 D$ i9 n
  10. // 创建根实例
    ) h, e- h' E. v) S9 v3 Y1 Y
  11. new Vue({2 E5 H( G  Z4 q0 k
  12.   el: '#app'
    : A1 l) Y" g$ W- D9 w( o1 L3 Q* X. e2 M
  13. })( z- V" _/ s, U) [- Z/ R* I
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
; P; K" T! I% M. r9 \5 R# Q
  1. <div id="app">+ |0 c3 a8 z+ r# [5 m8 b$ Y
  2.     <runoob></runoob>
    2 F  w& G. a1 A- o9 x
  3. </div>
    0 Z5 i: \! }5 m8 G1 |. J

  4. 9 _; n# |" d/ c4 e) L/ j# c. E. |- c" {
  5. <script>
    , ~' z9 c' |4 Z7 O1 h, F. @
  6. var Child = {
    1 b( L- t- I: o& r
  7.   template: '<h1>自定义组件!</h1>'( A0 e1 ]) M$ O% h( o9 Z( r9 G
  8. }  m. r6 W5 ~8 l- J" S

  9. + c+ f* S( r! y3 |% z8 K) A4 x
  10. // 创建根实例
    * K5 S6 d7 ]7 ]( ^9 r
  11. new Vue({
    ) Q, J6 @) e& A3 x
  12.   el: '#app',
    ) C4 }5 I0 r: A$ n0 ?
  13.   components: {
    + P7 t( L7 C/ \9 K. n
  14.     // <runoob> 将只在父模板可用
      \* I, m, w1 a1 z2 ], m
  15.     'runoob': Child
      ^6 s! e2 \' U/ R
  16.   }. }( F; s! Q' y9 M) P
  17. })
    , C3 k8 p+ t  @2 l" L" d. x& O
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例- [+ D8 _% @! p3 E' a
  1. <div id="app">; ~6 q$ Z* ~$ D
  2.     <child message="hello!"></child>
    * Y6 [, h4 }+ N
  3. </div>
    4 N1 I- G0 t/ F9 [: {- ]  J6 j+ C
  4. 7 S& W3 `* i( m7 }$ a
  5. <script>
    3 f8 e. M  B! o: @+ w! T
  6. // 注册1 \5 O2 }$ O* B0 q! G1 I+ L
  7. Vue.component('child', {
    7 l7 p  s# d) @, p0 n% c
  8.   // 声明 props9 w7 I2 \4 P% t' \9 f! V- g1 C9 l
  9.   props: ['message'],
    ' W4 x) R* r% T9 s; i$ D3 i7 E
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
      n/ V5 o9 C. m* V$ S/ d
  11.   template: '<span>{{ message }}</span>'8 S6 u+ T. P! H
  12. })2 j& ^4 m  E# ]7 x. _. O0 y1 S" e1 p
  13. // 创建根实例2 o, z0 o9 v) J: f6 s* R
  14. new Vue({
    ' H" v; x! Q+ F
  15.   el: '#app'
    9 S6 A6 J1 j* a% w
  16. })
    , ~& R, {- J0 I+ ?- b1 [- j
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
  \# ?2 g6 Y2 e5 M
  1. <div id="app">
    $ j% y- x: A6 N
  2.     <div>
    2 t9 L. V) r' |5 _6 ]+ c1 W# f9 q
  3.       <input v-model="parentMsg">: a, K) r3 i* ^2 T' [
  4.       <br>: D. B# @. \: K: e* ]
  5.       <child v-bind:message="parentMsg"></child>* \! W. q' E+ w8 c5 U
  6.     </div>$ E) e* T9 R+ a: m0 P( B! |
  7. </div>
    5 X* E- P2 B4 e# H0 E
  8. 4 j0 }2 j: e+ z" c! R0 Z
  9. <script>
    8 L9 {- _9 H% Z; ]$ |
  10. // 注册6 Z) h1 r" i- I) X$ N/ I1 A
  11. Vue.component('child', {0 ~2 y8 O/ j2 [, w9 ^: L
  12.   // 声明 props
    7 ^! u1 c* _3 y# r
  13.   props: ['message'],! }- s7 C- P1 T* H
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    - [" s' m1 n/ }1 Q' i; s
  15.   template: '<span>{{ message }}</span>'
    $ V1 N' r; A: {" o1 e8 b
  16. })
    - R7 p0 `9 \% e6 B
  17. // 创建根实例# z4 U: t1 w: m
  18. new Vue({
    ; b2 }# u- ]$ t) T
  19.   el: '#app',! [1 I" M$ S3 B8 w) d; N
  20.   data: {5 ^2 O$ j5 S8 b% @" V: d
  21.     parentMsg: '父组件内容'
    " x" P6 s9 d: O) c( V( n1 A% }
  22.   }; Q% n: d, P3 n- Y& ?
  23. })
    / g4 M. Z% B# k
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例+ c4 e) u+ |/ v0 \$ b( `/ ?. s
  1. <div id="app">9 K4 t. R( U/ ?- v6 Q, \( U
  2.     <ol>
    3 x2 K$ G7 _/ n4 }+ p4 M; V7 r
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>9 u4 V9 Q5 y; K
  4.       </ol>
    / `0 V9 a# a6 N# \1 U% F  S  E
  5. </div>7 k  F5 f2 |/ g8 V, v8 s8 K

  6. + D/ r1 C1 D# K$ d
  7. <script>
    $ m2 z. y; E. M$ W
  8. Vue.component('todo-item', {
    ' i! u  B- U, q# r
  9.   props: ['todo'],
    8 A" _) a3 A2 U9 X% _% {5 k
  10.   template: '<li>{{ todo.text }}</li>'4 Y& r4 @3 ]# O# T0 f
  11. })( s$ A$ q7 V% _: A* h2 d; I
  12. new Vue({
    2 D. @/ ]6 ?) I  C. Z. j
  13.   el: '#app',- A% d3 n6 y. r. n7 G1 X- |
  14.   data: {
    ' `% ?* i5 V. c5 e! q
  15.     sites: [$ B2 i8 H9 S+ K. H2 v) ?
  16.       { text: 'Runoob' },: n7 ^/ y4 |. @9 B
  17.       { text: 'Google' },
    ( y+ B5 \9 Z4 M4 W) D8 y
  18.       { text: 'Taobao' }  i& g2 T( T/ a8 f7 d& y
  19.     ]
    ; @% c: y6 x  p; J# R: |6 d. W! U2 T
  20.   }& s- s5 g6 n1 |7 ~' E3 V8 f+ H
  21. })
    & s' P9 Y- j2 q+ m
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    % A& B# O4 n; q' C
  2.   props: {1 M1 C* j1 z/ h, Q0 _1 I! L
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)# f' d& r2 N5 a4 ]* g
  4.     propA: Number,
    1 G' d- v7 M; E
  5.     // 多种类型( ?9 |& Z: }  \# l
  6.     propB: [String, Number],# ~$ e4 J$ J* b' c
  7.     // 必传且是字符串
    . i: G8 t/ B; ^/ {
  8.     propC: {
    , H! J( ^& d& f3 {7 w! t
  9.       type: String,- y6 M) r1 U5 o$ I9 f2 p
  10.       required: true
    6 n& y" n& }  ^% i
  11.     },
    % {$ g' N5 S. K' |+ Y
  12.     // 数字,有默认值; C' r2 o0 }$ C$ W# C# d
  13.     propD: {
    4 j3 j6 N. g$ O4 \6 Q
  14.       type: Number,( Y0 J. _. t) _% h( {
  15.       default: 100
    0 u1 ?; M" ^+ ]1 a9 L2 n; N3 q
  16.     },
    # M) c+ ^9 Y; f
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    " H" d% H- [$ L6 [6 Y
  18.     propE: {6 p2 w  d5 C7 O: l7 a
  19.       type: Object,; u" C: \0 z  r! D
  20.       default: function () {8 C4 k0 g& X/ z: W2 h9 g# C
  21.         return { message: 'hello' }
    . s3 X; [) @0 Z5 S; i
  22.       }
    ! c/ S# g2 J, j* k( `" r
  23.     },
    4 h3 B" h& R$ X
  24.     // 自定义验证函数
    : {- k9 t* D. y
  25.     propF: {7 E. q% D2 F/ e. ]6 V
  26.       validator: function (value) {. V- G+ I% e' c9 z6 @
  27.         return value > 105 U0 C) W. P( `; S5 U. b& \( N
  28.       }
    3 K; J# H) J7 t  m
  29.     }
    4 l' _" W( _+ n/ ]# a
  30.   }
    , h; \  d0 ~8 a3 R6 T
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array- G. R2 J# o  `
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    ( f: B7 }, E2 B5 i5 v
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
! S9 g, T; b0 z9 r1 \; l! S
  1. <div id="app">
    , _1 k$ G# ^! Z" }! k9 B% v/ Q
  2.     <div id="counter-event-example">
    ' X. D5 A1 B$ I: {' `0 k: m* ?4 g
  3.       <p>{{ total }}</p>& w- S9 L' e3 l6 [* p
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    3 C8 L+ k8 p7 W. j$ n! a( U5 f/ ^* t
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    ' z7 Z* c' V# b
  6.     </div>
    ; {6 V& n, E% O" c) K$ E
  7. </div>
    0 p; w% j0 d: ?4 G  J  x
  8. ! M8 w( q0 A  w6 i' X/ Q3 I% o1 L, K
  9. <script>  S5 R: A2 D4 i6 l- S- l5 b6 p
  10. Vue.component('button-counter', {
    5 E  U" C; g; z$ D( O
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',3 V4 P% @2 X& w3 L
  12.   data: function () {+ o" \+ Z2 D# A& D# x
  13.     return {
    / f8 m$ l% n+ M9 P/ U0 m
  14.       counter: 09 Z# s$ T  Q; i5 J3 Z" U; I
  15.     }
    1 A; B+ g7 E+ s/ i) a. M
  16.   },
    ; T# V$ {. s! G/ P) ~! u! q/ n
  17.   methods: {
    $ c: c- D0 N  z8 T' w
  18.     incrementHandler: function () {! j0 Y4 y  h- B6 {! x/ V
  19.       this.counter += 1; n, k' S  k7 {* R, ^% Q5 e- H
  20.       this.$emit('increment')
    % q6 I. D4 E# O; t; N  E! F
  21.     }% a5 E4 T+ |' \" G* d8 Y1 F  R
  22.   },  l" m8 K! p4 c
  23. })  E, C) G! v. D# I4 i8 i! o+ v% U
  24. new Vue({
    , O0 g/ m+ Q  A/ U3 H0 r9 a, ^
  25.   el: '#counter-event-example',9 c' k  f/ @: k, `! y
  26.   data: {( N/ d/ ~. e( o) n: W8 A
  27.     total: 0
    $ T  h  U' o; c6 r: o
  28.   }," m6 k% u; B2 s
  29.   methods: {+ v' U0 i) h, x  Y& m
  30.     incrementTotal: function () {' c7 _1 Z) L$ y0 T& p
  31.       this.total += 1
    . d; W( _  V1 q5 r2 r( n
  32.     }" m* Q; P+ j+ B
  33.   }  x6 [* q# z4 F0 _9 `
  34. })
    ( J5 V3 a9 L4 [. s8 q
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    + c) j/ v: j$ D. h  W' t. B" r, k
  2. Vue.component('child', {
    0 V9 W. k: E5 Q+ q& s1 y* R
  3.   // 声明 props
    4 l3 ~; J8 M  g7 \* B) S
  4.   props: ['message'],  s- K+ O0 l' ^, S$ i: y. e  n. L
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用( G/ \" s2 _% d. |! n& W, w! D& Q/ o
  6.   template: '<span>{{ message }}</span>'
    0 ]; l. G. J: v5 J) n1 o0 i  b) a
  7. })0 v: X' c2 q# u2 U7 b
  8. // 创建根实例% C* Z1 ?* x- c% q/ ?- Y
  9. new Vue({
    6 p3 ~( ~- E/ m) _$ G: d
  10.   el: '#app',5 y. F$ d2 C% X( J
  11.   data:{& v2 y+ u. I8 V5 e( a2 M6 K
  12.     message:"hello",3 W/ u' A4 D7 r; l
  13.   }- x' Z! j. h% L. U! G- M
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    , D3 {- n. H# y& [4 n  ?$ C+ p- m
  2.     incrementHandler: function (v) {
    " m/ e* s1 ^. E7 ~8 R/ y3 _: d
  3.         if(v==1){. \9 y$ s) A( o; k# W. N/ D" k
  4.             this.counter -= 1
    ( c3 i; e* v3 _$ L: w
  5.             this.$emit('increment',[1])7 ~6 j; @4 Y. D% R0 r3 e
  6.         }else{
    . w* T# D- K) d; r+ q! @1 g" L. G0 P
  7.             this.counter += 1
    $ D  O" W0 j; A" W
  8.             this.$emit('increment',[2])) i" D# g! i% P. w' Y
  9.         }1 K8 i1 Z7 V* N+ b; }. R
  10.     }
    # N' ~- ?9 k& a/ I" O
  11. }
复制代码
3 O- \/ R8 O# X$ e
( l: ]/ s/ u% I- Y
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-11-1 07:45 , Processed in 0.145131 second(s), 24 queries .

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