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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

& N0 T9 ^: j+ {) J! j" _
  1. <div id="app">
    1 r3 Q' C( I, U' }! F; ~4 w; ?
  2.     <runoob></runoob>
    4 q+ z, s0 S0 K- d1 I( l3 [1 `
  3. </div>' T+ N* `% h" H# `

  4. 1 S1 q: N! _& i! i
  5. <script>! w( m7 I/ P) a: h" m+ ~0 \: @% R& @. T5 [
  6. // 注册6 F3 H' w7 R! y' W/ s2 u
  7. Vue.component('runoob', {; X, m* g3 T* N6 x
  8.   template: '<h1>自定义组件!</h1>'
    0 |' Q0 z& O% B' {$ z" ^0 ]6 o6 X
  9. })
    8 n/ m0 B+ q- N2 R
  10. // 创建根实例- b) c! l* L/ I7 w
  11. new Vue({! _( Y2 E5 i5 \6 W  q8 C. ]" F
  12.   el: '#app'  z! N$ l; K* ]. d, n( V6 |0 V
  13. })
    : O- ^5 v8 w8 h" ?" w
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

* }. _% T& \; G4 n; U9 h$ {
  1. <div id="app">. k0 N+ {3 n3 D, d) p5 ^
  2.     <runoob></runoob>0 ]; r  w3 T- B( l* w1 d/ s! m
  3. </div>9 g  w" \/ m  e9 a2 D
  4. ! V- T/ A/ K4 o7 J* ?
  5. <script>; T! g4 I- W- U) w7 B8 C; j2 Z) Q
  6. var Child = {
    ; q0 u! A& m' z% S
  7.   template: '<h1>自定义组件!</h1>'
    5 ^' D/ Z% G9 Z5 R  U0 _
  8. }
    * t9 q" X& O$ O0 V( Q7 c/ M0 T
  9. " Z6 y2 x. `  V4 K8 z1 Z0 }! @
  10. // 创建根实例+ G. T5 w/ S; G& u* i
  11. new Vue({4 K; o$ d! I7 `4 }
  12.   el: '#app',! M- d# |9 c8 s( Z: t
  13.   components: {6 i: I. ]6 F# S  D" Q. S. D6 V) [
  14.     // <runoob> 将只在父模板可用# K6 [* m1 f: |7 `; P' I+ z
  15.     'runoob': Child
    2 X/ M; W2 o' L' J" u) E5 }- e
  16.   }' ^2 @" U# G7 s7 _8 c
  17. })
    2 t( v6 |+ o& Q* W5 x4 J
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例5 x' s2 i( a6 M$ L
  1. <div id="app">1 A' G, c1 l6 y% I3 o
  2.     <child message="hello!"></child>
    2 {: F5 O; H7 H( H6 P. r
  3. </div>
    , {/ Z1 _5 P! n& q' Y4 P" C# F
  4. 7 L+ p1 A  V9 J5 Z: z
  5. <script>
    $ N! ~1 P+ J" Z! r
  6. // 注册; h. T! x( S) H. z$ u. G( {# i
  7. Vue.component('child', {
    5 U9 A# J' a7 W, Z( P6 q
  8.   // 声明 props! I& T3 U$ A" Q# ~0 d
  9.   props: ['message'],
    ( X# A1 K! m$ l; J- F* e/ b
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用, t% r9 S! P" h# B1 Y+ z
  11.   template: '<span>{{ message }}</span>'2 v* v9 g0 R, l& {, }4 }
  12. })
    " i* f7 I- e; h  Z8 e3 C
  13. // 创建根实例
    6 `% I* }+ {1 P: w
  14. new Vue({
    " P/ d% k1 V2 i' H
  15.   el: '#app'/ \" g( e6 n6 G6 q1 s. n
  16. })4 ]. A4 v& m! c$ G8 S
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例" H6 \, F, X* n  j$ y: U$ t
  1. <div id="app">
    + g, B+ x+ E; ?
  2.     <div>
    % F7 p1 l. K4 p5 l* y
  3.       <input v-model="parentMsg">8 r/ Q+ A$ A. |$ D! I8 w  w/ Z
  4.       <br>. H8 X# l* N2 i
  5.       <child v-bind:message="parentMsg"></child>
    * y$ o5 `; D1 y+ W  W
  6.     </div>
    4 x) w; j. u: M0 C5 i6 G' U
  7. </div>1 B3 }# Z0 R3 G8 N4 |1 E' I

  8. " I9 t' V& H# q" E
  9. <script>
    - C2 t9 q4 Q/ b% Z' p
  10. // 注册3 t3 ^/ R+ C0 Z
  11. Vue.component('child', {
    ; [, r% r& {* I1 E/ V
  12.   // 声明 props
    : d4 X; V/ W6 a6 a. i" v) e
  13.   props: ['message'],
    6 \. x" ]! H1 k7 N& ^, d- U  U
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    , x: e  S4 J2 |6 H* k* X" P* M9 y
  15.   template: '<span>{{ message }}</span>'
    9 Z( \1 i, ^! `0 V7 [; F1 {! d2 n
  16. }); R9 F  C6 u9 Q' x7 F
  17. // 创建根实例* k- H: s* }+ Z& M  P
  18. new Vue({1 q2 w3 G$ n3 M$ Q" w$ A3 {8 g
  19.   el: '#app',
    ; C! Y; M1 Z( D. s8 C. F
  20.   data: {
    % p% c: [7 v- H" F6 F
  21.     parentMsg: '父组件内容'- M+ Z8 b& _( d0 `3 R( V; ]
  22.   }
    1 v; W: _! X1 V* N
  23. })4 X$ z9 F- U5 v
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
( T7 f0 ]6 q3 H/ e" D
  1. <div id="app">& e' f, ~( g& |- t7 U8 n" b* V
  2.     <ol>, u+ d, B+ [5 f7 X, j
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>7 Y3 `! s5 Q& P
  4.       </ol>) m6 Z. t  F6 h4 X
  5. </div>
    # y- l& B( V8 g) `" U
  6. ( `- w: ~4 d( q. Y- I) Q1 V9 |
  7. <script>
    ' @7 U  `/ H0 U  \- J4 w3 b
  8. Vue.component('todo-item', {
    ! X4 ~4 ?1 [, t% ]
  9.   props: ['todo'],3 w$ }, U& e) ^* O1 M: P8 h( U
  10.   template: '<li>{{ todo.text }}</li>'
    ( s9 b/ J5 ~+ G
  11. })! [5 N  p- P# _5 O0 U
  12. new Vue({
    ) H2 V+ i: D8 ]# b
  13.   el: '#app',
    3 Z5 B4 z  k' \
  14.   data: {
    % b9 t8 k' h+ v, [* g. v2 q( n
  15.     sites: [3 u6 v3 H( s8 b$ i8 q7 |4 q
  16.       { text: 'Runoob' },; a2 a* ]% L1 `
  17.       { text: 'Google' },
    ' p' a5 K( Y! {& j6 k" u) R, j3 b
  18.       { text: 'Taobao' }
    & _5 r2 v  p  i: s' l
  19.     ]
    4 P  B( T: {8 k' V2 B
  20.   }
    : [$ V& [8 k7 I) |, c6 u9 K
  21. })8 G: J" `& f' D8 s' N7 |* h1 i- Z
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    8 }6 |% W$ J/ G1 g- G
  2.   props: {
    & u3 K* y* f& P* q& |9 i
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)/ T0 q' {; n# j% l; I
  4.     propA: Number,
    # J2 E! Z: s' K: {% F
  5.     // 多种类型( q' k% Y' `0 X
  6.     propB: [String, Number],
    3 j4 U9 _4 x, f( A& M4 P% W: u5 Y
  7.     // 必传且是字符串) z% U7 |2 E# M0 h1 s
  8.     propC: {
    * L  Q; g+ |- F$ j& `  |
  9.       type: String,' y& `! x3 z) R' |
  10.       required: true
    3 \  z$ G5 g; `" c9 R
  11.     },& p3 ]. w) A. H1 ]; q
  12.     // 数字,有默认值
    + p5 r& K9 S9 O* F
  13.     propD: {
    / |; Q0 x, P0 X5 u8 x. O- K. W
  14.       type: Number,) L9 M4 y7 o! B  W
  15.       default: 100* G' D% x& Z& ^8 m, l! }
  16.     },
    # p3 B" \7 y4 Q: r; t% ^
  17.     // 数组/对象的默认值应当由一个工厂函数返回3 Q/ g$ q3 |' ^7 L( j2 L- l
  18.     propE: {2 m' B  S6 J' ^
  19.       type: Object,. {1 F0 w3 U5 ]9 G$ \& N% K
  20.       default: function () {& F) d! P% a( N# j  J/ z7 g4 m0 L8 X
  21.         return { message: 'hello' }
    ! r! ^4 S' Q+ j/ X: J! _
  22.       }  k" v- e; c5 h/ p( b+ G  J2 m
  23.     },1 f( D( Q8 p# G( r6 R6 Y6 v8 V- Q
  24.     // 自定义验证函数* t3 d: A5 P) e. {
  25.     propF: {3 y' k, s( k; n; H5 F5 t
  26.       validator: function (value) {, i3 p5 n7 @; p% I
  27.         return value > 10
    * e9 k  Y4 a1 i. i: k
  28.       }
      K6 r+ g# V- K: }  k. X
  29.     }
      G* Z7 W& m+ b- M! Q1 E5 N) Y8 P
  30.   }8 L2 ?+ t: e2 u% J' R
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    " g- b1 R- x) r3 Y9 ?3 Z1 U
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件1 v0 J3 z1 s; h0 D8 X
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例+ V4 [3 s; O1 S) h+ R& r% I: f7 H
  1. <div id="app">" M: I& w( M. P7 m
  2.     <div id="counter-event-example">
    4 U7 d5 n6 O' \6 F, T( `, L* q
  3.       <p>{{ total }}</p>% J+ a: h" j( j/ D! j! d- a; E
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    ) v  o0 ?: l$ T, a2 x+ x( d- X
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    $ h! s# d1 `- K
  6.     </div>: @4 @6 \  D5 X9 W) N) x7 K5 h
  7. </div>1 v% u8 h/ y, \5 x: }2 F# J# d" _, l

  8. 7 o8 e  \, H2 T+ _- L7 T* Y# _* g- _
  9. <script>
    2 L9 M% O$ Y- ?: O5 J7 x
  10. Vue.component('button-counter', {
      n* f  \8 c3 W$ d/ g+ x' _
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    ! k) k% U- y9 I  Z
  12.   data: function () {
    0 ]2 a: h# X1 q" \+ |
  13.     return {
    7 s6 e2 L; a: U4 {/ ^* U& F& P
  14.       counter: 0! S7 I% l: X& i) j5 R3 E7 H
  15.     }! I( O% w* y" u' i3 p; D8 Z) L
  16.   },
    & G2 S. e. c9 c
  17.   methods: {
    0 O) E" R5 Q% ~: w! N3 t
  18.     incrementHandler: function () {% C" u3 t! A2 T8 S* ]* ~- N8 m
  19.       this.counter += 1
    + [( b4 J. u( z. R' I7 |$ \& R
  20.       this.$emit('increment')2 o1 {7 Q) E# V0 ^+ O. }4 U: j
  21.     }9 n' H" D' ~0 O" M7 y; L! y
  22.   },9 X+ z. |4 p- ^: J" i1 i
  23. })
    2 A5 K0 A% B9 p
  24. new Vue({6 V7 D+ {  n" D& h6 R
  25.   el: '#counter-event-example',
    3 d/ u- R* b; D
  26.   data: {
    , q2 D* g: N0 c/ W6 c
  27.     total: 0
    " F1 d  c( j" Z. d* N' B  f
  28.   },
    7 E) F% f8 D/ ~7 n
  29.   methods: {
    " e/ n% k0 @6 f3 |7 s* D
  30.     incrementTotal: function () {
    0 r7 z7 }# T; T
  31.       this.total += 1
    ! n! Z  z1 F) b1 ^7 Z6 s
  32.     }* V7 I0 B7 `0 C2 ]4 E
  33.   }$ l' J% e, @* D" ?
  34. })' e9 `6 M# b( ]5 I( @/ f4 a9 F
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册8 y9 H; i( @( @4 ]2 G: _
  2. Vue.component('child', {/ q% j3 R: h" V: {2 X0 ^9 b/ X
  3.   // 声明 props4 }( p1 H) x  i6 p" H
  4.   props: ['message'],) R3 S# f; A2 B5 E. Y4 r  P& N
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ; \# H: @3 b2 l; G% ~
  6.   template: '<span>{{ message }}</span>'
    . Q: y& I# v9 \' j- \# N" J
  7. })4 ^9 G, N" j, o2 x2 G
  8. // 创建根实例
      j$ q  c: E- X8 J. s
  9. new Vue({
      b' _! Q/ q' ^) z5 ?
  10.   el: '#app',
    + r  e4 F2 X* O2 n: M
  11.   data:{
    9 F; n& M9 ^6 f2 z9 G+ K0 A! w
  12.     message:"hello",1 {6 o& H( g% \# E0 `& l8 ?4 T1 j9 V- y# _
  13.   }/ P: g' m) p9 V7 e0 H7 e
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    9 Q$ F: W' T* O) W7 y7 m# X5 T
  2.     incrementHandler: function (v) {/ c# b3 f' I6 u
  3.         if(v==1){
    9 R$ X. F4 S! y7 K! c
  4.             this.counter -= 1
    1 D; q9 X5 L" B3 m' Z1 L: A: ?
  5.             this.$emit('increment',[1])
    7 _# v7 h/ g* O3 a% F; a+ x/ @* M
  6.         }else{- S( U4 ?7 F, ~  [
  7.             this.counter += 12 g+ l" L4 M9 B" V. f
  8.             this.$emit('increment',[2])
    + D# Z3 w$ N( Z
  9.         }1 l$ t6 Q. N" o+ `5 f- }
  10.     }
    - ?* y# R( B+ B8 }
  11. }
复制代码
) u- \5 r; p7 E  v# k" c

4 a' ]" {. [5 Q* o
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 16:33 , Processed in 0.056891 second(s), 23 queries .

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