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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

- S# J( y, n- y8 B! C
  1. <div id="app">6 \0 o8 x, N/ ?$ u! ]$ |3 W/ b5 e' b: o3 k
  2.     <runoob></runoob>6 k+ o1 G" n  R" U* n, @( T7 j
  3. </div>
    # y. \5 l( {# w7 {/ @6 L

  4. + U7 Y3 S2 F" S6 }) ]" N( l2 n7 @& ~
  5. <script>
    + o3 f1 F( F3 v7 h3 ~* n3 K
  6. // 注册3 S: E' @$ Z- x8 N
  7. Vue.component('runoob', {
    $ W, z6 P+ v2 |+ o( h
  8.   template: '<h1>自定义组件!</h1>'
    1 [9 v, _0 q# h- z# k% `
  9. })
    6 d$ T( C; S( I% l4 ]2 ]
  10. // 创建根实例+ ]$ V+ Z4 U  [# U3 Z1 \
  11. new Vue({- k8 z1 Y9 e+ m7 e# J% _. Y
  12.   el: '#app'
    . F5 ~) S# s1 [
  13. })  \# {3 @, w# I' v* h! _% e) q
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

8 `0 x; k# s. w- v. I, S, U
  1. <div id="app">
    # N# S& S3 f* b' r' V
  2.     <runoob></runoob>
    # C. z  W0 e, J# u" d7 Y
  3. </div>
    + b' a8 L) N' R6 U
  4. 1 O5 ~$ G* ?2 W/ Q6 }. Z+ I9 n' [; T
  5. <script>) K. b6 q- z, k5 o8 O
  6. var Child = {
      p. |( X' M. W/ y( u& n, T5 n! {- V* X% D
  7.   template: '<h1>自定义组件!</h1>'
    % {) p. r& U* P& |( D  |. k
  8. }; N, u/ p5 }" t4 F

  9. ) \  V! e8 \+ f6 s0 c( e9 n* Y
  10. // 创建根实例2 z( ]$ K$ u: U' p0 Q8 Z& h2 |1 [
  11. new Vue({
    ' x6 f8 {* I. K, D& |
  12.   el: '#app',( O( K: ~, T( e1 b9 j% E1 l+ I, P' h
  13.   components: {
    , f. M& |. P  W0 `
  14.     // <runoob> 将只在父模板可用
    ) i  n- k0 e: v
  15.     'runoob': Child
    9 Z4 b( U7 D5 Q2 [: {  l* z/ H
  16.   }
    : O* W3 }& G7 H* \& D
  17. })
    4 R6 t7 r$ D+ C0 E9 R6 G8 t& Y
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
; u! d" e* @" Y
  1. <div id="app">
    ! l! Q% V7 L- [& b6 Z
  2.     <child message="hello!"></child>
    / ?+ h& R- L1 o- X5 y" j; I
  3. </div>5 c0 Z. n- H! d( T
  4. 2 B& t) K: O# t0 ]% L; h9 I
  5. <script>
    4 I# _; e, N/ W3 ]" H" a3 h1 _
  6. // 注册3 E( S8 I1 L/ _" g. E
  7. Vue.component('child', {& r* W7 F: S: Y( k) X" e
  8.   // 声明 props
    - t; Y8 e$ R1 }8 ~: ~: j( @
  9.   props: ['message'],
      A+ X; s" p2 V' Q
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ! r: J2 O! U# s; Y& k0 m" D  @2 A' C
  11.   template: '<span>{{ message }}</span>'4 Q0 ~" u6 ]4 b' j( R0 K% O6 l( }
  12. })( @8 j/ J6 D* U+ ]6 Z; D) g
  13. // 创建根实例$ b- v2 @4 x; [% j% L3 \' M
  14. new Vue({. _8 O7 S+ ?: ~8 g( T2 R; M
  15.   el: '#app'
    % B2 y1 _5 r0 m7 w1 j' s9 K" M( @
  16. })/ z8 R/ H* ~  {* z
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例  @+ [# b; ~1 y  x. {) w$ Y: _
  1. <div id="app">
    . T' |( i4 |& c; f6 k
  2.     <div>
    # h! M1 e4 k0 ~# `# U0 Z
  3.       <input v-model="parentMsg">2 e9 r, c4 V! I, i# {
  4.       <br>* T% L9 M9 R2 h
  5.       <child v-bind:message="parentMsg"></child>
    ) Z' \8 d7 P( U4 \. R
  6.     </div>
    % \; ^( a# A* ^' h3 k
  7. </div>
    : z6 i0 W6 w/ n) C# I- Y

  8. ( q4 ]7 y& ?" E  ?6 u5 ?
  9. <script>
    , v# g; K% j* y! R& _5 ]
  10. // 注册
    5 |" ]( `/ l) @% d3 ~
  11. Vue.component('child', {8 }1 X! L- J6 y* y+ r1 F$ I! o
  12.   // 声明 props4 i. M/ b: ]/ x3 b+ h) I
  13.   props: ['message'],
    9 ~$ e* J& o. t* L6 k$ n1 f1 y
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用0 C; d) ]2 O& J% Z2 I
  15.   template: '<span>{{ message }}</span>'
    # Y4 V5 \+ [, f/ L$ V3 f  q
  16. })
    0 [# \) L8 O% k& o8 q( h
  17. // 创建根实例
    ' d5 N2 ?5 ]1 L% K  I2 ]
  18. new Vue({$ `! P, x: V- F* [) O" k( a, P
  19.   el: '#app',) Q2 r3 e+ Q& n, r  F. R1 ~
  20.   data: {2 ]; I8 Q" ?7 l3 K
  21.     parentMsg: '父组件内容'
    * ^  j' E! e7 k4 T; r
  22.   }
    : {: @' y/ I7 E
  23. })3 v& E' u1 Q2 ~# w# s+ n" a
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
$ F) I( t/ e" i, U# a
  1. <div id="app">
    * S( ]" i# T2 c1 u
  2.     <ol>
    + H1 p% S% K" T- Y
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    ' u6 H( f/ d& s) {, f. n
  4.       </ol>! B7 r0 r' V% i& |
  5. </div>, R* r; \# e7 o1 y5 x8 ^/ x

  6. 0 H* w; j+ h9 i2 {9 o2 _  ]
  7. <script>
    ; m6 q3 {/ g4 U% b
  8. Vue.component('todo-item', {
    ) \6 s0 s4 ?6 K0 V" a
  9.   props: ['todo'],6 }  b4 g% J7 S' m: y5 _
  10.   template: '<li>{{ todo.text }}</li>'2 `2 |4 j4 m. S$ o
  11. })
    4 |8 y) Y8 v) C% _# a
  12. new Vue({) R7 H' {- F9 i& a, \; h
  13.   el: '#app',( M2 @6 D: d7 k
  14.   data: {
    4 Z* ^: d6 C) [' d9 y+ j" A& d
  15.     sites: [( S; u, F- Q( W" Z$ ?' V6 M( Z
  16.       { text: 'Runoob' },0 S0 G' p6 g9 u4 e+ E
  17.       { text: 'Google' },
    ' O) r* q: @" o) C) [" z2 s$ n  \5 r" @
  18.       { text: 'Taobao' }7 f' ^) x* v9 p: x, S
  19.     ]# G% l8 M% n/ v: {- g6 \% N
  20.   }9 S/ a& u$ j$ g* u; m, S
  21. })9 x4 t) O7 G8 g# Z' i
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    " w  G$ S: w# m6 E
  2.   props: {
    3 q. O1 d; _: b; k/ j! C+ N4 y. y5 X
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    " t9 n- Q0 `' G* w3 O
  4.     propA: Number,
    . E/ b: v6 f* n/ C8 \. y& J
  5.     // 多种类型
      d/ [$ y0 X, E" p% B' G
  6.     propB: [String, Number],+ v/ l2 {6 }) u9 |7 `% B
  7.     // 必传且是字符串
    - _, K$ K' x. D
  8.     propC: {
    $ f( n& K  u8 z$ ^4 X( s* a' x6 G
  9.       type: String,
    ) V; s# F5 T4 V- ^/ x4 ~
  10.       required: true4 g: O! E9 M: |9 p' n
  11.     },1 L( h/ }9 |/ I# _# A2 E) L+ a( ?9 W
  12.     // 数字,有默认值
    . U) \) P( a7 c- \3 V
  13.     propD: {! B8 G9 K/ v) F1 [; [
  14.       type: Number,- o4 I# x0 Q! k7 v0 X
  15.       default: 100% m# V0 h9 A/ _2 S+ W; {1 p; Y+ a
  16.     },
    , P% n6 p( e  S$ O2 c
  17.     // 数组/对象的默认值应当由一个工厂函数返回  x% A7 p8 J7 L3 R+ l# u$ E
  18.     propE: {! b4 m/ K' g, K- g2 i- o; X
  19.       type: Object,
    # r, b8 c4 ^; F" t3 i, b& I% ]9 L
  20.       default: function () {8 C6 |5 ^% v) y0 `5 j% K
  21.         return { message: 'hello' }
    : J- Q+ k( F6 d
  22.       }
    # N, e  ^  z& s& O+ y( K
  23.     }," [# S5 @* j# ?4 Q( H7 n
  24.     // 自定义验证函数! a+ a( V* X! j- f  F) _
  25.     propF: {. U9 ~; ~% o4 a& l6 `5 X
  26.       validator: function (value) {
    $ a, e  _) s! y" [5 K# }3 |! Z/ R
  27.         return value > 10" I2 ]* O/ w7 w% w, J1 u+ q- A
  28.       }$ H% P1 e' J/ o# f2 y* \
  29.     }
      v* n* @; a9 _# g9 z4 I1 T
  30.   }7 p; Q+ y% E$ e- n" C
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array: l% ]8 {: V) G5 H1 i0 i0 e& C: [
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    8 A( l7 d0 l8 @+ W
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
; [, t- j* N; m. w  b" I7 f8 t
  1. <div id="app">
      ~3 t5 ?3 Z" ]% n3 W% p
  2.     <div id="counter-event-example">3 H, @! k( ]) c: v4 v( D2 @. `6 @
  3.       <p>{{ total }}</p>$ [& B/ a1 r" O
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
      M8 i) c1 T7 j0 M1 A  Z6 p
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    " C3 y4 }3 H0 b. T2 v
  6.     </div>  h: t5 l( u* v4 B
  7. </div>9 b7 |1 K& j2 r. q  x2 U
  8. ) ^5 y4 ~/ m  ~
  9. <script>
    8 r6 D4 W7 N' G! D/ t2 e
  10. Vue.component('button-counter', {
    1 Y$ o, W8 @% {* ~* `4 u
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',9 @0 U) h, k9 S
  12.   data: function () {0 H& ^' x. O, L+ ]
  13.     return {
    ; D' }! a' H5 S- f. \. H, L
  14.       counter: 0
    6 y+ `: ?& h$ p. M+ m, Y& C6 M1 k  N
  15.     }
    * {; [/ M6 ^* d# x
  16.   },' K+ ^! r+ \3 Z; C) g1 f$ S& _/ G0 p, X
  17.   methods: {
    ( H# p& ~6 q9 {) I, V/ n
  18.     incrementHandler: function () {
      E* @, N. E8 @4 V! j7 n% D
  19.       this.counter += 1. p( Z! y& p3 J5 w$ q- b
  20.       this.$emit('increment')  ~+ p# a- m/ a( r- W, Z! X
  21.     }
    ' P3 p: C/ B# q
  22.   },( [9 X' L+ L) q; N. \
  23. })/ t) i# ]1 t& r) |  u" ]
  24. new Vue({
    # a8 f& h2 n4 ?5 b
  25.   el: '#counter-event-example',, s9 o3 u9 R( P  o
  26.   data: {+ j9 N7 q0 `& m
  27.     total: 0) m9 }" d' ~) x, ^
  28.   },+ P' y2 ~! |  c* r
  29.   methods: {
      n0 ^" c( |9 K5 {* y8 k5 G
  30.     incrementTotal: function () {+ t) }8 s9 t* `1 Z0 L
  31.       this.total += 1
    + E: H: Q  ~8 s3 S+ M) @8 ?
  32.     }- }, K3 L% {. ~! |
  33.   }8 v  P9 L0 K& t/ D
  34. })
    / e$ N5 _# c8 W( C. W
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册$ ~2 L7 C) S/ j! M- N
  2. Vue.component('child', {
    : d+ V' M0 Z" I# r: p& @
  3.   // 声明 props* ^2 x9 a9 x" [  _: j+ D2 t: E8 W
  4.   props: ['message'],9 ?: }' e9 a( q' K  c; P
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用; x5 v/ L: P' r9 ?# n; K: S# G
  6.   template: '<span>{{ message }}</span>'
    + o$ `: j5 _% {0 Y4 d
  7. }): m+ c! V( l# [  L
  8. // 创建根实例
    ) t& v# T1 s; ?
  9. new Vue({
      N$ E! r% c& P% K
  10.   el: '#app',7 U. q) @- \) r8 ?+ q
  11.   data:{$ e+ E5 E% I; i: |
  12.     message:"hello",- ^2 H+ G0 s& u+ Y8 g3 |( G
  13.   }0 l0 n) L+ h4 `  W1 x
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
      M( w* t/ _" H0 G/ |# ?
  2.     incrementHandler: function (v) {
    4 G% `$ h7 d3 F0 g4 n/ U7 n
  3.         if(v==1){
    7 {' V1 W; J. i" @
  4.             this.counter -= 1
    4 r0 a) X% t" F+ A: V- }) g
  5.             this.$emit('increment',[1])- F% m8 }! r; u. A0 ?9 T' }7 o
  6.         }else{6 M. {7 g6 _/ z
  7.             this.counter += 1
    7 X0 n8 a# [+ q1 N+ v, M8 S9 T  P  b
  8.             this.$emit('increment',[2])& C  [: R; H$ L- W
  9.         }
    / ^) i1 m$ L0 j# U3 R, [
  10.     }) m% ]( X- B% X8 p, ~) g
  11. }
复制代码
4 S" A$ B8 N* T: [' \

; |7 b( v( K4 @; `% v
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-7-19 15:50 , Processed in 0.073971 second(s), 22 queries .

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