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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

* Y* r1 j. W  {- B; J5 R
  1. <div id="app">  A, \8 V+ k' |8 Y2 z6 T
  2.     <runoob></runoob>( R! A1 \& }6 q; z! o3 u9 @& \1 T7 h
  3. </div>9 s/ y0 W( W0 Y
  4. . D+ I& W5 b3 F9 _- R
  5. <script>
    ! }! G8 j4 r$ H( i: ]
  6. // 注册5 Y: t. b, \& r/ f% E7 j, x0 M! s
  7. Vue.component('runoob', {
    ! g/ Q- w: J, a& r+ k  G
  8.   template: '<h1>自定义组件!</h1>'
      y* `: [) r3 k% w
  9. })
    : K5 X6 u4 ?5 o$ ~% I) f  {0 d
  10. // 创建根实例: l. }+ {0 m- j1 D
  11. new Vue({
    ; Q) l- J# X0 x
  12.   el: '#app'
    4 B* g- r) e$ \
  13. })5 t  o- k6 X1 D7 w5 S! X
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

' c  l9 y: T2 f5 k
  1. <div id="app">
    9 n, E7 k& F" g& ]
  2.     <runoob></runoob>
    ' Q) j/ g: i) |; `& h5 L/ S3 F
  3. </div>
    4 b0 [* B% r0 h
  4. $ j& q0 n( q& u- X, G
  5. <script>
    5 D5 B% C+ ^5 u3 L
  6. var Child = {9 ~( E- h% v/ v$ C8 Q$ k1 E+ e# C
  7.   template: '<h1>自定义组件!</h1>'
    2 M( }! X( u/ K9 |4 q+ T+ z
  8. }
    0 m8 E- ]0 W1 O# `, e- F4 Y

  9. 8 q1 ?# T# p: R& r+ V$ ?
  10. // 创建根实例( f5 ?. S) ~1 H2 n) a6 {# v
  11. new Vue({! c3 O. t5 Q2 R5 e' `/ p
  12.   el: '#app',
    1 a/ S, C" F  ]8 U- q5 S6 d
  13.   components: {
    8 O1 H2 A) o# v; I
  14.     // <runoob> 将只在父模板可用
    8 T7 Q; O3 X- N$ k
  15.     'runoob': Child
    ; L% Z& t% ^0 Q
  16.   }) g  l! B' d+ K# P. h+ _
  17. })
    : `9 Z2 C% p( f5 d0 v& _; x% \8 z
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
9 e* I4 k4 x8 }6 p" W4 S
  1. <div id="app">
    ! _. t1 {8 S1 n0 E1 q3 E
  2.     <child message="hello!"></child>8 w+ ]# j0 ]' O- [  n
  3. </div>
    6 v$ j" v$ A+ V5 t
  4. 7 e- T' a& h/ \
  5. <script>1 ~& e- e9 V8 Q* C
  6. // 注册
    + w! a% ^0 G! h/ W6 b
  7. Vue.component('child', {# u1 r( v5 s/ U2 Z8 t
  8.   // 声明 props
    . W0 j9 O9 U% `, }+ F0 I0 @( [
  9.   props: ['message'],
    8 c$ ?/ C! u9 ?1 e  n+ k' ~
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用9 E/ d+ V1 C2 [7 n; R4 V
  11.   template: '<span>{{ message }}</span>'& g7 W0 D. _3 ]8 O6 z
  12. })
    . ?. o& ~& [" S. O0 O
  13. // 创建根实例
    * E- A) A9 q8 N; M0 W( ]
  14. new Vue({: q, s6 x" _8 _0 }
  15.   el: '#app'
    * d; }7 z, `5 _7 p
  16. })$ B9 T) v! d. f" ?( c
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
4 p( U! m& I+ K  `5 c1 Q
  1. <div id="app">2 \' S' V! u# j, j
  2.     <div>
      G! t' |) d7 {5 B! B
  3.       <input v-model="parentMsg">/ `3 w+ \, t7 P: W+ `; f; M
  4.       <br>. i, R+ v3 j( R( O* J  C7 o
  5.       <child v-bind:message="parentMsg"></child>' s, |" ?! Y4 o3 r, ]
  6.     </div>8 v* _7 c- C0 n0 a
  7. </div>
    : i4 B. F; ^) V# w
  8. 8 n! _0 d1 [% v* R" H
  9. <script>4 W0 W# W* T. H3 k  D) u  D6 x
  10. // 注册
    / ^- Y% w) G# E# Q0 b2 `
  11. Vue.component('child', {
    ! u' Y4 |: W4 n4 C
  12.   // 声明 props
    & X* ~% O8 a5 i( i" N+ R
  13.   props: ['message'],* E$ ?* l( ~4 Q5 h0 N; W9 ]
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    & K. v* u: g2 S3 \  j
  15.   template: '<span>{{ message }}</span>'6 j4 C. ^* O3 s" o( H
  16. })$ {" z/ |0 b  |, }! s
  17. // 创建根实例
      g* z6 P! T6 s) A0 A
  18. new Vue({
    . v( n: h- ^) j$ p! c
  19.   el: '#app',+ u( X+ {/ L: |* ~' c$ J
  20.   data: {3 t5 i' C8 C( d
  21.     parentMsg: '父组件内容'8 d2 i! S# G6 W; F5 [  k, }
  22.   }
    9 J2 X1 ]8 r) K  Y2 M
  23. })
    ' q' q1 T& g: }* k8 v- {+ i, y
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例: B2 F- L+ C* f( B/ u
  1. <div id="app">" G# v4 i4 ?* F; @& z2 I2 g, B( ]
  2.     <ol>) g) g/ w% ?' ?/ z9 d$ k0 ~
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    6 k0 z, \  B/ V+ A
  4.       </ol>: }' [/ o& v# R9 g7 I' z
  5. </div>$ A9 q- \. W% ]$ F& C& B8 L8 \+ p

  6. + c3 `2 `0 e0 {2 E
  7. <script>
    $ Y: I# F0 P* h9 L* {# v" P
  8. Vue.component('todo-item', {
    ' v, E) Z( x1 H- i! a5 C
  9.   props: ['todo'],; d) C/ X. @& B: Z2 U5 `3 u* |
  10.   template: '<li>{{ todo.text }}</li>'
    / B0 C' F. ~, {( f" v
  11. })
    ( m: f) r9 J8 a4 f% j" `/ ^
  12. new Vue({
    * b; a" [8 W6 L  s. H3 s: Z
  13.   el: '#app',; w( n. W3 J  ]1 T. W# w( p
  14.   data: {$ l2 L, A  B# V3 W* I+ D3 @0 ]4 m0 k
  15.     sites: [) S1 g) s/ J; t) N" Y$ j
  16.       { text: 'Runoob' },7 x/ s. @. a, j0 k
  17.       { text: 'Google' },
    ; k1 a( h5 p0 N1 j
  18.       { text: 'Taobao' }& c2 \! O+ d$ c# g# n7 i! C8 p9 S
  19.     ]0 ?' `9 v  ?  h6 U
  20.   }
    2 N! ^7 d! L' @
  21. })
    - ?. B0 o, g! D; \& q" o
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    2 g" i. c. D9 j9 I4 v, W
  2.   props: {
    + W; R2 @# g  b/ x
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)' R6 |5 b0 r; E" U4 E" C
  4.     propA: Number,
    * e/ P* L. o+ f' t, _0 T7 e
  5.     // 多种类型* h9 n0 W# W! M* Y) u7 T) O
  6.     propB: [String, Number],
    . |  ^" i/ G" `: y( \: A
  7.     // 必传且是字符串- E( E# F/ o/ M- i3 h
  8.     propC: {. X: \! v3 o6 Q
  9.       type: String,
    # M# N2 x; X2 E
  10.       required: true
    8 A1 U- ^+ z# Z3 V3 p% Q( }
  11.     },  p2 p9 A( ^. T3 D# j- ?
  12.     // 数字,有默认值
    5 F  I8 @2 H. z
  13.     propD: {
    $ l9 p3 ]1 w# M# A, H
  14.       type: Number,
    , o' }: i% r  f& d* F
  15.       default: 1009 [: q; c& g; C& b% _, J
  16.     },
      {$ {' P! X5 p  c; z5 U/ L
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    6 _" G  G+ `; x$ K% r: f' y
  18.     propE: {
    / b1 i+ L) x3 i* k) B) Y  g
  19.       type: Object,
    , O: ~# f6 m7 D* U. |
  20.       default: function () {
    ) t2 `5 f% C/ p/ \, f
  21.         return { message: 'hello' }
    5 t- p8 j3 M* y: Y$ s
  22.       }8 {1 O$ y, d# p8 t& C3 X4 u# P! _
  23.     },1 Y7 W* W5 p/ ]+ f9 f, I$ Q3 p
  24.     // 自定义验证函数
    $ C- ]/ D: v  x5 s- P* x; B! C9 l5 p# {
  25.     propF: {
    # o6 c7 d2 ?/ {
  26.       validator: function (value) {2 v# Y# N$ ~4 s+ J* n
  27.         return value > 10
    # M8 U  p' j: r8 D& y
  28.       }# C: M' A5 z/ g9 b0 e
  29.     }
    . _# y2 ]0 m# J% T& H$ m
  30.   }( M( \! c6 r% h: ^, O# B# X$ l$ n
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    7 R1 Z6 q3 ~8 S1 Y+ U8 }6 `" {
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    * A/ B" x4 X2 q$ a: v% g
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例1 f2 m4 x+ z' [5 @$ n3 M
  1. <div id="app">8 I$ m, d* m% x  x
  2.     <div id="counter-event-example">
    / e: U0 }9 G$ H1 E' d9 a
  3.       <p>{{ total }}</p>
    : Z% i1 o2 a# _) {2 k1 P
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    ; U% X" ~7 _" g7 Y  r
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    * j$ j6 i1 r6 Q( I" I$ |9 Z! V* A
  6.     </div>
    8 p% ^$ D: v4 g4 u$ d: ?, ?. ?8 s
  7. </div># a( f7 d0 p+ n0 q: F
  8.   D3 {/ d, x/ L3 {5 i
  9. <script>
    1 n2 B9 {/ y9 I# t, {/ C4 a
  10. Vue.component('button-counter', {
    * D( k7 V6 L; n9 j+ e: E
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',- d) o/ Y( a: r. u
  12.   data: function () {& `. o1 y" U4 g( ]1 q
  13.     return {% F1 @/ W" s6 g+ X
  14.       counter: 0
    0 n; Y9 M' I" u' L
  15.     }! O9 A" r+ m; |- R: }7 ~
  16.   },
    + A/ w8 u/ A+ C" G
  17.   methods: {; d) u2 J. g' J- L. ]
  18.     incrementHandler: function () {5 `' C+ i8 U- Q/ f- F5 R! s
  19.       this.counter += 1% c# v7 V8 q2 x
  20.       this.$emit('increment'). a5 N0 U$ y; n$ [
  21.     }
    : \8 T2 }. C2 J& a
  22.   },
    ! f5 K) e/ J2 J0 B
  23. })# T+ C1 O. e8 v% E" `1 H
  24. new Vue({8 U# d; R5 ]+ I7 A* g' E
  25.   el: '#counter-event-example',; u+ o# X, m# F0 E8 x- N
  26.   data: {4 _( @3 Z# M5 j8 o" y. G/ c
  27.     total: 04 w' U9 Y# ?, x) ]: z4 B
  28.   },
    7 N6 r+ X% {4 H( T: \7 @& T) ~
  29.   methods: {% ^' u! C, I/ n4 l# ~
  30.     incrementTotal: function () {, `  p! r+ B( J: K8 O7 P
  31.       this.total += 1  X  M* j4 S7 l, j6 x$ A- F) M$ s* [
  32.     }
    2 M; j/ N' V- p: e
  33.   }
    8 `7 Y& m6 J3 W+ v5 ]6 j
  34. })
      A+ v# h8 ^7 q5 L
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册6 e8 M, C6 e8 ]- s
  2. Vue.component('child', {. A$ m- |4 D9 J  _7 ]
  3.   // 声明 props8 S4 J0 U( D" O  \; s+ ^
  4.   props: ['message'],
    ! p# K/ Q8 h/ l/ u
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用% w7 ]# Z. f% _" M  \
  6.   template: '<span>{{ message }}</span>'
      e5 ^9 p6 b  `7 e8 X3 W$ X
  7. })
    + E$ n0 [6 k1 v2 j+ O; Y
  8. // 创建根实例8 p! e1 X) L$ ]
  9. new Vue({
    4 A% H5 t1 @0 v5 |3 N
  10.   el: '#app',
    $ q; ~2 E7 U" c# g4 }
  11.   data:{
    . Z3 d  z& O/ x: {8 m+ n, a( L
  12.     message:"hello",
    1 a) @# B8 u+ a: a. M6 }2 l
  13.   }
    ) z# Z# t; U; r  X% g' C+ O
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    , @+ Y$ k! _$ U4 e2 |( R# G
  2.     incrementHandler: function (v) {
    ) {4 n; ^! y  u8 j+ M
  3.         if(v==1){/ P6 D$ Z# d, y! w0 I2 ^
  4.             this.counter -= 1
    3 |3 \& }# z0 G, a; ~
  5.             this.$emit('increment',[1])! L) x* {8 s  f& r" ]! A
  6.         }else{
      i3 o6 g( ~  \  R! `. a
  7.             this.counter += 1# H+ R0 q) v( w: r3 z, H, A3 C
  8.             this.$emit('increment',[2])
    4 d9 v/ ]; m, q6 {" y
  9.         }
    4 {& [8 ]' |" b0 G
  10.     }) q  W# u1 H7 e0 X, W
  11. }
复制代码
  C% S) S) G; j2 @' z9 h0 ~
8 [6 l! H: g! b& {/ u
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 21:00 , Processed in 0.116838 second(s), 23 queries .

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