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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15364|回复: 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,并使用它:
) u+ Q4 q+ ]- e. y9 `6 S
  1. <div id="app">
    . C8 x* O7 K1 R. U$ O6 B
  2.     <runoob></runoob>
    5 u2 Y: |2 ]7 g4 V0 H6 q
  3. </div>
    " N3 J* P; ~  A8 h0 [
  4. . X0 h+ z* y- L9 d4 D+ O6 j
  5. <script>
    3 K$ ?( f  B' T$ A0 O2 Z4 h1 K* V
  6. // 注册
    1 S7 @6 G' B5 l. c! e! J' }* ^+ W# L6 k
  7. Vue.component('runoob', {
    - i$ N+ d1 l3 k. H
  8.   template: '<h1>自定义组件!</h1>'  t' z4 n7 C( b* A
  9. })
    ; o! K' w( Y+ A' d# m
  10. // 创建根实例+ M# k& f# V2 ~+ j
  11. new Vue({
    , x  |, r7 K& I7 C- j
  12.   el: '#app'  @4 m; ]' j$ Z4 T2 U
  13. })
    6 X  V, u& F8 G! b
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

9 J" m) v& m2 h
  1. <div id="app">
    . t& z4 P; h' N
  2.     <runoob></runoob>
    - D8 ]( A7 d0 A) q6 u
  3. </div>, a' ^+ f) T& q4 z' }! h2 j
  4. : y+ h  ?: m3 @! }3 V$ h% Q
  5. <script>
    ! e  O9 r- Q* ^
  6. var Child = {3 k4 M1 g& _1 l& Y, D6 H
  7.   template: '<h1>自定义组件!</h1>'
    ! P/ A9 |& s; R& C* A
  8. }
    ' N. h1 ^' C2 a' H' y

  9. + G! y2 I5 ]8 V: D5 r/ ?
  10. // 创建根实例# u% |0 v2 k3 i% i* g
  11. new Vue({
    : |. u3 V+ N2 D' e+ ~7 K7 c  \
  12.   el: '#app',
    $ T* K; D* o" f* N: ~, V: z
  13.   components: {! r5 T3 \) l& E
  14.     // <runoob> 将只在父模板可用
    ( h9 q; \4 ]& {. ~
  15.     'runoob': Child
    7 ]( e. Z$ d# D$ z' n4 `
  16.   }( i! ]. A6 Z+ L
  17. })
    # Q# O$ J: q& I8 Z" D; d
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例" Y. F: h/ b% d# w
  1. <div id="app">
    , v1 f+ i5 Z6 |# d% T
  2.     <child message="hello!"></child>
    : L$ W" _' O( s! c) h
  3. </div>9 X( ]2 }, j3 J$ Y4 j. s% H
  4. " a1 f7 a2 e4 g- ?1 g: Z
  5. <script>* f0 W. r% u  ^7 g: f
  6. // 注册4 h/ e) g( E; F+ _# W: i" j
  7. Vue.component('child', {' i" j( ]" d6 I: N, Z
  8.   // 声明 props
    6 e) o+ B, z( ]0 e: _
  9.   props: ['message'],1 M3 f$ l5 `2 R7 G( k, f. `; E$ D3 S
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ( A/ B& \/ w) E! M  j
  11.   template: '<span>{{ message }}</span>'
    % v: e9 n- z, I, b
  12. })
    6 |9 D8 \  U7 [6 k+ R0 t5 ]8 x! A
  13. // 创建根实例
    ) L! ~0 i: c8 e: j& J
  14. new Vue({
    ( }- O+ n0 `2 ^! w& j
  15.   el: '#app'
    & r0 U0 B9 D! a4 x! T9 ~
  16. })
    4 z& q4 @( T" `1 ?) M( y
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例8 t) c+ g. F5 o7 i% p9 ]6 P
  1. <div id="app">
    8 g& ~8 l/ s9 U' F4 S' u2 z6 _
  2.     <div># S* R/ z  s' T
  3.       <input v-model="parentMsg">- X5 X: o9 Y) T" ]
  4.       <br>$ b! C% z& J0 t2 Q2 t' R* ~/ ^
  5.       <child v-bind:message="parentMsg"></child>. y, Y3 Q  \% f! U
  6.     </div>
    9 ]) r; Z; P+ g2 D( A5 s) y3 ?: l, D
  7. </div>
    . ~& p/ N' E5 z8 V& K5 y  \3 U

  8. 6 ^) p; w  r7 P
  9. <script>' [: U6 k+ W- P8 s- z, @' B' v* i) b
  10. // 注册
    9 x$ U2 R" w' i/ r1 Q
  11. Vue.component('child', {/ Q6 e8 K& n1 g9 R
  12.   // 声明 props8 ~9 o0 c- i5 ?4 l+ E4 }* u) W- V
  13.   props: ['message'],
    8 C' X; |; ^8 m- n0 j
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    5 }- B5 I3 z2 E. v/ ~: s5 {& g
  15.   template: '<span>{{ message }}</span>'0 g: |% N9 i8 g* U7 D- r
  16. }): \* d2 }, D; e% K# `
  17. // 创建根实例6 S" |* u: f) M$ m5 S' H$ z
  18. new Vue({
    * a1 P  c! _7 [, A
  19.   el: '#app',
    . z7 ]6 j6 \6 ?* K5 C6 [7 o
  20.   data: {
    3 y9 s$ l. y1 U. U$ W, e
  21.     parentMsg: '父组件内容'+ A8 K1 Z) E' L- k/ I0 P
  22.   }8 _3 [  I& c) U, s, F
  23. })" ~  x1 c' E1 ~& G
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
% M- O' [' O) e
  1. <div id="app">7 ~' [. {2 T+ ^
  2.     <ol>0 x4 l7 j9 ?6 Y$ j- R; }/ Z1 m
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>: A. U+ G' i/ a, c9 p$ e
  4.       </ol>$ p# K, e% w2 n9 B! b5 u
  5. </div>$ _0 F6 Y& g" u" ]1 F

  6. / C; Q; z+ p/ m/ e% B
  7. <script>" K6 D; ?' s. \; C: A
  8. Vue.component('todo-item', {
    ' _  Z) X7 I% B% u
  9.   props: ['todo'],
    ' |- _. J0 O4 x2 I
  10.   template: '<li>{{ todo.text }}</li>'
      V" W3 A! Y/ y$ O$ U
  11. })3 l, d2 o/ C8 a1 ?3 I: p' U% Z) O' [
  12. new Vue({( b! G5 l$ r# I4 p: [8 _
  13.   el: '#app',' f+ d# U( J; t) u, O, m6 ?6 z* Q) Q
  14.   data: {
    ) a: i; i: |% z( P- z
  15.     sites: [
    " J8 }: ~8 C$ s: ~' M$ x3 e
  16.       { text: 'Runoob' },9 B0 B3 O; h. R9 S8 U4 x; X, M7 C
  17.       { text: 'Google' },7 b6 D  D. m! _9 @: ]
  18.       { text: 'Taobao' }5 C4 y* ]1 L7 f$ a+ A3 E
  19.     ]
    - @! h7 d1 C  d$ ^# r8 d  g
  20.   }
    - f* e, s+ @  ]( f, K5 v. O' v& c
  21. })" ]0 \: z9 z) x. D8 i0 u4 m
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {( h2 U$ `- y+ h( j
  2.   props: {' C7 w/ l1 w0 |) C3 k. K: ?
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)9 T+ Q" K1 q) r5 e- J! z( f
  4.     propA: Number,+ u' H  x+ c9 Q3 k
  5.     // 多种类型
    $ z  [8 C9 R8 z
  6.     propB: [String, Number],& @1 L) g1 z, D  ~- d: `# |  m
  7.     // 必传且是字符串. ~' p% m( j9 h
  8.     propC: {& P% y2 s' }7 d8 O
  9.       type: String,
    # F3 U) V( V" j
  10.       required: true/ S" _8 M& F. y  A: {! Y. Q
  11.     },! j; S# C& W  W  q0 v8 G
  12.     // 数字,有默认值, H/ v+ J$ C, W# y& l+ ~% Z
  13.     propD: {4 _+ T# l0 e  i6 q2 h) g
  14.       type: Number,
    4 P4 n8 A# @4 r
  15.       default: 100" \$ ^# P. S! E" o" t- s
  16.     },; b: n2 m* J5 G4 v4 v
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    % C2 I. D' N. s
  18.     propE: {6 O+ K7 I  n0 o
  19.       type: Object,
    : N! W- x  e* a- P) d  B
  20.       default: function () {
    # X6 J% M) f1 s
  21.         return { message: 'hello' }# h- n0 [) R1 _, z% P
  22.       }; t/ ^5 c9 ]( y8 W6 t& V  J* n4 f- n
  23.     },$ t0 i( `/ z) S& k& b) T$ P
  24.     // 自定义验证函数
    : d' m& z' Y7 S# G  k
  25.     propF: {5 X, B3 p4 b- a! Z: I) A
  26.       validator: function (value) {6 Z1 A$ U3 }; Q' X! S' l6 L5 Y* H
  27.         return value > 105 A' W; g0 X. D& Z
  28.       }( W# i4 ]1 @, k% y1 ?' i( d1 R# B
  29.     }: ^7 o. N% g4 }; A7 B
  30.   }
    0 w: @3 A& e3 @3 c( n
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    0 c4 n3 i4 S, w$ v8 S
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件* q4 q( y( [2 ]$ L
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
* {& i) r: C2 \$ [
  1. <div id="app">
    / s  L$ l( ~, y. B  d  C9 t
  2.     <div id="counter-event-example">; I" n  ^. p; ^1 _2 U
  3.       <p>{{ total }}</p>
    2 k* [3 i8 S, B; U5 e" c- G
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    : y) D& s/ |! p5 \' |6 n( S! s
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>. V- H, ]' X9 P  G; z; Z5 B
  6.     </div>( z4 V+ m" {2 Q$ P
  7. </div>
    / L; {% f% k/ G* r  m  z8 T% k) H

  8. - ?( X* g' {) ]6 L  H
  9. <script>6 _+ d, n6 Y- \3 |$ P! |
  10. Vue.component('button-counter', {$ \$ a  H' `- A- _7 J
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    3 w1 ^9 F3 F4 P6 V4 U# \" X
  12.   data: function () {
    ; Y; U5 _: U- O" D' O) U
  13.     return {
    3 E& a: n3 {3 r- L, {
  14.       counter: 0
    6 i. F( Y( M6 a: m2 F) B/ X
  15.     }
    $ d" {" F' W4 T4 m* e+ P: r
  16.   },0 f  `) Y0 N( s( d# M/ _7 S
  17.   methods: {/ o' x# m3 G$ Q  }
  18.     incrementHandler: function () {( g) n" r, m3 A/ i
  19.       this.counter += 1
    6 x) @3 h/ D- E# k, T
  20.       this.$emit('increment')
    ' f+ A/ h0 J( k9 \5 p; t' l
  21.     }
    9 F$ L% A; y7 R
  22.   },
    # O; V, f4 Y6 I: l; O
  23. })
      e9 Q- [+ A3 Z
  24. new Vue({
    5 Z, f6 v/ `9 H7 v5 Q/ f  S3 [
  25.   el: '#counter-event-example',- u" Z8 L) T; H# u! P
  26.   data: {0 c/ o3 P/ ?" l8 A
  27.     total: 0: m1 t1 {9 ~6 q+ z# ]  L
  28.   },0 D6 o6 j) d% ]1 K' o) D3 f
  29.   methods: {- m: |! U1 j7 @) g6 M4 p
  30.     incrementTotal: function () {7 S# N( U. B1 `7 o/ N
  31.       this.total += 1
    : _( k) v* Z) u0 y' D
  32.     }
    ; P# }6 f2 p  a( ?! @& @
  33.   }% z% I* S' }. i! ]
  34. })
    + h) E0 @$ n1 \7 i; X; @* k" n& M
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    - F0 Q2 X0 e: L6 u5 A
  2. Vue.component('child', {
    3 {* d5 C: o' k# I# U
  3.   // 声明 props
    6 K3 j: E# @0 {
  4.   props: ['message'],! o: I4 J: }# I% _
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    4 v+ W% ?9 J9 L  g9 K3 R* b
  6.   template: '<span>{{ message }}</span>'
    + B) b0 R$ @3 c) w3 K
  7. })) H; Z. s$ {0 K3 f2 }( k
  8. // 创建根实例% k3 V5 e8 }; l3 D: n6 m, U' I8 \
  9. new Vue({, i* d7 r. U: n
  10.   el: '#app',
    6 b) j: x! O" H; \: u: ]
  11.   data:{
    2 l; Y* E/ k# l2 }( f
  12.     message:"hello",
    - K" f2 U6 s% m5 c
  13.   }
    7 f2 _- a" n! X3 \: t: j! T( r; s
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    3 b+ E* R: c4 o6 }
  2.     incrementHandler: function (v) {* f$ r$ s- e' r
  3.         if(v==1){7 x( J2 w- V" G
  4.             this.counter -= 1. j5 q; |( K. L
  5.             this.$emit('increment',[1])
    ( |% g5 R* W- W! C3 p
  6.         }else{9 H7 t" }# n: q) a8 {) p- X$ F
  7.             this.counter += 17 Z6 S9 k% |: S  c0 a! B" x
  8.             this.$emit('increment',[2])# l7 ~( o/ |6 k7 h, H
  9.         }. C8 W7 d9 k. S, b. i& c
  10.     }
    ! D8 f1 f4 M/ {7 a5 \" M1 h( B
  11. }
复制代码

3 t' z0 t- }0 _. Y  H. Y6 W7 b4 H3 G" m
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-16 22:10 , Processed in 0.091504 second(s), 24 queries .

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