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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

6 y( v; u0 w  c9 c" j
  1. <div id="app">
    % h$ a. _5 x8 Y: i4 C
  2.     <runoob></runoob>$ d" ?  I! f: R0 r* {3 m
  3. </div>( I: j8 f1 S- v* j: h3 F1 Z& z: M

  4. 5 [2 S  ~* e+ w  C! N4 [4 g; r
  5. <script>
    + p0 T# Y: t. M
  6. // 注册
    5 \7 d, x2 Q- R  Z, Q8 f
  7. Vue.component('runoob', {
    2 }& N2 A9 V6 p; d4 F# B9 S8 }
  8.   template: '<h1>自定义组件!</h1>'$ {* b" ?) W) C% Y( l" o$ R
  9. })* e: P: E9 E( F) m; n0 v
  10. // 创建根实例
    ; t. `6 S/ C/ f4 [
  11. new Vue({, R: s! A( ~6 N& A- N  r$ Q
  12.   el: '#app'
    . H. i' i, _: E7 w
  13. })* g' l2 V; a. {4 H
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
6 f2 W; e; r8 q; R. e2 x! R
  1. <div id="app">0 t( U+ v4 S' `& Y$ k
  2.     <runoob></runoob>) S6 y6 }- N+ y4 r/ O
  3. </div>4 F$ E, A* f0 t; \$ s+ R

  4. * Y1 I! e6 F# W* \, B8 _
  5. <script>
    ! P7 \3 R9 O; R' g. |
  6. var Child = {# l: h, Q" @$ G6 b! G# {+ M
  7.   template: '<h1>自定义组件!</h1>'! |* b7 E, j3 m( h0 S4 n0 }$ {8 n
  8. }1 A; l6 q, t7 i; T# x
  9. 3 {3 V) @; c4 L
  10. // 创建根实例
    - x" P; }) `3 r) h
  11. new Vue({
    ) [* \. e; T. P3 v# G6 L, D
  12.   el: '#app',, a/ b. P* ~- `. N  Z; f3 b9 c; O  ]
  13.   components: {
    & g6 D( ?: |- S
  14.     // <runoob> 将只在父模板可用
    - F1 @0 u' B! O$ ^8 S1 |
  15.     'runoob': Child
    ; y8 d/ J* r: }1 E$ H2 M
  16.   }0 k  {, O) ]: n1 n1 f. ^
  17. })/ @( Y( u7 w' F8 i
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
3 p% ~+ X/ x* N/ N, w; D' X
  1. <div id="app">
    3 |; F5 \7 Z! ^! O* p7 M% I
  2.     <child message="hello!"></child>
    9 ?1 M* ]0 f' R7 ~8 [+ W& L
  3. </div>& Q1 k' u2 a3 \1 D& s* \

  4. 1 f8 J4 G( t1 G+ v. R3 _$ K
  5. <script>
    ; I6 L2 N8 G& F, U, H3 z
  6. // 注册4 ]) `0 U, Y( O) f
  7. Vue.component('child', {( Y" v) q& H( T! X! c/ w( M6 Y
  8.   // 声明 props, m; P. ^) D1 \1 j. d! \
  9.   props: ['message'],
    , e$ O/ W( v& @" I
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    % W! X7 t2 i) k: a& O
  11.   template: '<span>{{ message }}</span>'8 s* w9 k1 d$ P
  12. })! t8 j* D* u: A/ N# x& k
  13. // 创建根实例0 Y3 r$ R- v- w* B% p
  14. new Vue({
    $ l$ x3 P% `! c/ W) O
  15.   el: '#app'
      N9 U# p/ L  [' b: a
  16. })
    9 `# U; X' a" H% I5 [; f
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例% ~; v4 ^* b6 _+ D
  1. <div id="app">
    0 a% _% q5 T- b" Q9 \1 ?2 K/ q
  2.     <div>  j% Q* a" ?6 f- q" Z3 Q: O
  3.       <input v-model="parentMsg">5 \5 O- C7 j  M  z, n; Z; I0 G
  4.       <br>; x9 h7 d( P/ g0 p! ?
  5.       <child v-bind:message="parentMsg"></child>) g6 W0 O6 w1 w% h
  6.     </div>
    4 z' q3 z& g5 H( W
  7. </div>
    % [* J: z$ p8 u* _& A9 H

  8. 7 t% _' P  e- j* }9 a
  9. <script>9 E  G/ e- G' j' b
  10. // 注册
    1 I7 k( H% n6 {( ?2 U" v* c# r
  11. Vue.component('child', {# d, @9 h6 |1 k, O; V9 U
  12.   // 声明 props/ @5 M4 ~& @! x0 w
  13.   props: ['message'],
    ( h3 k! ]9 ]. R$ K
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用+ _4 b4 c2 E% m
  15.   template: '<span>{{ message }}</span>'* I8 L, s+ p+ R; F9 w7 \0 J
  16. })8 y' _7 Z0 o/ ~) X% O9 R7 P; o
  17. // 创建根实例
      X. c& f5 `8 F2 {  z$ F
  18. new Vue({9 X' [  D, D4 N2 X! B8 b9 J
  19.   el: '#app',
    ' {; \3 J% A7 ]: Q. W
  20.   data: {) N! Z- J2 c- W% _# r8 i
  21.     parentMsg: '父组件内容'& D# E/ o3 K2 N" Q
  22.   }: C' m; y/ j. S6 h
  23. })% K: A8 ^% G  c& Z8 U7 B$ f) M
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
' h% Q' q9 E3 ~- b/ [9 `: D
  1. <div id="app">
    ; F! ?: _8 P: q/ Z
  2.     <ol>, A) ~% V5 J4 s% D9 w
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    5 G" T3 C: ?- {* I: k* {$ W
  4.       </ol>
    - A0 M  R9 j( d2 f# m5 z
  5. </div>
    6 D, }8 i3 ^0 g* z( Z
  6. ( ?0 J1 L8 V8 g$ B+ a* D
  7. <script>
    5 F. _1 [6 |5 f, O5 q" A5 s" [
  8. Vue.component('todo-item', {# k% ]4 O$ i3 {* ]
  9.   props: ['todo'],$ d0 x2 J+ t! D5 u) v: Y% D, d( x
  10.   template: '<li>{{ todo.text }}</li>'
    - N, [4 e5 ~0 O9 A6 K2 G
  11. })
    ) V$ u8 M' q$ R$ R& p" F" h
  12. new Vue({
    1 U$ L8 S8 k0 n) w7 x
  13.   el: '#app',% Z6 z* {# }( d" s
  14.   data: {1 G  o9 F0 W  u2 v- V5 n0 `* _! ?
  15.     sites: [
    ' ~1 g. ~9 a0 n: Q; V! i
  16.       { text: 'Runoob' },
    # U& j0 C- B: ]& w8 ?, J5 a. G# E( k- e
  17.       { text: 'Google' },; k( ?' N) [: |7 p7 z
  18.       { text: 'Taobao' }2 U  H: E; t( v2 [
  19.     ]
    " S% \! L( P" I$ l8 T6 k5 y  `
  20.   }
    8 {- C: F& D+ h+ @  O. m( x
  21. })
    " l0 T4 h; B  _( v
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {3 ^: `. J7 n& p, z7 m6 g) ~
  2.   props: {
    ( ^2 a5 |0 P  F; l9 e. d* a$ Q
  3.     // 基础类型检测 (`null` 意思是任何类型都可以). R  j9 {6 z0 n! x: ]& U9 |6 f
  4.     propA: Number,
    - Z1 a! j; T4 |8 A" S6 Q) T# K9 ]
  5.     // 多种类型! d! \" _4 x# p; A, M, z
  6.     propB: [String, Number],7 U9 Y; Q: q# q/ R  k
  7.     // 必传且是字符串) w: ~+ z4 ]5 }3 o
  8.     propC: {
    4 J" r' ]) D1 ]5 \1 l4 ^- v
  9.       type: String,
    ; E+ ~9 O# {: H4 [$ S# e& B6 f0 R
  10.       required: true: q& c, N: x) @/ W, b0 g
  11.     },
    - @9 F3 n) D+ q
  12.     // 数字,有默认值
    6 A' _, O/ S; b  R( L3 y/ t
  13.     propD: {
    6 D5 s2 N8 d& o" |
  14.       type: Number,. ~1 I0 N$ A- y
  15.       default: 100$ Z+ G  Y2 `* s7 \- a" Y) j
  16.     },: M# g: G, o: G" \& y+ g8 U+ d  N; T6 T
  17.     // 数组/对象的默认值应当由一个工厂函数返回; m" h( D1 i9 D8 L6 C
  18.     propE: {6 f% {1 ^( Z3 u4 k' i0 s1 R
  19.       type: Object,
    1 G, Z+ t5 A" V; {" i( `
  20.       default: function () {
    ! G) i/ r( s+ Y* P
  21.         return { message: 'hello' }- ~2 C& p/ n2 E/ s/ h# `/ X
  22.       }
    & ]& x: @- U- }9 Q! S
  23.     },+ l. Q* c5 p3 w. p  q& N% W
  24.     // 自定义验证函数
    : P& I/ {5 K) `" n$ O  x
  25.     propF: {
    9 ^; a# M: |: g% B+ ?, V$ u1 a8 ~) m
  26.       validator: function (value) {
    % Q; f- F. E  v
  27.         return value > 10
    # h( D6 e+ C1 s/ R- n. r
  28.       }. u+ l2 A* L, c  I8 r( f  P
  29.     }6 G& \% y7 k4 t$ L. n+ g
  30.   }
    ! |7 t+ k5 C) k$ _' E$ d( P9 A
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    ( ~8 a" Q. Y1 Y% y4 b5 I! h' N
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    7 P1 Y- J! V& V! P1 x" ]
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例. n& u4 ~/ F( a- L
  1. <div id="app">
    1 D9 Y/ M7 f; _& Y" x
  2.     <div id="counter-event-example">! D' ?1 k9 u. A# ]4 E
  3.       <p>{{ total }}</p>
    3 D! H- U) k0 c7 B' A
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    % l7 o7 T6 G! u& a  F/ I" {6 k
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    ) I; j8 q4 P/ K3 E  l! J
  6.     </div>! Y# g( e" N" e% O, k6 J, p
  7. </div>" M) O/ H8 l1 v2 T; h2 y

  8. # D  T3 ~5 y: n6 F; b& f
  9. <script>
    ! S+ Y& W) N5 G& l5 s
  10. Vue.component('button-counter', {
    . X; h$ B7 p3 L/ ]
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',% y  m3 |4 A) P( z
  12.   data: function () {5 b+ {2 V) ]. b2 q' a! [
  13.     return {
    8 {$ Z& p; o: V; O
  14.       counter: 0
    / |+ E1 e. h9 h1 ]0 T
  15.     }
    / }4 ?1 }6 }& R, e) R
  16.   },
    5 y) `1 `  h" Y! e/ O6 E
  17.   methods: {# n* }$ }4 D0 n4 ^
  18.     incrementHandler: function () {9 W  g% f7 H3 f
  19.       this.counter += 1
    1 f4 N( r7 _* b9 {
  20.       this.$emit('increment')( f3 l) a2 [" j$ }4 c
  21.     }
    8 O( j* f. b0 B9 f
  22.   },& u* U4 y; ~" T1 Z0 l9 }4 q0 u
  23. })% B: p! X! h2 D
  24. new Vue({
    8 M& g4 r6 y. S  Q
  25.   el: '#counter-event-example',0 D7 |$ Q3 w$ q
  26.   data: {+ Q8 _0 C- b& j$ O3 y4 {* c
  27.     total: 03 }" N# z8 R; p- u$ m) Q8 t9 E: B
  28.   },
    3 K/ Y. M$ P1 T2 v5 u% \% ?
  29.   methods: {
    , j% Q) Y* j& k
  30.     incrementTotal: function () {7 Y$ Q5 }( v. V& N
  31.       this.total += 1, G. @! e  T( S* ?9 k3 C
  32.     }
    4 @8 ]% R' {) Z
  33.   }/ f0 ]% t% C6 M" H% r3 O0 i# ]
  34. })
    ( P0 a5 i7 l" G9 k# x$ Y
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    - G* @2 m8 g$ f# t8 L. S' m
  2. Vue.component('child', {) n+ _5 P; G) Y+ {: E& {6 ^7 K
  3.   // 声明 props( S7 j# \" P3 D
  4.   props: ['message'],
    " `+ o( z; c8 V
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用7 [) k8 G6 z; F; q2 i5 I% C
  6.   template: '<span>{{ message }}</span>'
    2 w! t! T+ V4 s7 ?- a3 m# _' X
  7. })
    8 x2 x9 |1 w  S9 n) m
  8. // 创建根实例
    3 p! p9 n: r) _  n) f2 a, ~; ^: q
  9. new Vue({
    ; c3 b. T" o' m+ N! M8 ?
  10.   el: '#app',
    5 @' L) K9 U5 G# q9 ~( g$ x6 v
  11.   data:{8 a2 L: H+ k, G( F. }) O
  12.     message:"hello",3 Y* w: d0 P+ g' l* N0 a# i
  13.   }
      p5 ~* d9 f8 Y3 E/ |/ r
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {, m+ ^* W( F9 x: W
  2.     incrementHandler: function (v) {4 j5 o# n& O- O2 m; N" p4 s) k  `6 W
  3.         if(v==1){
    4 |  r9 ?# J% O9 I. A9 D$ B6 o
  4.             this.counter -= 19 |/ Z' h/ w3 t; I% l. Z
  5.             this.$emit('increment',[1])
    0 h3 M# j1 }, Z. b$ h
  6.         }else{
    & R# g* u# c: h; B( s
  7.             this.counter += 1
    4 ?6 y& ]3 K* g# |" y9 j
  8.             this.$emit('increment',[2])
    ! S( r1 h5 N7 n) N2 S+ W0 |# n
  9.         }% s! T) a2 l1 e" a
  10.     }; f9 E- r" m, C0 R7 K1 D7 j! p. e" u
  11. }
复制代码
6 L7 P5 B4 X4 i+ @$ n4 L

, t$ P0 x+ f, I- ~/ E* Q
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-6-30 00:05 , Processed in 0.131257 second(s), 24 queries .

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