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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

, _/ V, y0 G" \* B3 {. W
  1. <div id="app">- V+ L5 w% y2 j! p
  2.     <runoob></runoob>. N1 K% O6 F- E  v: f2 z( C; E
  3. </div>
    : L, I" J& `. U

  4. 3 a& a/ D" S0 H0 W
  5. <script>
    + [$ ~( j8 Q4 Q" R, }
  6. // 注册
    7 G! V% p; Q3 X! y1 j. ?* a
  7. Vue.component('runoob', {* E* ]7 R# j! q9 y9 e
  8.   template: '<h1>自定义组件!</h1>'* t, L) t3 Y+ o8 ?
  9. })
    3 u$ I' n" ~; |+ U0 v7 z8 i
  10. // 创建根实例
    ( S' ^* U9 _3 E7 ^
  11. new Vue({& L  \* M+ E) x" s7 a# \
  12.   el: '#app'
    : s* J5 m- g7 z1 I6 z8 |4 C
  13. })
    ( X" H4 T4 b* G+ ^3 S' }
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
6 u8 _6 K8 A/ y! [# o2 e. T9 Q
  1. <div id="app">
    + T7 y& z( ?0 S7 |  `
  2.     <runoob></runoob>" ^& h  g6 U1 g) T  `  k) E. `
  3. </div>
    # [& m4 x4 ~; x3 k6 s

  4. ) U" y7 e3 W4 a, @0 Q
  5. <script>+ [4 Z! `" @+ X" W6 |7 A% |
  6. var Child = {
    ' G' `7 F# F: L- m8 ~* ]
  7.   template: '<h1>自定义组件!</h1>'( H! q$ t( ^3 g5 ?% l# ?# h, [
  8. }2 Y' ~' y) d$ m8 ^" K
  9. 9 v) a! O* |6 T' u% d
  10. // 创建根实例
    ! k6 ?& H+ C" S  d1 Q
  11. new Vue({: a' u8 _) @! a% k0 B7 b
  12.   el: '#app',' W* I/ J" R  D) Z- o
  13.   components: {
    ) k+ D! [2 F6 ?& u
  14.     // <runoob> 将只在父模板可用, ]0 ]* [( e0 h3 b/ r
  15.     'runoob': Child
    ( C7 a# Z6 u2 [; j- h& {2 \
  16.   }) d2 ~; e' e- ^/ U; y, Z! B
  17. })# |4 h6 _8 c. l7 s- B
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例6 G4 F6 D8 z% R
  1. <div id="app">4 b- L+ o; ?  n. b# _4 a! ~7 }
  2.     <child message="hello!"></child>
    + {1 H. C3 Q+ _' B1 Q
  3. </div>5 `/ T# @( S' a0 d! C. S( y1 t, N

  4. 7 w" N* L+ Y3 f! Q" Q1 F0 |  @
  5. <script>* j) ~+ B+ o0 n# E8 h; a9 O
  6. // 注册* T3 u0 B; q4 b% ]8 \- ~1 f
  7. Vue.component('child', {
    * X; p9 ?+ s3 R$ f" ^! j
  8.   // 声明 props4 _3 x- j, E' t7 ?4 q
  9.   props: ['message'],5 N( z  u$ f; H7 }& Q
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用4 I5 f5 l# ^4 H8 _' i) `1 z
  11.   template: '<span>{{ message }}</span>'
    ' o7 i0 `& Z  W$ a1 ^2 S3 k
  12. })6 h+ ^+ I* }) }$ G# z) n
  13. // 创建根实例
    8 u" K8 q" j0 x# F
  14. new Vue({5 C; l* v+ f9 l& z. `
  15.   el: '#app'& a0 |( _2 N  V& U
  16. }); a" B0 V# W7 B& x6 X
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
. y5 O' G4 b6 Z& {) k6 u& q
  1. <div id="app">; i, x( k9 ]1 v" `+ r9 M2 o
  2.     <div>: e) F) G" e- M
  3.       <input v-model="parentMsg">: l( Z1 [) k# y$ v/ _6 R- }( p! g
  4.       <br>
    0 A. O6 F+ B5 r: m2 X
  5.       <child v-bind:message="parentMsg"></child>
    # Q9 \3 F7 `. b1 g# g, a
  6.     </div>
    * x5 s+ ^* ^# a$ c
  7. </div>
    : M/ I' a2 m& a

  8. ! ^" l0 |1 N1 ~! g
  9. <script>) k) ~4 t4 ]9 b
  10. // 注册
    : A% C- Q" f/ ]0 n
  11. Vue.component('child', {4 {3 S- Q; W% a) a& J
  12.   // 声明 props# X7 D; ?0 M# f, C5 l
  13.   props: ['message'],& y8 a; H- G( P* {: t2 `9 P
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    # k5 \* i* E0 E( m
  15.   template: '<span>{{ message }}</span>'
    8 p1 B( m+ X3 ~
  16. })+ @* x5 T) A9 J3 v- B
  17. // 创建根实例& [1 c" {" V, }3 W2 g* p% J) {
  18. new Vue({0 X# |" [8 q+ M/ Z; H# v
  19.   el: '#app',
    . U% U- |. `) Q
  20.   data: {. ~9 s- }' ^+ P
  21.     parentMsg: '父组件内容'. U9 t- h) L2 F+ B; V: o: f* P
  22.   }
    # a& w' D/ ^! t+ `9 w" y4 N
  23. })1 z5 U9 Z: P- z& e
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
  J' N4 J+ @$ r/ G
  1. <div id="app">
    0 G) G1 A' h3 y! \1 R) q1 Q0 y" }
  2.     <ol>. O% t. P/ F4 q6 r1 E( z0 q8 l  r
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    4 s6 }& O9 C, D- W6 F
  4.       </ol>' T$ @+ f5 Q2 J
  5. </div>. L; d4 Q6 ?3 f$ D+ A! h
  6. 6 t1 j2 O# l7 }& y% }: Z+ i
  7. <script>4 n1 r' @8 ]% S: M$ |& f, Y
  8. Vue.component('todo-item', {
    7 g1 j7 R8 M3 N# V
  9.   props: ['todo'],4 y% A3 r' @; K, I4 V
  10.   template: '<li>{{ todo.text }}</li>'8 m# }  e2 j- L$ v
  11. })6 u0 |3 D( z! e! G$ T
  12. new Vue({+ h9 g9 u4 a0 ~) I. _! b+ r
  13.   el: '#app'," a) N9 s8 _5 ^/ p5 d# M7 n
  14.   data: {
    + B3 f- H2 l& g, E/ ]
  15.     sites: [) i! \: k1 R& }" v, q3 `( V
  16.       { text: 'Runoob' },9 r  a+ \. ?! [; L7 C( F( t2 \
  17.       { text: 'Google' },, ^* U) ]) g" e
  18.       { text: 'Taobao' }
    " I1 q7 A6 Z# Q" D6 w
  19.     ]
    7 C- Y: X3 |* h) ?9 b  ?
  20.   }5 A' g6 I- q$ |( ]
  21. })$ b, ^; e* h' \: P: G. v- N
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {& o+ A# p& @" K( U
  2.   props: {
    9 V1 @/ X, K' ]+ w6 a& V
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    ! ]- ]9 n: z0 w! b4 z
  4.     propA: Number,9 e% y2 `* E7 A% n' {: f: S
  5.     // 多种类型; i0 s: ^6 K8 q( E- ~) i& c
  6.     propB: [String, Number],- e! Z* Y1 W' ~/ a% Y, Q( U; v* h% y
  7.     // 必传且是字符串1 Q; B: Y7 u/ L! w" O6 z* o# x
  8.     propC: {
    , X/ R4 y& c; B" J4 t
  9.       type: String,
    ; L+ d: y* y+ {. e+ g
  10.       required: true
    8 S5 k0 V/ \  l7 X  |
  11.     },  V. E9 b# }/ y) W$ T
  12.     // 数字,有默认值
    ! H4 Z1 N0 z7 e
  13.     propD: {0 k. C. m4 [0 l+ J' [7 E$ E
  14.       type: Number,
    9 T2 h: P9 m2 l! E
  15.       default: 1000 E) _: n# L+ f3 n
  16.     },
    6 Y' U2 r3 j+ c/ m2 ^1 X3 }
  17.     // 数组/对象的默认值应当由一个工厂函数返回( [) v- t) ?2 C9 F0 Q7 D5 v
  18.     propE: {5 k8 u8 \1 z4 s$ s  Z
  19.       type: Object,$ ^4 F% l- t+ j
  20.       default: function () {
    * u% p" O$ A1 ]/ I
  21.         return { message: 'hello' }# p) S' a) ]& k# n8 C
  22.       }$ \1 Z: Y1 P. O9 o6 J5 b
  23.     },: ~6 |$ y" a4 J7 r+ M, ~' _
  24.     // 自定义验证函数' o5 k) }$ ~  ]# m9 H
  25.     propF: {
    ; E' E1 y0 J, g, ?; J
  26.       validator: function (value) {  f' I' e$ n$ q2 p
  27.         return value > 10* L* T$ T& G+ [8 ?
  28.       }& }- n6 X5 ^. @' T- _) Q% ^
  29.     }
    2 Z2 i$ O5 e, l6 K" h- `
  30.   }( H$ ^$ Z) p  }4 m' {
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array  Y* k2 _  e& b) ?
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件* @; q5 r# H: |& [% P
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例3 I3 E) ~% B3 O& a/ F- I& x2 j
  1. <div id="app">
    & z0 j9 w5 |. B5 [
  2.     <div id="counter-event-example">
    ; X- q' F+ ~: B5 ]
  3.       <p>{{ total }}</p>
    " ~1 t0 N7 _8 Z  x+ |
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>$ i0 y* u( c7 W, \" Q" z) \9 y' g
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>% c; B1 \3 q( i( q
  6.     </div>
    ) @/ U/ n' \1 z( ^6 j; u: K
  7. </div>
    1 z* v: t+ p4 x. Y

  8. 3 E; s4 K: s* W" j6 H8 O
  9. <script>
    . N1 o/ u- a6 W5 a# G0 ^6 Y) z
  10. Vue.component('button-counter', {
    3 R$ j$ Q  m2 Y: V) u# ~4 x, Y$ @
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    % t5 N( q  l. F; ~, N% R3 }
  12.   data: function () {2 [5 Q2 S3 o  K* A
  13.     return {6 I% e: m( B& ]8 h. F3 Q
  14.       counter: 0: B9 a; e9 ^2 M# @% G
  15.     }
    / \$ g; D& {1 d) r4 w& t# X
  16.   },  o2 o/ T5 p7 A. @: J0 `
  17.   methods: {7 E1 u: B0 O: G# L5 [  i( b+ {, _
  18.     incrementHandler: function () {/ U1 C7 |2 p4 [2 Z8 J
  19.       this.counter += 1( f. E. Z7 D1 O, W
  20.       this.$emit('increment')
    1 c+ y0 t1 T' O: e) I
  21.     }0 ]; @. a. B# B0 r6 \3 D
  22.   },7 y. b) K5 r+ q. ~
  23. })
    % E5 l' V0 \* ~; p: R( B2 A
  24. new Vue({
      L7 S! @1 \3 t
  25.   el: '#counter-event-example',# g3 G7 a( X: N  P$ h
  26.   data: {
    $ I; W, }+ a9 X5 m* V9 g( K" H, c
  27.     total: 0
    2 d& l& a' t  n
  28.   },
    5 P" m+ Q% W5 F/ Z9 e, g( [
  29.   methods: {
    ) u4 S# I. D' A+ T  `* a" B6 j( v
  30.     incrementTotal: function () {6 l1 I2 H% r( a/ W; k9 N
  31.       this.total += 1, b0 \9 W7 B* y
  32.     }
    ' W* ]" l9 n! \( ]3 N
  33.   }, D4 S  X# u8 @, Q9 p/ I' b7 j+ ~7 V# Q
  34. })
    8 D; L9 V4 _6 K) g2 g; f
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册! P& y* V5 S& b2 A! ?# \
  2. Vue.component('child', {
    , |0 e) E2 Q* X7 M
  3.   // 声明 props
    2 C& l/ i3 u* {) l: P. S1 j- C
  4.   props: ['message'],3 ~$ b( X; f, V( M* U
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用( T; e+ n3 g) J, M  C1 g8 A
  6.   template: '<span>{{ message }}</span>'
    " C9 e. i  n0 N  Q% `5 q
  7. })
    , ?$ M4 Z# l) L! N8 g* B5 Q
  8. // 创建根实例5 \  v* ^3 ?  G  t. r
  9. new Vue({
    : j2 A( n" e- o, ?* _% Z
  10.   el: '#app',/ G4 V) X, p' h
  11.   data:{0 ]5 ?5 U# B5 j7 ]
  12.     message:"hello",
    * J' R4 B4 ?2 p
  13.   }0 B" G  r. p. K& E& l: q* C" m
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    ' l& g9 I6 m. p
  2.     incrementHandler: function (v) {3 f7 U+ l6 R9 c/ a9 N+ @* Z: h$ G
  3.         if(v==1){+ p9 O* b! _- f' p' H# b
  4.             this.counter -= 1
    ! r' j1 j' W8 `  V' n
  5.             this.$emit('increment',[1])
    6 ?5 H9 |/ A& _! Y# j% |
  6.         }else{+ D* o* m* M- `% t8 g& m
  7.             this.counter += 1# ?% e; t8 b5 x4 q2 @  F
  8.             this.$emit('increment',[2])
      E- |! k0 y* z! e( Z3 f- m( J
  9.         }
    * }1 I8 G: T  F$ T9 M( [
  10.     }
    / t: R, @  y6 L' H4 x8 Q7 T) x- L
  11. }
复制代码
5 t6 M1 p/ \6 j% [, B

: x# R! {! m7 ~7 ]
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-9-21 03:14 , Processed in 0.061597 second(s), 22 queries .

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