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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 10844|回复: 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,并使用它:
3 Z; ^4 U0 B  n: i( d
  1. <div id="app">
    + [4 H  D4 ?2 z& J) t" T
  2.     <runoob></runoob>
    / L# j- }2 ]0 r- N4 C/ `
  3. </div>( d( M* l# z7 o; z0 K
  4. 4 _/ F9 }5 C% B6 n* B5 {( N7 l
  5. <script>
      g2 I5 p7 D/ T
  6. // 注册: T8 D, |# Z0 w! h3 f
  7. Vue.component('runoob', {9 f: K- c& P8 H" ?& V
  8.   template: '<h1>自定义组件!</h1>'9 `% }" e" R2 D: F% l
  9. })
    & `' j  f8 V: \, L9 O( T' C
  10. // 创建根实例
    / w9 @  k6 K1 f4 _& Q3 Z
  11. new Vue({
    ! I4 @. [$ p- v
  12.   el: '#app'  k; w2 r/ q% S, f. A
  13. })+ G& e9 r. `" `5 ?; n# b8 _4 f4 r7 v
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
8 d) z% B, _  D" `3 x) O! g
  1. <div id="app">* s' X* ]8 s1 V: b( o" b
  2.     <runoob></runoob>
    $ o: P+ e( B8 |5 u
  3. </div>
    " o6 e+ [# w2 ^6 d" I& Y" n

  4. ! ?3 f7 ^' o1 V" O) z1 c
  5. <script>
    7 R2 [* \! a& @5 f$ x
  6. var Child = {$ Q+ f0 S/ k0 K. i- f( k
  7.   template: '<h1>自定义组件!</h1>'
    # P9 E$ [+ T1 S
  8. }
    8 u+ `; |* t: m! Q8 O

  9. - K" L7 g  E5 O! ?
  10. // 创建根实例
    ) X$ r6 i  \8 u  Z4 Z: V
  11. new Vue({
    " }2 C" m$ ]8 K/ g9 N" C
  12.   el: '#app',
    - e7 X2 @6 L: e8 j8 H4 J3 ^
  13.   components: {& d) _" \4 _8 m
  14.     // <runoob> 将只在父模板可用; {/ }6 r0 n/ W/ H& R- H( H( K
  15.     'runoob': Child9 a% A! M4 z8 y1 o# j
  16.   }
    * z) b, ^; D( r8 i
  17. })
    / d, G/ Q& _6 u, F9 w) \
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例4 k/ b7 }: P6 N% c% K' J( L
  1. <div id="app">
    & c0 Z- Q; k2 b! j$ `: n
  2.     <child message="hello!"></child>
    $ f4 d8 H' N" E/ D" Q2 i6 k
  3. </div>$ S; M& t! G, W/ `( z
  4. 4 Q& t# Y: c( m+ O" X4 I
  5. <script>
    $ W8 a+ S0 G5 n8 o
  6. // 注册
    " b- T4 Z. t! S/ n# J2 B1 m
  7. Vue.component('child', {
    # Q- o9 |' x+ V4 k
  8.   // 声明 props) K. _, L. D" x' k3 V! z; f8 Y: W
  9.   props: ['message'],
    1 \" j3 @% Y' l, S7 J, ]  F% b
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ( z+ |* a4 Q! A* J: e
  11.   template: '<span>{{ message }}</span>'! B2 e+ `$ X* |
  12. })
    0 V' }- l/ l8 l3 J! X) m$ q/ F9 T
  13. // 创建根实例* H* ]7 n; ~2 d2 p" w) }( J
  14. new Vue({
    2 \9 i: w  X. e" F4 E
  15.   el: '#app'
    $ U3 S5 ?; I1 K/ y+ b
  16. })
    ! p: @: i& q# s9 \* H
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
/ r! y2 x% p8 _7 e4 L5 s( [! R
  1. <div id="app">7 L6 T1 A: W% J4 Y1 K; `6 b
  2.     <div>
    / J* T& ^7 w4 ]2 n. {9 y
  3.       <input v-model="parentMsg">
      g. `. ]( Z. U
  4.       <br>
    7 a) A% M, b! }2 c3 A; s6 S4 C* T" x/ r
  5.       <child v-bind:message="parentMsg"></child>: g) g  r! p4 O, G8 c( x
  6.     </div>
    6 O3 r) ?! c! |, ?2 @
  7. </div>
    8 @3 y4 o  Y2 A- I4 |

  8.   e& K1 n) N6 a$ B' L% Y5 M2 a+ J% b
  9. <script>0 t" {0 J, M! s3 f& ~5 u# J- A
  10. // 注册9 s- F' c# L4 j* e7 Q+ V2 n& K
  11. Vue.component('child', {
    8 h$ [6 c  [9 Z7 j* U, Y
  12.   // 声明 props' u6 o' i* y* q: N1 T
  13.   props: ['message'],# ]# _' P+ G5 K/ j+ Q4 f. F2 D
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用( X2 [& D  A$ y0 U
  15.   template: '<span>{{ message }}</span>', e# z1 q6 K- C: e  Y. V
  16. })2 j2 G8 D- D; h: }7 y6 A, g
  17. // 创建根实例
    + @0 n4 Z# R6 K/ M* j: b
  18. new Vue({: }9 t! P. w. F) m5 Z  L) _2 O
  19.   el: '#app',, t( n4 P* U$ t/ B
  20.   data: {
    2 {- i: ~% J$ S' a1 F0 @4 y! d
  21.     parentMsg: '父组件内容'' g2 w% {! U& v$ s: b
  22.   }1 S/ F0 x7 x1 w! i  W: d/ p
  23. })
    9 I( }) a4 ~6 C" |
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例2 ]- |8 V; ~; a: Y+ z$ B7 K! t$ K
  1. <div id="app">
    & S- V. \. ?8 x, s6 \
  2.     <ol>
    5 M( \- ~* t( ?$ k* q
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    $ j$ v, v) r2 z% E( c6 H. L
  4.       </ol>* M9 `7 q  F; k. ~
  5. </div>
    ; d3 z3 L6 _, x
  6. 7 u% w5 x$ d7 ?; ?7 ~" R; g! S5 I
  7. <script>! K2 W9 z+ s0 B" ^2 G4 ~9 f' L3 q
  8. Vue.component('todo-item', {$ F9 P5 ]5 v; g/ L: n
  9.   props: ['todo'],2 e) [! e, {8 X  h  a6 k4 y
  10.   template: '<li>{{ todo.text }}</li>'% v, r  ~0 v: w+ f
  11. })
    : t8 z( u( F9 J; ]# p. i
  12. new Vue({: e+ @0 ~1 x& J0 V4 O- ], j! P
  13.   el: '#app',# X) f! i; q6 ~
  14.   data: {: N3 @6 {$ H( r2 l# e
  15.     sites: [& T' M0 f/ @% F- G8 y7 f1 B" k
  16.       { text: 'Runoob' },
    $ N  W8 v$ t: m, O
  17.       { text: 'Google' },
    8 F! O- s! r, q  s# e7 ?4 R3 L/ m, ^
  18.       { text: 'Taobao' }; F) r# T  O; m" l
  19.     ]2 S5 M5 v5 ?2 S7 L5 ^$ \  N
  20.   }1 J1 d% x( F$ d9 u' v
  21. })
    : ]& {$ r% B- n! q# K3 ^( U
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {6 F/ X* A1 ]; I
  2.   props: {9 ]( r3 T; t" N) _1 y5 a" J
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    ; L+ }; C0 \/ I" d( j
  4.     propA: Number,, V# _2 _' ^2 A6 Q) k  W
  5.     // 多种类型
    * V0 f& P" O' e2 k" j+ F, j% z6 L
  6.     propB: [String, Number],
    . ?2 [9 O/ [: o0 F* `% u
  7.     // 必传且是字符串
    + C9 E# k# I- |9 O7 z
  8.     propC: {9 E) e: m; B+ d* l: L; e/ a
  9.       type: String,+ V# [* }5 R, f; ^; J: Z9 n
  10.       required: true* d8 N6 p! t6 c( z2 r9 `
  11.     },: B5 l4 s. w. e
  12.     // 数字,有默认值' F( _5 e6 p/ c
  13.     propD: {* S7 Z( Z$ {; E0 A! N
  14.       type: Number,
    % A  M- x& j- F& g5 r. J
  15.       default: 100
    5 J9 c1 G. f3 M% J1 T& }, z0 G
  16.     },
    6 X* x7 j+ I! m
  17.     // 数组/对象的默认值应当由一个工厂函数返回1 `% H* v. M, G' Y7 p
  18.     propE: {8 Z8 a  [! w; C  C$ K7 m
  19.       type: Object,/ T  t0 f0 d0 ~4 I" O* ^
  20.       default: function () {
    2 c1 ^/ V2 y1 H+ B% n
  21.         return { message: 'hello' }
    8 ^5 ^, O$ L. k& D4 ~
  22.       }0 K) t4 ^5 {/ f9 }; Z  P( A/ m: {0 B
  23.     },5 E) e7 g+ y. X/ b1 D2 V" u
  24.     // 自定义验证函数9 q9 \0 O. `3 E5 E1 m  ^+ I
  25.     propF: {
    $ N8 J. Y" S, o% e
  26.       validator: function (value) {- o" K  G  S! d/ v5 o/ N5 |7 @
  27.         return value > 10
    " B7 {. u3 c$ O5 \$ Y' \$ ^. b
  28.       }: P7 K5 S' F% ?) F/ |) v1 \$ A
  29.     }
    % T, F- b& U3 f/ m! s0 V
  30.   }& Q3 H$ x2 B9 r/ ^2 O
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array8 ~6 t4 r: s# j9 F( B/ Z
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
      w* E! Y  X- ]
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例! R: r% W' c; g9 }: h1 E  n, u/ O+ V
  1. <div id="app">
    ; _( z3 X# t) `
  2.     <div id="counter-event-example">
    - ]5 V- S; H0 k
  3.       <p>{{ total }}</p>
    2 Z# W7 k, d! B) ]  \
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    - B" ]9 q0 J$ H4 P7 Z' Y! d
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>! [7 x+ h/ a8 O+ ~& F& ]+ k
  6.     </div>& i" T, d( T  Z2 R5 g6 y5 s
  7. </div>
    ( {' B1 q) z# \
  8. % k. I4 i/ U( C/ w8 ]  E
  9. <script>
    0 A6 F- {, J2 Z
  10. Vue.component('button-counter', {; e  U/ y& d9 X) v' ]$ Z$ C; |
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',+ Q$ N4 x4 j/ d  ~6 u% [
  12.   data: function () {$ R* j" |, ?3 ?& |  f
  13.     return {5 x! w& \: H' }0 b( A9 ~& x" Y
  14.       counter: 0" k. g/ e# y$ H6 g
  15.     }) `" B! C) M' L5 H  ~/ a$ c
  16.   },/ l2 `3 o8 T. ~( @
  17.   methods: {, r4 p: s, R0 \4 X8 E: ^7 ~0 g' b  q
  18.     incrementHandler: function () {
    3 a9 P) i, @2 Q
  19.       this.counter += 1
    2 @" m" v- t& s" i! k7 L
  20.       this.$emit('increment')7 s9 k6 m; v' u( N" z- b" x5 i
  21.     }
    + H) U1 ]( z( V; [, f6 N
  22.   },4 @" r& y2 b% F5 S
  23. })1 L. _2 @5 ]+ y) I, g* Q
  24. new Vue({" l4 O. i) n8 y( f  ~8 _2 X
  25.   el: '#counter-event-example',' I9 m2 ]' W2 x: \1 I" y2 k
  26.   data: {6 G5 T1 Y( z6 P" W* J. U
  27.     total: 03 w' X4 y0 h8 ~3 e
  28.   },5 f, Q) A' C+ |4 {3 z% T+ w
  29.   methods: {
    5 l, F: O  r4 H% o5 {' T( t+ E! U) F4 Q
  30.     incrementTotal: function () {
    9 a" E: y+ |  o4 W! J! g% M, g' Q
  31.       this.total += 1
    - P' @& j' f. s& U& @8 h) E
  32.     }* f3 V! B- ]/ d0 x" [
  33.   }* P+ K/ }  i1 N" t% k
  34. })
    3 x1 x1 w: M9 n6 v. e/ q
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    " n( V' x+ K: b5 |% w" j
  2. Vue.component('child', {- c* s, h7 F, ~4 I* ~
  3.   // 声明 props
    : a, Q+ R& j7 C! n
  4.   props: ['message'],
    ' s0 x' X. y0 W; L0 v
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用! Y" N1 s! T/ X- I; H' W
  6.   template: '<span>{{ message }}</span>'
    ( d0 y" ^# v" w4 b0 n) J! f: b
  7. })! q$ h) ~" O/ M" ]$ e& J
  8. // 创建根实例
    : o5 X$ {, Y- {0 P# ]
  9. new Vue({4 w% n5 R8 c, F
  10.   el: '#app',
    1 v! C' `3 G: Y
  11.   data:{* r# \# }' T4 I) [+ r( @0 [) K2 H) q
  12.     message:"hello",2 S- }$ @% E0 @5 t1 U  q
  13.   }; \. S9 B& }3 ~  N- G
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {* e$ M) ]; w2 H9 x, p* K
  2.     incrementHandler: function (v) {
    % I- J7 h; S1 V
  3.         if(v==1){
    5 U9 `# G2 x$ ]9 m. X# ]. K
  4.             this.counter -= 19 z1 H4 X% F' j0 g# r
  5.             this.$emit('increment',[1])
    9 s* d8 }: f" J6 j4 I
  6.         }else{
    * z/ f; p* w) t0 x- q# Z; Y
  7.             this.counter += 1# C1 j" I5 Y! j9 Z) y$ [( W
  8.             this.$emit('increment',[2])- G" b$ x' Z7 \/ s( B
  9.         }/ G! a/ V% T, o2 Q2 I% o4 B' q
  10.     }- d7 B: n7 M. v8 \7 I) N
  11. }
复制代码

0 o3 J/ y; U6 D  W( `" N- w/ ^/ J: `
& \3 X; J6 k. v/ d; ^
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-4 20:43 , Processed in 0.125128 second(s), 22 queries .

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