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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

  @& \2 Q) v# F# l# I
  1. <div id="app">% G( b) B; D# p! s8 J
  2.     <runoob></runoob>
    % H& }- b: a3 r) K; Y: u, d
  3. </div>" m" Y7 J3 \3 ^6 r) A4 t5 z

  4. * H) C( m( n( f( q
  5. <script># k, F+ ]9 C" o; K, ~+ ?& \
  6. // 注册: K6 |( @6 a1 q2 ~. B( F4 w7 @
  7. Vue.component('runoob', {7 S  x% |1 `1 L+ K& k4 [
  8.   template: '<h1>自定义组件!</h1>'1 Z  K) `$ B/ |3 _
  9. }), P7 G2 r" U; a2 C% a0 v& H
  10. // 创建根实例
      ?. S8 ~# \; ?/ g: E. A
  11. new Vue({( Y5 M9 |; b$ B: P
  12.   el: '#app'* L5 _  r4 Y5 S3 Q- e
  13. })/ W( D8 O- A% [3 \/ ~  J* G
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
# Y/ z7 f. d$ a
  1. <div id="app">- h: m4 y& O" A
  2.     <runoob></runoob>& J/ k. w! C+ O3 `+ q
  3. </div>
    7 i" {4 u( ]4 ?( v1 w2 p

  4. 4 v7 ?) N# i3 p8 Z- B" ]0 G7 y
  5. <script>9 g9 w/ Z/ K. [; G. M# a6 H
  6. var Child = {
    9 L/ K1 |/ |  t7 a3 n
  7.   template: '<h1>自定义组件!</h1>'" h$ U6 M& J; K# ~% [5 n% q& _) z
  8. }
    $ n6 [" q! O. Z3 I, X
  9. 2 o# [$ G& W' |+ x6 P, ?
  10. // 创建根实例
    ! p) _9 P8 [9 b2 g7 X( x3 \8 m0 D
  11. new Vue({( u" \  ^) ~( g  [. ?, {* e
  12.   el: '#app',
    # M8 X$ ]% e: }4 @
  13.   components: {5 B9 t  ?# [% g( {- O6 r& V8 T
  14.     // <runoob> 将只在父模板可用
    ; }8 F6 _0 Y, a5 e6 o* z, v
  15.     'runoob': Child
    9 w4 [# {5 h9 P: M, }
  16.   }" i/ M, I" x; |" u" L, V
  17. })
    6 @5 }( a4 y& M
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例7 F& B; |* g- B! N2 ^
  1. <div id="app">
    9 T$ U0 r0 \, A  e* F' a
  2.     <child message="hello!"></child>" E+ w# A- o/ d+ X* t3 g
  3. </div>
    - a! v  g) L: v" r6 n! X5 ]
  4. ' r1 X+ b  W/ o) |) h9 ]
  5. <script>
    " s, o& _5 v0 W& o( H; T
  6. // 注册
    - o2 H2 W7 f! P% i' ?# W
  7. Vue.component('child', {; p. m8 K! L2 b. w! K8 I+ B0 q
  8.   // 声明 props
    1 ^, V: {( q) E4 y0 K  O- Y
  9.   props: ['message'],
    2 T- n$ v3 p) R: J/ C
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    4 w% D4 z( V) B9 J/ P
  11.   template: '<span>{{ message }}</span>'
    & s. Y8 C+ r! v" L% ^, p
  12. })
    1 k2 }0 a, \: v" u/ ?6 q( R0 L4 k
  13. // 创建根实例' v& o, J, J) t. ]8 S5 c8 d# O
  14. new Vue({- h$ t# |( @4 p8 Z; t1 F# p
  15.   el: '#app'  C  t3 c5 j8 s
  16. })
    7 S/ _' u1 o  B( \# _
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例; v% w1 _# R5 U& o/ g
  1. <div id="app">/ P" q4 M, B3 N; v! T
  2.     <div>
      b) C* A. n' r% {3 Z9 T. _
  3.       <input v-model="parentMsg">
    ; Z0 t" G* w  }0 h- j
  4.       <br>
    3 O. f* G! ^8 a6 ]: J! I
  5.       <child v-bind:message="parentMsg"></child>
      x" {* G9 h* Z, `6 [
  6.     </div>
    " X$ w; w2 Y2 T; V: z1 r
  7. </div># e0 f+ j3 ]/ l$ Z+ \
  8. . T0 u! A4 ~! f/ t2 ^
  9. <script>4 ~8 f& I& R" L$ t' r0 ^3 l% J9 C% a0 B
  10. // 注册& y7 Q6 j; h. q7 J( R0 n3 g
  11. Vue.component('child', {( Y. F) Z* g8 x! m7 j7 b' ~) v- u
  12.   // 声明 props" A7 c4 r: ?6 \/ i$ c$ w6 P
  13.   props: ['message'],
    0 G& l1 t. p4 `9 }
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    0 b, `& p/ x9 U
  15.   template: '<span>{{ message }}</span>'5 X6 T& R; }& A. {" ^7 A& E
  16. })
    4 {) C5 I" l8 Q& A
  17. // 创建根实例, h% R. ^# H) q) V% s6 u
  18. new Vue({
    3 ?; F- V- A7 T5 M
  19.   el: '#app',' i: ~, T) f( t
  20.   data: {0 r" j, A7 ^: {1 Y
  21.     parentMsg: '父组件内容'" c) _( C2 a& ]3 q. n
  22.   }
    3 V! w1 Z$ ~* |8 D8 D: y
  23. })! {/ T. ?+ o. g' e" c
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
) b6 A) |! I2 p) N; l& L8 e) p! g
  1. <div id="app">
    % ~. C& g7 i0 e0 m7 |) f/ F% e+ I$ s
  2.     <ol># w6 [5 K; Z/ M2 K2 Q
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>9 O& c9 e1 C2 k% _
  4.       </ol>
    % w# X0 k/ C! |  p
  5. </div>8 I/ U3 H  s: ~" F9 W
  6. # X; [: F2 q" B; J  |# T
  7. <script>
    , |3 P0 @; `. R( d* r  L
  8. Vue.component('todo-item', {
    ' \1 D, H7 y; c/ H6 V3 n3 @. \7 S* h
  9.   props: ['todo'],+ h3 e% [1 ~3 x8 _; w, s
  10.   template: '<li>{{ todo.text }}</li>'
    / Y7 w- |6 k6 G" k
  11. })
    0 ~! l8 ?. z0 P$ ^4 i: n% S/ f
  12. new Vue({- `+ k( e  R3 p7 c+ j
  13.   el: '#app',0 z0 b  M+ D$ a7 V( y
  14.   data: {
    " T! t/ k& _/ C
  15.     sites: [* [, Y. w0 X; I/ M
  16.       { text: 'Runoob' },5 D. `! s- \! [  x& J: R
  17.       { text: 'Google' },- _5 R+ m4 @- O2 |
  18.       { text: 'Taobao' }/ L# j' Y$ L+ c# V. B8 R6 d
  19.     ]7 K3 A9 }6 [2 n9 A9 g
  20.   }
    1 `; J7 ?; C* R2 Z
  21. })8 G1 t0 d# R2 s+ N
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    , ~" d" n/ E( N4 A! J% o" a# ]
  2.   props: {6 C. M0 T4 r, ]  l, V3 V9 H! F
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)9 S* b  b9 `8 X' F  c3 ~, Y
  4.     propA: Number,
    2 q& K0 |% h' y. ^3 q9 ~
  5.     // 多种类型9 Y3 [( M. H* m1 l3 k
  6.     propB: [String, Number],
    2 w4 R$ z) r5 `) o3 h
  7.     // 必传且是字符串2 E5 I3 L4 ~' _5 s  A
  8.     propC: {
    + Y8 G( z$ l* d  J
  9.       type: String,
    # z) w, n& Q) d! t4 q
  10.       required: true
    8 W0 _' c) G8 Y* i# O% q7 {
  11.     },* D" R7 K! m9 B: P: @
  12.     // 数字,有默认值' O3 q& e, u9 Z; B- D3 W! J8 E) Z2 }
  13.     propD: {8 {# K+ k3 L" M4 i: C: }8 H* B
  14.       type: Number,
    * R# t, c# H& s
  15.       default: 100
    $ Z; C5 G1 G2 K7 x$ T
  16.     },
    6 }  o  M; l+ n' V& k
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    / M/ Y7 J+ f$ @: K0 K( ^
  18.     propE: {  @2 V7 j( U) z6 }
  19.       type: Object,% S' a" ^" m; c, Z( n$ X  F: x
  20.       default: function () {$ e6 _% y4 X7 j
  21.         return { message: 'hello' }
    4 C* ?8 p: Q0 h5 W
  22.       }
    9 W$ s" u9 Z. K; q1 }$ }8 `/ ~
  23.     },9 ]" w& d# [* a- c& j& b( ?
  24.     // 自定义验证函数0 m; H. t& ~5 \7 X
  25.     propF: {
    : L  ~! a" K! H
  26.       validator: function (value) {
    + ?' @' J5 \; ]' }
  27.         return value > 10* ~/ Q7 [2 x: `7 Q+ j$ c
  28.       }
    ( Q7 D6 B. O* {
  29.     }
    4 X2 `9 b. A2 P  b- K& r
  30.   }$ E: c$ M# {. g, l- [1 q2 Z& r$ S
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    0 r3 V7 R# u) B  |7 \/ C
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件& _$ Y% r" Y! ?4 q; Y
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
5 \/ q. g, c/ M) o2 o1 q6 Q6 t* L
  1. <div id="app">0 e0 f. h% L5 n% `
  2.     <div id="counter-event-example">
    - E+ b/ I; j, e2 x
  3.       <p>{{ total }}</p>6 f' g5 A5 p! F7 V
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
      D+ d7 W8 w$ ?! L
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    ! j( E9 V  H1 R$ k. C7 R
  6.     </div>( |' }0 c3 |6 s. X) s( B- n$ P. w
  7. </div>
    ) V' E: h& w) X$ d
  8.   ^  v9 M* L7 \/ }" ^
  9. <script>
    3 z7 ]$ \) l0 Z" u' H! @
  10. Vue.component('button-counter', {
    / ]: l7 z( u2 o; a9 y
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',' |' u  {2 Q- t8 E6 [
  12.   data: function () {
    6 ^5 V; O4 p) B5 P; j
  13.     return {. p& ]; p1 R5 u# f' z8 u0 w
  14.       counter: 0+ v6 s: _* u: N0 K3 k' F1 M/ _0 [
  15.     }
    1 y5 t& v' k- M' o  k
  16.   },9 x& g& @! N0 s0 I9 w6 H; o
  17.   methods: {
    0 m) R' [& K1 m5 M8 k& D
  18.     incrementHandler: function () {
    ' w7 h0 ?* }7 q2 p7 y
  19.       this.counter += 1; k( m1 w/ C( ~% [9 C& X9 r8 O
  20.       this.$emit('increment'). R/ M- M; @0 I+ q' b9 v
  21.     }  C4 r; h' o9 G  K
  22.   },' |8 Z. J. L( y6 u
  23. })
    # u3 |3 ^( H0 d
  24. new Vue({
    - g+ J% |$ V- ?- k9 i* o. z- ~
  25.   el: '#counter-event-example',) G1 y' W9 p% j5 [% f% }6 ?
  26.   data: {8 ?  t! l$ t$ C
  27.     total: 0% F& E$ P9 g& k0 P
  28.   },
    / f" C* L% o2 q# x( Q; A2 ]
  29.   methods: {
    8 c# b- {! T5 W8 ]3 Q9 s
  30.     incrementTotal: function () {
    ( ^5 T. S/ I: n. I; D, h, d7 y# k- z
  31.       this.total += 11 [( `7 [8 \0 f! v" o3 A! o
  32.     }5 `4 W% b0 V# u/ \. C) _. l$ x, r
  33.   }
    ! n4 t# F+ H  l
  34. })" \& f( A; i( H$ _" W
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    . @8 j4 r' N5 n1 V, [" t4 D0 Q$ I
  2. Vue.component('child', {
    5 E; a( q8 ?* p9 A! O4 W
  3.   // 声明 props  M% J% K; `9 _. k8 ]6 }6 [3 `6 x
  4.   props: ['message'],5 S  Q7 N1 d6 ]+ A- T
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用! S! B6 M" }1 F0 N9 w0 i
  6.   template: '<span>{{ message }}</span>'
    0 W) Q3 g. f: G4 s  n6 o3 R
  7. })
    / j* l6 s, `+ }/ M5 U' d# j' \
  8. // 创建根实例; I  A" [7 p" F" D
  9. new Vue({
    + o7 H' R6 V+ V3 ^; d1 ?) Q6 B
  10.   el: '#app',
    1 y- }# w/ \  j5 s
  11.   data:{
    ; w5 w' p( X& q+ }
  12.     message:"hello",4 D9 W3 N" Y. r9 C; o& L/ C
  13.   }
    $ i! s* _( l; y, V) `- O# E
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    / |! w+ R% X2 V  h' S( v2 T
  2.     incrementHandler: function (v) {
    - U6 @) v4 f7 F* e: m
  3.         if(v==1){# {6 f. D/ o- F# ^
  4.             this.counter -= 1/ w# V% K; p2 \
  5.             this.$emit('increment',[1])( j3 b; c0 P+ g' O; k# Z3 n
  6.         }else{) ^$ \* i) e- A+ P9 ~
  7.             this.counter += 1/ J6 ~/ m. x6 d$ F+ r' `& w
  8.             this.$emit('increment',[2])3 k1 r- s. Y2 r
  9.         }$ u) i% q9 O" W1 S
  10.     }9 j) o: C/ j- ?* u& V2 f& a
  11. }
复制代码
; a7 s! {- C+ ^# g: a

3 |: M; M7 n5 \
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-20 00:59 , Processed in 0.116451 second(s), 22 queries .

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