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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

' N- k% l2 |8 l( C2 N0 {" v; v- E& Z
  1. <div id="app">
    & a0 c! g+ J5 Q/ @% |( y
  2.     <runoob></runoob>0 m1 }# _  O1 f$ j8 o* y& K
  3. </div>
    : E/ X7 y5 A6 ?$ U
  4. " g; \/ i' ?; Y2 Y
  5. <script>
    # Z; f  F3 e& U- O& v& A( N) G: a+ I! X
  6. // 注册
    ; y- I2 a, T6 y4 o; e* P
  7. Vue.component('runoob', {
    / ]3 \9 h  M7 b2 b/ r8 L/ T
  8.   template: '<h1>自定义组件!</h1>'9 M7 q$ Y4 X) w7 @
  9. })
    0 b. T( E, M8 T: _$ i
  10. // 创建根实例
    9 f! t5 h2 q9 O+ `$ c
  11. new Vue({2 H2 {. v& T5 x' G5 e4 D
  12.   el: '#app'7 {3 X1 U/ R1 F1 h, b
  13. })5 Z1 g7 t$ d. q3 f8 s( g
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
  p% k* f" m, S* h5 |
  1. <div id="app">8 i# Q& ?5 P! L2 f0 ?6 u8 B2 q5 x4 W
  2.     <runoob></runoob>
    ; f0 P4 z5 [0 l' c+ U$ c1 G# J
  3. </div>
    7 T$ W! I$ Q) u0 ~9 C0 ?/ H$ E5 N4 ^

  4. 4 G( h  Y# X! ]8 y& j$ m7 c
  5. <script>
      r% ~6 |! o, _
  6. var Child = {
      q: @. C. N2 N" |
  7.   template: '<h1>自定义组件!</h1>'
    , Q& l3 g0 S. U7 _# t& i
  8. }+ J, y0 }6 ]# V- r% n1 |3 i  M7 b

  9. * `% V7 Y' t, _" }4 |3 ~( K  [
  10. // 创建根实例
    6 t5 l2 Y9 p, K% d5 z% R2 H8 q& h1 Z
  11. new Vue({
    6 y, g: D4 @% g  _7 Q% |. s
  12.   el: '#app',
    ) X! s& I* D2 {* h8 B/ H* l- O
  13.   components: {, J+ S: x3 H; Z# b; |& U& Z
  14.     // <runoob> 将只在父模板可用( W# O( i4 g/ a: N
  15.     'runoob': Child) ^+ ^* q8 H' |& N( L
  16.   }
      m, O" H1 f, _: K' O
  17. })
    5 a# p3 u5 b& c$ D' s. S
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
4 g! M  l8 T0 g' X
  1. <div id="app">4 E$ U1 p8 F1 U% x
  2.     <child message="hello!"></child>
    * A8 u5 J# Y+ B5 _
  3. </div>9 q$ M- F; l* v- _

  4. 9 U  r# G* t7 H& S
  5. <script>0 o- p" r1 D, g9 M( n
  6. // 注册. z, y" j5 G( u, c  o) J: v
  7. Vue.component('child', {
    . \5 V/ H2 N( z% Q. I  H4 n
  8.   // 声明 props
    0 N+ }) e( A0 y. E: Z0 ^
  9.   props: ['message'],, _% w. M" G+ e6 l5 D
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ! ~& y) D9 D% F/ l; I* @. [
  11.   template: '<span>{{ message }}</span>'+ G/ o5 ?/ T; k5 J+ m: x2 k
  12. })( @5 X. h3 @! P; l: K$ F
  13. // 创建根实例
    3 m4 u2 u. y2 m. [
  14. new Vue({
    ( W# n% X$ k  h; {+ ~. b
  15.   el: '#app'2 Q/ U# @+ @4 c  D* v- D
  16. })
    2 ^8 B/ i$ [/ |
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例$ h: D2 R: i# V# }' T; o4 {
  1. <div id="app">
    . s( U& ^: A( j: I* L' ~( w$ Q
  2.     <div>
    , }0 B+ R% l. `# O- K# d/ [% T. e
  3.       <input v-model="parentMsg">9 p8 R0 [5 {& I/ _
  4.       <br>
    6 m; Z  X) t3 k& D1 D$ M
  5.       <child v-bind:message="parentMsg"></child>0 M) Z  D7 X  T4 o% {
  6.     </div>
    + A. f6 D9 x2 \5 f. c/ D$ p% @
  7. </div>* h* d2 A  H$ g# {: K
  8.   {  W" w& q9 m, O6 _% J
  9. <script>
    * Q5 ?# X8 \5 Z. F& }
  10. // 注册
    + L  R1 k6 n& G1 x4 D
  11. Vue.component('child', {% p7 \2 u1 M& G( Z" K
  12.   // 声明 props
    % H4 I5 H* W* T5 c8 c
  13.   props: ['message'],
    $ j* O. @& B) ~6 U: I6 p
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ; ~" ^3 p. v9 q* T6 ]
  15.   template: '<span>{{ message }}</span>'4 i; K% M8 Q+ Q5 y9 g, l
  16. })
    ) ~8 A0 e- ~# t7 i! W! S- ~" u
  17. // 创建根实例! e5 f0 d. N5 p- n, y& ?8 X) s
  18. new Vue({1 @5 d" |" p' t& F$ _; g, i# V) O9 j
  19.   el: '#app',' p" v, s0 D* T5 @. Y
  20.   data: {
    , o2 E; U* A7 q. O0 u9 x# w
  21.     parentMsg: '父组件内容'" M( ?% P! w. \. }' w) G' _7 ^
  22.   }
      k+ |% F3 {. r5 `0 U! _1 @% \
  23. })
    ! t9 N0 t) ^3 u  s9 L
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
4 E) a! p$ W3 H: z8 y2 @
  1. <div id="app">
    1 U7 `* l; x7 D$ N7 s
  2.     <ol>
    # L& j" w$ X& x5 ~3 t1 H+ \/ A
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    ' S- Z. n# x2 M8 m4 g; F9 y3 K  G
  4.       </ol>
    # j& A3 d3 l1 z, e- Q8 a: v4 X
  5. </div>3 H! R$ t7 Q3 b+ x5 `- c" X
  6. 9 ]$ }9 @* V8 f7 \3 q; b" L
  7. <script>
    : `7 O. ~7 Q* g, ~( Y( G; x4 R
  8. Vue.component('todo-item', {
    ( X! ?; \$ p" A8 N6 M
  9.   props: ['todo'],9 a; F$ m, H' G  v5 h9 b
  10.   template: '<li>{{ todo.text }}</li>'  ~% {* G9 V$ Z" A
  11. })+ i/ ~% A8 i% ?$ T
  12. new Vue({
    0 L) A' [" G# p/ s( Q* D
  13.   el: '#app',
    7 ]/ P3 c# p2 \' _, n6 G
  14.   data: {9 `" x/ o- u) H
  15.     sites: [
    8 U4 o& E+ }2 c" K
  16.       { text: 'Runoob' },
    ) N. l' X" ]8 @1 R8 v
  17.       { text: 'Google' },
    ' I, H9 _5 B7 R; I; L3 I
  18.       { text: 'Taobao' }
    ! f$ L$ l4 I5 t+ \* G
  19.     ]
    0 k( a6 f' x: @. G- m; Y" E
  20.   }, h: P0 V& A5 E$ M9 U! h; @& m
  21. })
    2 C" m$ u8 |) I- j3 k
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    , o- s; x$ x1 X/ ^( ?+ I
  2.   props: {
    + i9 v  ^6 C6 w5 u  t3 O
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    2 w- ^7 G1 |2 y  r5 u' Q3 c! H& J5 c+ t
  4.     propA: Number,
    6 c8 }6 U1 W' [; Y: C
  5.     // 多种类型4 Z" ^, M' r  @
  6.     propB: [String, Number],5 H( W' j  k- {* g( ]" d2 h# q
  7.     // 必传且是字符串
    2 X; _6 I5 v9 T7 w3 _. x/ y. P
  8.     propC: {% m9 v, g% F9 Y" z
  9.       type: String,
    : L* t6 Q- u  {6 K  Q9 |5 _6 P
  10.       required: true
    - _! C/ U1 \8 g
  11.     },
    " w: q- v! N: @- U
  12.     // 数字,有默认值8 I2 c! J/ A5 X& G: J$ P
  13.     propD: {: j2 f; W3 |' C- q
  14.       type: Number,9 j4 P9 I# f# w
  15.       default: 100! @% \0 V4 M% L1 b2 m: x& P
  16.     },5 D4 L2 I' ^/ y' `: B
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    $ [0 {2 T" L$ p0 x8 t" {$ I
  18.     propE: {
    $ m  `1 I! W& Q1 K( M# r6 }' p
  19.       type: Object,3 n- b" X& A$ r, I3 I( h# j/ ^
  20.       default: function () {
    ! o; d' F, l# W3 W+ @/ @+ K2 A
  21.         return { message: 'hello' }" q$ q% `3 X% e: @: H
  22.       }
    & W1 _7 U- w9 G- Q0 {" f
  23.     },
    + e( q( E9 e4 ], c
  24.     // 自定义验证函数% e' U4 O8 y% |$ K. C0 _3 K' V
  25.     propF: {0 B9 l" d# s& x
  26.       validator: function (value) {- I$ N# @1 W# Z! @3 K  u$ H% r6 x+ t
  27.         return value > 10
    ' A+ w- l7 h; Z
  28.       }; b' G# o0 L1 T1 a8 l8 |" o
  29.     }2 H, O1 d# a, l8 ~9 S7 |
  30.   }
    7 ]- `  V  z5 e8 F
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    3 D8 I7 |' {( ^1 ~4 F
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件9 t5 Y- c# C" G/ L  }2 g
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
- C% m) O. K) P+ F" F9 C" X
  1. <div id="app">% |* J7 z! M1 I/ W& s* r5 _
  2.     <div id="counter-event-example">, {" h; B' v- V* ?, t7 v
  3.       <p>{{ total }}</p>
    / c/ |# S3 g1 W& \9 ], j
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    ; D! @7 F% A+ L
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>$ O5 ?% Y9 J7 q
  6.     </div>. S& z* s) E. V  i8 r
  7. </div>! y  v+ E) ?8 M; f$ b5 S

  8. 6 n3 ~* V7 r9 O3 D- h
  9. <script>, h, c+ F. {/ I" L  k+ f
  10. Vue.component('button-counter', {' x$ m; ~/ I8 Y$ p
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>'," M6 w9 e2 R3 b0 C' C  e
  12.   data: function () {
    4 a* A7 M6 R# o$ H, P6 H
  13.     return {
    6 \6 c# \! T+ _
  14.       counter: 0
    , |  Y2 i- _% G7 E2 t
  15.     }' i0 A5 @/ ]" ]4 O* A
  16.   }," ^6 }0 e6 a" q
  17.   methods: {
    & ?: W  T2 t& H+ c
  18.     incrementHandler: function () {
    ) s/ l0 B) P: ?  M) o
  19.       this.counter += 17 K, D! h1 u" h$ J$ t/ x. l
  20.       this.$emit('increment')* R4 c" z5 |2 z2 J) M
  21.     }
    3 m: j* b2 M1 Y0 w
  22.   },9 P! T; d, G4 n5 D; p7 a2 ^
  23. })8 \/ n; i$ P- H. N
  24. new Vue({) f. |2 \0 I$ e  P1 O
  25.   el: '#counter-event-example',
    + G- [6 L7 H0 h4 E' W0 v  D- T
  26.   data: {) ], Z1 H( \. V8 r$ Y
  27.     total: 0
    # n2 Y2 p2 q. E4 d6 D' N
  28.   },( z4 t, h6 f6 I  B  f$ v
  29.   methods: {: v3 j1 B! W7 g& \, P( ]$ M! A* B/ A7 f. h
  30.     incrementTotal: function () {3 I9 o5 F; _+ d  G( E
  31.       this.total += 1$ ?, x5 z# s: m1 ?9 m
  32.     }
    0 S4 r  n1 L, a
  33.   }
    # v' c& ^2 Z# Y
  34. })% t0 t; j7 z# z( H; G. q
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册: e' \0 D0 [. i! g* S' |
  2. Vue.component('child', {
    5 m$ [0 O4 X" W
  3.   // 声明 props
    ) V: X* J" w: A1 `$ T* f8 W
  4.   props: ['message'],# z7 P* ?% o2 G2 h8 {( ^
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    4 h# L0 M2 z) q) s* x
  6.   template: '<span>{{ message }}</span>'
    6 u$ h* T9 \3 M
  7. }). w. \: g% @+ T9 z  p9 L4 H- x/ q
  8. // 创建根实例/ w! ?5 z$ c6 P- N% y" k
  9. new Vue({& N$ d+ S8 e& Q( v9 I5 Z, G
  10.   el: '#app',, G' K4 @+ _$ t0 j. T4 L8 w( J8 s
  11.   data:{$ q2 s1 H# P# S0 ^
  12.     message:"hello",
    % y, i% S! f: _: `; s, G+ E  [
  13.   }: J+ \0 g6 `# `4 ~& D7 j
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    5 V! M5 S$ L) _% B
  2.     incrementHandler: function (v) {
    / K& n% t7 l, D) X& k: U# `" |
  3.         if(v==1){
    . r6 @4 W8 J5 p% f
  4.             this.counter -= 1& w0 Y3 W2 _  ?5 ?9 R% p3 `
  5.             this.$emit('increment',[1]); _% w/ c! Z1 c# y! i
  6.         }else{* t% P, M3 U, A! T" T/ Z) m
  7.             this.counter += 1
    5 |/ ~& Y, M* o" Z+ I3 W6 z: y
  8.             this.$emit('increment',[2]), I0 {2 g& r! [3 _/ \8 `: ?
  9.         }
    3 F0 y" z6 G' c/ [: Y: R
  10.     }8 i9 H/ Z4 e* n+ W- ~) s
  11. }
复制代码

# X$ c# q0 G/ V2 {8 E- w) R. z3 R2 X8 G$ m  ~1 N1 F  N7 J
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 16:17 , Processed in 0.115618 second(s), 22 queries .

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