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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

) c6 D8 P- k# C5 r
  1. <div id="app">
    ) l& z: \# W' b' V1 {
  2.     <runoob></runoob>
    8 n& x. g- W3 @1 i7 ~- w% U6 d" b6 Z
  3. </div>
    5 b. q) A8 u+ m( e& Z0 ?8 u4 ]. O
  4. 4 F, E5 b1 L* w% Q3 g
  5. <script>/ ?2 v2 Q! b* r! N
  6. // 注册
    : K  {) m  r) ~7 l
  7. Vue.component('runoob', {
    / o7 |8 \6 T5 r: K
  8.   template: '<h1>自定义组件!</h1>'
    . \* {, C! {* |. Z
  9. }); S0 N) e# b( h8 s4 ?$ Z9 c6 }
  10. // 创建根实例
    + G: Z7 k1 \' T5 J' ^( b+ o$ a$ n
  11. new Vue({
    1 D" x9 W7 x) E$ O, S/ q7 u2 b
  12.   el: '#app'
    & W/ k$ O5 Z! p* |0 u% r: b
  13. })
    & n5 A/ x3 K; J* `4 D: P" v
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
# q% ^3 x  g8 W& m) g' Y' R" D; U
  1. <div id="app">
    9 h8 ^" a, I9 ]9 X( `  M
  2.     <runoob></runoob>% G% R" a( `9 N5 u+ h# F
  3. </div>
    2 h8 i7 n9 I0 V! `' h1 F5 y% O

  4. # c. @& S/ e/ v5 M5 @; h4 o9 A
  5. <script>& H: o7 b: |2 U9 R/ [  d
  6. var Child = {8 c# {0 Z% S' W2 }. `; U3 H# o
  7.   template: '<h1>自定义组件!</h1>'. I  X' w3 f4 C6 Q1 M
  8. }; a; J, n' v8 G! [5 A8 O, |; e

  9. . F6 a; r! t, C0 ^
  10. // 创建根实例7 m2 @% Q, E, T$ L! p9 S2 D
  11. new Vue({$ S& C% |0 U# g2 l% U7 g( @( r
  12.   el: '#app',( @8 I3 Q1 e+ L8 U/ K
  13.   components: {& h3 v1 j  G6 x8 s& G
  14.     // <runoob> 将只在父模板可用
    % t! p4 ^. c8 @% O+ w6 A9 h
  15.     'runoob': Child5 u5 T  ^' i' e) `/ l9 _- ]0 f, W2 I3 n
  16.   }3 p: m! q3 l; j
  17. })2 t2 b8 f* C5 K' m& W, r
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例, I+ |1 |7 |; \3 L
  1. <div id="app">0 w- B% X0 C; _# W
  2.     <child message="hello!"></child>
    0 z% [- s0 S1 e6 l7 H
  3. </div>
    8 v. r6 _# y; N6 D
  4. ' a  z% j& u3 d. g, {  u
  5. <script>( W# O2 ~( b& Z+ ~
  6. // 注册
    2 f0 o/ f; w  G( ^9 y0 @& V
  7. Vue.component('child', {- i8 O9 S/ [9 a  ?1 }; w
  8.   // 声明 props
    - ^. Y, b# c# A- o! M( m
  9.   props: ['message'],
    9 b# X3 e- ?5 S
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用" d4 D* \) q7 l' S1 ?% d
  11.   template: '<span>{{ message }}</span>'
    # W7 |. c* j& B, |9 z7 m8 R( Q
  12. })- O1 j4 Q) f3 U) D  l- [# {0 _
  13. // 创建根实例7 Y- u/ u# w+ G, c: @% t
  14. new Vue({
    0 z7 L4 K; p% J) A; e
  15.   el: '#app'1 g' I9 }5 {) B4 z$ I: {
  16. })+ j$ p- p% @' H4 L) x" i. A
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
) S3 l6 ~9 X( j
  1. <div id="app">2 o; P* e0 D+ |/ _, p% e
  2.     <div>
    ) [1 S$ c0 k. d; W
  3.       <input v-model="parentMsg">7 J5 N9 a' a' O  Y2 r1 A
  4.       <br>
    2 d- }' ^, F8 z/ o2 s! y& z
  5.       <child v-bind:message="parentMsg"></child>
    0 K1 _. I/ C( @; n8 y
  6.     </div>
    ) n5 U" I0 X$ C& K
  7. </div>
    8 v8 |' k) m2 E1 G  j7 i3 O
  8. * V) P0 f. C: F8 Q; ~: w" x) `7 f
  9. <script>
    ! E( X. A3 @3 ?* G! I4 t; s3 P" ^6 A
  10. // 注册) v) |/ U7 S: n1 s$ w+ I
  11. Vue.component('child', {
    * h0 {' v' N; ], ~4 e5 c0 U
  12.   // 声明 props/ }% X8 k8 {& o& H0 C0 X: E- G
  13.   props: ['message'],% P* C1 H; c# ~# V- P/ T
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ! l  q3 N. i$ }) }# ?. w4 T9 y7 m
  15.   template: '<span>{{ message }}</span>'
    0 B% f/ m( o# c6 _) }' o) c
  16. })
    9 i' n7 [( J6 |
  17. // 创建根实例4 e+ |+ f2 s. y0 z0 ?' Z
  18. new Vue({" j6 _5 p1 c8 T4 T' z
  19.   el: '#app',
    7 H4 |* c4 |% H1 K% n: `
  20.   data: {
      d6 [& ?& v# r
  21.     parentMsg: '父组件内容'
    , D$ G! e+ z6 e% _+ B
  22.   }1 O) I+ U3 Z. z5 p( k8 u4 o
  23. })' K0 F8 u3 t# F: R4 N
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例- P/ H4 F% W$ n2 z1 T
  1. <div id="app">5 X+ y4 N2 ^$ `9 o
  2.     <ol>
    + n- q2 a6 J  a# P  _
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>* h& M+ u4 ^" ]% _: U
  4.       </ol>
    & V+ [; R; T+ R* m3 s: P8 {7 X
  5. </div>( ]9 W# i2 K' w7 V% G) P

  6. ; |- L7 X$ M4 z3 Q  G+ t
  7. <script>* R$ v4 f. T. b1 h4 d
  8. Vue.component('todo-item', {! X$ V/ V+ z& G' i3 s
  9.   props: ['todo'],
    8 w' p/ K, O/ `9 y3 W. V6 d, Z
  10.   template: '<li>{{ todo.text }}</li>'9 N) ?& v5 y1 Y: }/ F9 F
  11. })- `6 v& o, S+ w) y
  12. new Vue({
    ) q- ~4 f, y' d' o
  13.   el: '#app',, ~3 P! a2 g& o3 r: l: x
  14.   data: {+ B/ {* }  \! O1 p3 o* C! \
  15.     sites: [
    # K! X: b' l. H, {7 @
  16.       { text: 'Runoob' },6 r* S/ T6 H! |+ |. t
  17.       { text: 'Google' },
    ! v, W/ v! ~# P# G3 V( i' U: P5 m
  18.       { text: 'Taobao' }/ Z3 b# T, D. I# W( g1 Z
  19.     ]! I" ?4 u7 S( A, F" h$ r. v
  20.   }
    ( `2 g' o( R3 Y2 W( B
  21. })' {7 k$ M4 V& h0 S( T
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    : L, _" a3 ~0 @! t$ n4 w- e
  2.   props: {8 b# I1 S" ]2 f9 e
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)+ v) u1 S" S; M
  4.     propA: Number,: v0 k) k0 M; I+ R
  5.     // 多种类型
    ! \1 I2 M* |/ j7 L" S
  6.     propB: [String, Number],# _6 g2 @; G2 w2 d  i6 a
  7.     // 必传且是字符串
    # ]/ e) I" J+ P& o+ ]( p7 H
  8.     propC: {& f& [. R2 z* K% Q) d
  9.       type: String,0 G" {, y1 T7 |: h
  10.       required: true# ^. b' V- f6 g, ]
  11.     },& U7 E& A5 d/ \& Q; u
  12.     // 数字,有默认值0 L/ F' C3 m! b8 O
  13.     propD: {
    : {, u3 F) I# q7 V$ k! o
  14.       type: Number,/ d; O1 j- X! T: `  n+ l/ v
  15.       default: 100
    : Z4 i% M' v% X, u6 e
  16.     },
    " Y5 X, ]+ g+ b- I
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    ! _7 |" X7 Y5 ]* h$ @' [: _4 v* E
  18.     propE: {" v. h) ~; j, C- l: p( _  P. n* @
  19.       type: Object,
    - X9 P; \  h" `& f
  20.       default: function () {
    0 s  \* [; R1 t
  21.         return { message: 'hello' }
    2 r# ], E! u  g; q9 b4 Z
  22.       }& A1 Q5 ?: b7 a  a* l! m
  23.     },/ g' q, {! s: D
  24.     // 自定义验证函数
    5 m( p% s0 C1 [
  25.     propF: {$ i: ~; ~" {2 D- K
  26.       validator: function (value) {
    & s) h8 Q3 ]% [3 m+ z7 P! p# y
  27.         return value > 10
    ) w- m8 X) p- w1 V8 ?8 {
  28.       }
    - K. i! G0 j1 h% `2 Y% i. O
  29.     }
    , w8 x& G: ]1 D. X, ]+ ]7 W
  30.   }
    & C) `1 }1 n: r; r8 B
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array+ Y: S7 |; c7 f
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    $ Z1 s4 n" e' H- S  i, Z1 O
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例" ]6 [( L; U5 {' [
  1. <div id="app">$ D. S! I+ _3 F7 z2 T2 I- a0 M
  2.     <div id="counter-event-example">5 p* n. T5 W4 c8 M8 O9 F' U% O0 Q
  3.       <p>{{ total }}</p>6 r$ J9 z+ m) b# q
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    9 @; s! o' K1 {8 c
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>& p* n. b, @; H$ K. N- z
  6.     </div>
    7 E/ Q8 ^1 a, V/ ?1 F
  7. </div>5 y' C1 }- m+ }/ P
  8. ( U3 s! Q: G* G0 w
  9. <script>
    ( |3 K6 l6 i9 h2 ~  G6 C& t2 n
  10. Vue.component('button-counter', {5 a/ M$ j  G2 G8 X6 J3 `! _. ?+ A/ i
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',+ n, E  X1 m. U9 t6 J0 N+ Y
  12.   data: function () {
    3 u9 h6 g( H  [' _
  13.     return {% H1 b- j! h% q; o9 v
  14.       counter: 0
    3 F" ?% Y7 d9 }/ W- }. k
  15.     }
    " I9 f4 N- z  T0 O, z0 Q2 [
  16.   },
    4 b! P9 ?4 W" r, P$ i: f' t
  17.   methods: {$ R# ^' F  z/ k# G' `7 G
  18.     incrementHandler: function () {# m/ K9 l* o& K" `" Z+ W" u
  19.       this.counter += 1  t, ]( ]/ t& ?2 h
  20.       this.$emit('increment')
    4 U, w" f. B: }
  21.     }! l9 Y1 P0 W+ W' U' L
  22.   },1 s% B) F# I8 f1 k: l, u  p% T
  23. })
    4 I9 g9 t: U( t
  24. new Vue({0 k$ t+ d$ d0 S* n
  25.   el: '#counter-event-example',
    3 @# }/ u3 N7 }1 W7 T" x. j
  26.   data: {9 B( z2 ^* C5 F1 u5 ]! P+ k
  27.     total: 0) o  z* G7 b- k2 z1 Z
  28.   },( I0 S' ]0 p0 ^) T- I: W% g% p' M. L
  29.   methods: {/ I* D1 S* j% Q9 h0 u; Y
  30.     incrementTotal: function () {! }, P0 I6 q0 J
  31.       this.total += 16 U5 n; X# r6 I8 N7 x
  32.     }4 X7 s: g, z) ~8 o  H' @
  33.   }  Q/ I% F5 Q3 f9 p2 s9 ]$ F
  34. })
    - }% k0 N, O! `8 c9 _9 S0 i
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    : y1 |0 ^! @) x" k6 ~
  2. Vue.component('child', {
    " A/ t# o9 D1 }% M4 _
  3.   // 声明 props6 l% \* t  ~5 A: ?6 e8 y5 J
  4.   props: ['message'],
    + q2 W' y$ D( A+ \$ Z$ Y
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用# v' t- r6 Q  B
  6.   template: '<span>{{ message }}</span>'9 D0 N4 K, s8 c
  7. })
    # r( k, a9 `, N1 \# D
  8. // 创建根实例' d* B5 |5 M1 ^# O
  9. new Vue({' q% @% I3 z% I( P. G1 I
  10.   el: '#app',$ ^! H4 Y  @% {# ?3 |+ [
  11.   data:{
    & ?: m2 V" `/ I5 o% W
  12.     message:"hello",+ q' ~9 C2 z2 Z& \: v/ h  |8 ^2 P
  13.   }
    % c% R9 b# i; {1 ^0 K9 q, F
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    : @( h7 @8 W/ D; w7 C2 u2 J
  2.     incrementHandler: function (v) {
    ! y5 C  F  g( o: s, X0 j& S& d
  3.         if(v==1){
    0 l1 K  p3 @/ u4 M  T# D- q8 ]
  4.             this.counter -= 1- a$ I/ I* Q% S2 q$ U* D9 {2 K: B
  5.             this.$emit('increment',[1])
    ' W4 p; V! L' \7 W
  6.         }else{+ @& T6 O7 P  P1 N5 r4 z, n$ j* |( ~
  7.             this.counter += 1* U8 y9 ?$ N5 g$ p
  8.             this.$emit('increment',[2])1 M0 }( a, ?6 x
  9.         }
    ; X2 [: Y1 j- J0 l8 r3 \
  10.     }
    # c8 G( W6 {1 C5 f
  11. }
复制代码
, z2 u+ ?. V# Q7 G4 B
# p; x: L/ b9 Q! [- z
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 15:56 , Processed in 0.117883 second(s), 22 queries .

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