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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

4 V/ u! {& b9 h: [, z3 ^; E
  1. <div id="app">
    + H1 P2 Z- w2 d: x- q
  2.     <runoob></runoob>5 \" g+ t' `: j0 P- p: c( H5 F
  3. </div>
    - _6 X1 [- f- @7 F9 u4 ~! m- [' o
  4. ' m  y9 r8 V& v+ x
  5. <script>
    2 B, n/ s8 i5 `. O
  6. // 注册
    6 v4 O9 J- ?" b- i" |
  7. Vue.component('runoob', {
    2 l# m& p. X  A9 I! d
  8.   template: '<h1>自定义组件!</h1>'- |6 [. l9 g% V, w
  9. })
    # B  r$ N# s& ]1 _: e3 m. H; \% t
  10. // 创建根实例
    $ D7 R; W2 z5 T5 R$ B
  11. new Vue({8 E: e8 l; P8 q7 D0 W
  12.   el: '#app'8 B  H+ v: A, V8 I2 n
  13. })
    : ]. E6 |% x8 n  x
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

0 X' B; _; x8 X3 H: i
  1. <div id="app">
    3 b/ ]' n' o& [7 l: X
  2.     <runoob></runoob>8 d5 g6 D& R7 z$ M" d5 `
  3. </div>
    + n3 t# V  e# y# y

  4. # h+ O: p2 j% [: y7 H
  5. <script>
    6 [3 S, P/ r& T3 q' H# X
  6. var Child = {
    ! W+ c. U+ Q$ c1 M: k: {
  7.   template: '<h1>自定义组件!</h1>'3 g. o+ S* D" D/ K+ z& Y
  8. }4 h+ v1 L1 Z2 z, d+ S6 D

  9. " |( C, q8 R" k3 q" N# r  [
  10. // 创建根实例
    ) Y* Y: U7 O/ a6 O- Y$ {3 O
  11. new Vue({
    2 G) c, s, r' m4 |2 b+ p- Q* B
  12.   el: '#app',9 R' K% A# `% d* e" y
  13.   components: {
    ( L8 q3 e3 Y9 p  s. @
  14.     // <runoob> 将只在父模板可用
    , r' W& a6 H' l4 H. t* V% o
  15.     'runoob': Child
    ' I* \' B$ C  c
  16.   }
    / R- y# X( b  }! S1 I5 z
  17. })8 @6 \; f7 _) w# ^1 R
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例8 ?; F+ |# d3 }" K
  1. <div id="app">- @1 q  A  ~3 J8 V$ [+ b4 B& J
  2.     <child message="hello!"></child>
      ~! m+ c4 o' q& K" Z  O
  3. </div>& U: y# T  {1 \# N" j4 j
  4. . ^6 ^4 ?! l3 O$ P& t
  5. <script>
    4 w+ A0 ^, K2 M+ Q
  6. // 注册, c* M9 e' K' x( G3 J0 c/ k# \# C2 n
  7. Vue.component('child', {
    7 Z8 v8 \& }" a& C8 \6 n4 d; `
  8.   // 声明 props' m% e* c9 Q2 V1 O; O5 n
  9.   props: ['message'],2 w, G& @. h4 p
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用9 _% L2 V3 c9 J# L7 y
  11.   template: '<span>{{ message }}</span>'
    % ?9 s, M# X' T3 f" |/ F5 ^
  12. })  N6 U( F$ {2 i. e4 q% t: p+ ^4 g, \
  13. // 创建根实例
    6 q9 W& D7 r0 q0 n( C, c3 K
  14. new Vue({/ [( O5 S3 u1 a, {* w
  15.   el: '#app'1 n: y3 x5 C: k# B2 r: P
  16. })
    : v. f4 O3 U& V& q' y. y- G
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例7 X6 I! a3 Y2 ~) k
  1. <div id="app">
    6 h9 z/ Z7 ^& O9 G; V9 f
  2.     <div>
    7 Z% F/ ?  @6 x0 @) P  T* ?
  3.       <input v-model="parentMsg">
    6 u- g6 }# W6 t, V; ^  N$ W9 t
  4.       <br>$ H4 p+ h# k$ ?; t& z5 G
  5.       <child v-bind:message="parentMsg"></child>
    7 C* P2 f3 }7 u2 Q
  6.     </div>
    : F' G  _2 J3 e+ u- ]
  7. </div>
    * B8 z/ a: n# s( H5 z

  8. 2 G) s+ L4 p' W& }9 ]
  9. <script>
    , a" [# x) z  m, P
  10. // 注册4 H' V2 _" I! M* D% L% P3 i
  11. Vue.component('child', {0 x! r7 W3 B( {4 {& u- C
  12.   // 声明 props# O% q: n! I" Z* D
  13.   props: ['message'],9 e% K$ a1 J5 ~6 i+ T# U
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    2 B: ?( ^, k* W  O% ?+ }
  15.   template: '<span>{{ message }}</span>'
      T# X' [7 \: r% g+ B
  16. })6 K# S( K! }: q' A, @
  17. // 创建根实例
    $ E! G# Y3 y7 Z3 g7 e8 n
  18. new Vue({; x% w1 s- _3 L& @
  19.   el: '#app',1 \. x1 R. }( e5 k. A& r
  20.   data: {
    $ _4 m  k7 h- i0 F5 {
  21.     parentMsg: '父组件内容'
    ) a/ s" S% O& o9 \! m! n
  22.   }6 x# C( V/ y8 d
  23. })8 a. a1 E4 ^+ t
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例" f1 k3 Z; k; G, z# `$ q  N7 [
  1. <div id="app">
    4 ^/ ?: b" w! U
  2.     <ol>3 u! t  M! V2 Q' h
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>" Q3 K: G& `$ {6 z4 ?1 Z
  4.       </ol>$ W1 t4 M6 y+ F7 J1 ^% d
  5. </div>
    ' L7 q5 [) o8 m, Z0 V+ R, G9 i
  6. - ~% W4 H4 n. X3 ~8 u* y
  7. <script>3 P9 v1 ?) @9 O% [( [& i; w
  8. Vue.component('todo-item', {  g  h; E3 ]: ]+ c3 Y' R( ~
  9.   props: ['todo'],& W) P) T9 G# j: o, C3 W
  10.   template: '<li>{{ todo.text }}</li>'! j! V" X5 z9 x: @* I7 |; k
  11. })6 q: B  _7 ~( W
  12. new Vue({
    1 u5 C% m* _! Y6 }+ O  @
  13.   el: '#app',1 L, N8 I" g2 @! v
  14.   data: {
    ( Q, X( C' x- h3 K" ?/ c( K
  15.     sites: [; x+ `! ~6 \3 \6 v6 {& g+ Y
  16.       { text: 'Runoob' },
    ! [& h0 ?8 Q. ^3 }0 `* ?6 t
  17.       { text: 'Google' },
    " p+ @) _0 T. \7 B# k
  18.       { text: 'Taobao' }
    + M* J1 _7 N6 j0 E
  19.     ]
    ' }- z! m. w1 f6 Q5 V" k
  20.   }
    ) w& _& z5 x% `( L, `7 a) |+ ^
  21. })3 u! A  `, w" N/ b2 w" j
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {$ Q$ S+ D& |3 \# P# X
  2.   props: {8 a# s4 \  F, b. C: z) H
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)5 C  I7 f: K. n3 l* @* n
  4.     propA: Number,
    + P. P: h; q/ y) d" j% C
  5.     // 多种类型
    ( }" X7 t. f, ~* n' z" }
  6.     propB: [String, Number],4 P: _& Q+ ~# ~
  7.     // 必传且是字符串' Q' H" H- q, B- u
  8.     propC: {6 k5 C* w9 ?4 l  d' G
  9.       type: String,. i, l! s1 L1 Z
  10.       required: true# F; T" F1 R) i6 W6 S
  11.     },
    . N: D& R9 v; R, u% D# W
  12.     // 数字,有默认值
    ) L" ^7 V$ l$ y! H- `: ^
  13.     propD: {
    9 c- O8 ^7 y- D/ ^! t" v% u
  14.       type: Number,+ y1 N$ D& W" u" ^( @
  15.       default: 100$ q1 a: I  b, l% A1 X* p
  16.     },, v* }) d6 u' v* ~/ j
  17.     // 数组/对象的默认值应当由一个工厂函数返回' ~# m! g0 H# b1 B; k
  18.     propE: {
    : E' s' @9 k- Y" [6 b$ y8 _
  19.       type: Object,4 r. g" l, I/ N7 f& q2 b$ |, G
  20.       default: function () {  P3 C+ W7 U8 \. A! Z
  21.         return { message: 'hello' }
    ! z4 y6 L8 }, y: y1 Z
  22.       }0 {+ k) m9 [" _+ s( M: ?$ ^
  23.     },* T$ j" N! X3 j; G' h5 r2 }4 {% I
  24.     // 自定义验证函数, T& z9 J7 P6 `5 n
  25.     propF: {( t: M8 D2 t, ?* _
  26.       validator: function (value) {
    9 G' u8 {! @# K1 c: j$ x
  27.         return value > 104 X8 Q. s$ E# V, l. v' w9 O
  28.       }
    3 `  _  Q  n. }: M' X* l
  29.     }
    % ?# o4 o6 m' y& s0 H
  30.   }
    1 e% O  w  f8 h8 L+ I
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    3 T* D- ?- r; |1 I& ?# G
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    6 M3 y  T4 L- f* Z0 p3 Z4 B' \6 {
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
! X; d. ?) B/ B6 h4 v: ?
  1. <div id="app">5 v" k  R) q% Z( K5 _
  2.     <div id="counter-event-example">6 i2 Y: s! J( b! Z
  3.       <p>{{ total }}</p>
    4 U/ ?# a1 w7 b9 q
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    " q+ t# U9 }  r8 S( @' ~; L
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    + f* [9 ]# _% l4 ]' R' E5 A8 o9 z- c
  6.     </div>
      [, ]$ R4 B; s3 Z
  7. </div>
    4 s' p; K# n' ?" z2 ?* I
  8. ' j! ^( T3 R) {+ ~
  9. <script>
    # N! e7 @( M% O5 i
  10. Vue.component('button-counter', {
    - P, m- i( F: ]3 Z
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',2 G* w8 u# A+ w1 \' E( l- [  A9 r7 X
  12.   data: function () {) O! t5 Z, j% U
  13.     return {
    / f+ Q+ x) J9 P" H3 ~. w5 o& d
  14.       counter: 0$ j1 R; u+ V( g5 W. D7 F* F( }
  15.     }
    - T) v1 U  J6 W7 B* p- y) c
  16.   },) x( w+ s/ v& }# Y4 p3 |1 n
  17.   methods: {
    : K9 l1 B4 ^& y* b
  18.     incrementHandler: function () {
    0 Q( O# T( S8 C  O8 o/ q
  19.       this.counter += 1
    1 a6 J: V; Y% G9 j4 C% p0 C; k
  20.       this.$emit('increment')
    * g# k! q7 [& p4 W- Y, n
  21.     }6 b3 }" T; |# K. ~3 J" {* _
  22.   },
    . e! D  U- Y" L* W  \
  23. })2 @/ v. u* `8 Q0 Q  ]- x, ~
  24. new Vue({6 t7 p5 B, y! D5 e9 y
  25.   el: '#counter-event-example',& X) a, A) n7 z2 u
  26.   data: {# s  W; t& e( \( e5 D( M
  27.     total: 0
    ( A- f/ y# j5 U3 _9 T4 s! ]
  28.   },
      e2 ~, n& e6 f7 X' y6 r
  29.   methods: {
    + [$ d: ^0 i/ N0 A! B, W# t
  30.     incrementTotal: function () {. V5 K6 y$ C6 j& ]) U" S8 q/ C
  31.       this.total += 1
    ( J" \2 k/ C, v1 H9 B# k0 T
  32.     }
    4 f# X) w; ?" _4 v. o4 F5 N
  33.   }
    6 K; {7 E: L9 O+ L
  34. })" [: N2 H& \" q0 Y2 D% i
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    * f7 I/ M8 x1 z. G
  2. Vue.component('child', {
      [  R& U" ?& H6 ~0 V3 O
  3.   // 声明 props1 H! T$ t% ~# j/ ~: D
  4.   props: ['message'],
    * J- N) ^  R% }) g- x6 K! t
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用; r0 Z1 n; [7 l5 r
  6.   template: '<span>{{ message }}</span>'+ s& G; R- B$ s1 A: V) c
  7. })! j2 N  I. A* w1 h3 Y) ^
  8. // 创建根实例5 R' i; S& n/ g# s( ~4 s- e
  9. new Vue({0 |. o" ^" g% h1 q0 L. V
  10.   el: '#app',7 C  J) _7 L6 p1 G
  11.   data:{0 U  k4 h; C4 o) V* f4 L
  12.     message:"hello",
    " z; l- g: `9 b0 u$ O7 d5 ]7 g, z( ]
  13.   }+ f. C# n$ R7 L/ ?
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {% n2 G3 v4 V4 z6 [; ^
  2.     incrementHandler: function (v) {
    ) N7 n6 b4 B. V7 U
  3.         if(v==1){
    # e; w) ]; S; ?! b+ @
  4.             this.counter -= 1
    0 P! C* c0 ]: O1 Z& t( i0 M
  5.             this.$emit('increment',[1])
    + M  F/ G: c% D' A
  6.         }else{
    . D+ W9 l. Z& g  i/ B/ L7 p
  7.             this.counter += 1* E& x2 X3 _1 h9 Y3 V, K
  8.             this.$emit('increment',[2])
    0 W/ C0 V1 q. {1 P. ?
  9.         }
    2 {) i+ a& J7 P+ O
  10.     }  y4 C5 m# W8 h$ V+ I  O( W" }5 R
  11. }
复制代码

/ E5 b" w" Y' Y' a& u$ _1 a6 R% Y7 M  ]+ a8 ~$ ~% \4 R
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-9-21 04:17 , Processed in 0.072163 second(s), 26 queries .

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