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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

; P  U) L  ?% ]3 z4 b" w
  1. <div id="app">' [$ W- c8 f) {5 r4 z  h9 N- w% C
  2.     <runoob></runoob>
    8 Q. t* M- K- O3 n4 z- O) T+ [
  3. </div>
    ; G. e1 y8 y1 c% z5 V

  4. 8 s& G3 x& {8 B* ]
  5. <script>
    ( e) v1 v9 s6 o+ B3 v. J
  6. // 注册
    ' [/ O3 _) _- f
  7. Vue.component('runoob', {
    - S& O' r# o" \( [6 }2 y$ n
  8.   template: '<h1>自定义组件!</h1>'& h; y! a! W0 {  t; [1 k* D
  9. })
    . |$ `  b+ F( ]: V7 E9 ~0 i
  10. // 创建根实例
    4 |. f: T; T* ?+ k
  11. new Vue({
      X! v" z; e' f  e# r
  12.   el: '#app'
    ! w5 x% P$ t: r# n. y3 d
  13. })
    9 |; C' V* ~% G. Q
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
! K1 O: m# D% \7 y6 e* s
  1. <div id="app">
    7 ]/ k  C7 P5 k' z# v
  2.     <runoob></runoob>
    1 l0 j, U' W% _: \& d0 K3 p
  3. </div>
    9 g: s( P& W+ D& \8 o4 Z' O, @- c" n

  4. * t3 r7 b/ E4 @; W6 R2 }! _
  5. <script>
    & y  v0 I% T! j1 m
  6. var Child = {0 e* `1 z, I- O, w0 n7 X
  7.   template: '<h1>自定义组件!</h1>'
    0 ?+ k* k3 J" u$ J6 B) z
  8. }9 T, [& U9 L& S' `: k  e
  9. ( ^* Y1 X5 A6 e$ j1 b3 g
  10. // 创建根实例7 [& c& m2 x% e' u) M
  11. new Vue({7 q" w+ O5 A  P* [. s* U
  12.   el: '#app',
    1 x4 Q/ K  i" X/ A3 N
  13.   components: {
    * z% U6 W# Q; d( m
  14.     // <runoob> 将只在父模板可用
    0 `  B: t4 y4 y1 h# |
  15.     'runoob': Child
    1 H; g, H" b9 m6 E
  16.   }
    1 F) J7 G0 H9 ~
  17. }). [1 z$ p; u9 K% {7 V$ {
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
! j4 M' Z6 \* O  ^( R( z
  1. <div id="app">: C" V2 |6 P1 H
  2.     <child message="hello!"></child>
    1 Q" p0 Q# V; O6 h7 Z0 ^
  3. </div>/ Y1 L4 s* o# m  U2 k0 j+ c+ R' h

  4. ; z! b) P  j" r2 n1 J
  5. <script>% v6 f  D& ]3 ]! n  }- M8 A
  6. // 注册$ A/ W& C3 b" T6 ?
  7. Vue.component('child', {
    % {6 ^/ T4 f/ t
  8.   // 声明 props  ]: q% ^( S  ]
  9.   props: ['message'],
    ' Z- d( m$ Z; w3 M5 K
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ( \! q( T* F1 |$ w- X. y1 d
  11.   template: '<span>{{ message }}</span>'1 A3 H2 M" \' F
  12. })
    9 M$ T+ s  J7 W) Y3 p4 B) }0 g
  13. // 创建根实例- [# |! P1 d' B5 k/ ^0 C$ g
  14. new Vue({7 G  n* a( z$ ~8 Y6 P
  15.   el: '#app'
    , Y! e6 D/ {* b& ~" H/ J$ A
  16. })
    . U9 `8 O: {8 e
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
" a9 c! l5 U) F$ S
  1. <div id="app">
    5 C0 z; ?# k6 F) D
  2.     <div>( Q( h( g0 @2 J5 Y1 L
  3.       <input v-model="parentMsg">( F0 K0 ~7 e+ n3 n
  4.       <br>/ u$ o; K, X- W, S4 H
  5.       <child v-bind:message="parentMsg"></child>
    $ J0 f" L7 }4 k% E1 m
  6.     </div>: T1 J' p5 O* [; A' ^3 ]
  7. </div>
      r- H8 u- X- Q7 w! z+ ^
  8. ) {3 v7 `: z( B! z
  9. <script>8 r- f) D" h0 f5 I4 I1 X
  10. // 注册( N) F1 Y5 ]6 Z0 ?: X
  11. Vue.component('child', {
    / [; U* W/ _. _1 O: C$ N( h/ G
  12.   // 声明 props& n5 s/ \$ W, l5 I! k
  13.   props: ['message'],
    % i+ q; n* s7 o9 J1 Y$ h; g
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用' _  M. Z7 f2 |+ D( U
  15.   template: '<span>{{ message }}</span>'
    7 j4 }/ o5 s6 u! {7 B
  16. })9 \7 j# b9 F6 @1 k. k# [8 H
  17. // 创建根实例8 Z& r' a/ L: X2 v" ]5 E! `
  18. new Vue({; e  [* R8 K% N
  19.   el: '#app',. M% c* d, m7 F" \( {  W# O# m
  20.   data: {
    / s1 T8 D: e- s, B
  21.     parentMsg: '父组件内容'
    2 J# D. P; y  [$ y+ h
  22.   }& q7 n; l0 I9 p& w" p
  23. })
    4 L: M! V7 k; v  x  P
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例8 ~1 Q9 g$ x1 e  f( |' r! g1 i
  1. <div id="app">
    1 M3 P; }3 U( T) L; X. Z2 o
  2.     <ol>
    6 q9 x4 c7 g* W/ C5 a
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>1 F5 B( d% Q' i7 P! _
  4.       </ol>
    6 a! c" K  u) m- ^, p
  5. </div>
    * j0 [% }9 j$ B

  6. 3 K$ @7 t# C" x- H
  7. <script>
    - _6 X$ i# l3 ^$ J# o, o: X' P
  8. Vue.component('todo-item', {
    8 ~" E/ q& `/ W7 ^) z
  9.   props: ['todo'],6 G7 l4 V1 E: [/ }' j( @7 e7 x; g
  10.   template: '<li>{{ todo.text }}</li>': A0 H- C% C! Z
  11. })5 R) b' \2 D) }  F, e% }6 ]( j
  12. new Vue({  D  [9 M( \9 o+ o! I. Z5 Y
  13.   el: '#app',' g: K, \2 p. k5 y- P6 G/ s! l
  14.   data: {; n6 ~( }/ V/ T2 s! V3 O# u
  15.     sites: [
    4 X. ?9 s+ R* c& O" ^. W) Z( n' m
  16.       { text: 'Runoob' },. N' _" J, ^  y; M
  17.       { text: 'Google' },
    ) J2 g  s, }- }6 h4 v! l* \
  18.       { text: 'Taobao' }
    ! i0 |+ y& c8 Q9 K1 w: U
  19.     ], W; |$ S0 H# z; {+ h! V
  20.   }
    ; r. V7 H7 e$ r7 o
  21. })
    * k  x8 G! t1 v4 z/ u
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    2 \" K& B( @' Z3 O
  2.   props: {4 e# ~9 y0 T4 N# K5 }5 |7 s, I/ A
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    ! H5 h$ I7 ^+ k' i2 h
  4.     propA: Number,
    + a! A: S( q( j! r1 j& p  L2 J
  5.     // 多种类型7 |2 s; s' O9 ?$ T. G
  6.     propB: [String, Number],- Q' S: K  O& B5 y, h
  7.     // 必传且是字符串
    4 t8 f4 Z2 |3 l  N
  8.     propC: {
    1 U; Z% Y& Y% _9 b0 k# o
  9.       type: String,: H! l+ P! y/ D
  10.       required: true7 h9 B1 E/ _5 R' ^5 i3 A  _
  11.     },
    / u/ ?$ s/ x7 h. k0 N9 E
  12.     // 数字,有默认值! b/ k- c$ k4 S$ j9 |0 g& S
  13.     propD: {8 _1 |9 w# y  x8 h) F, G  s
  14.       type: Number,
    ! t* I5 }, v0 V# P; O5 `' E6 u
  15.       default: 100
    9 E( f. t6 u" K% Y! A( p* F) r
  16.     },
    $ v$ d7 Q& `- Q* D/ z7 z- l( C
  17.     // 数组/对象的默认值应当由一个工厂函数返回4 V4 [. W' V3 B5 w7 u
  18.     propE: {
    ' U) m% m: U8 J: @) A# S  S& g$ P
  19.       type: Object,
    3 n- c( A# D8 h! Z+ `8 D" o+ ]
  20.       default: function () {  s6 d3 N# U7 t6 t
  21.         return { message: 'hello' }. i7 n5 q+ f: S& l% K, _& e) Q, N
  22.       }& o. v8 K3 y* z' c4 }
  23.     },  q6 O/ @0 V( ^$ Y0 y2 ?4 \2 g( S
  24.     // 自定义验证函数( K* P- A, w9 D9 d: |
  25.     propF: {0 l9 y. c9 ~; {% N9 I9 E
  26.       validator: function (value) {7 I: n* [$ H/ d/ K
  27.         return value > 10
    ' l$ y+ a2 d; t# d3 o$ o
  28.       }9 s/ n  d2 k% A
  29.     }+ N& `. _5 k0 J
  30.   }/ v9 r- b; c% C8 j  L, n2 G, E
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array# U. D6 o# t, n3 t/ k# E
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    5 |9 O: v3 h' q" a* ~7 E
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
. Q9 _( `- v5 @
  1. <div id="app">. D. Q) u5 _4 l
  2.     <div id="counter-event-example">% b  h" H+ ?) j. K- E
  3.       <p>{{ total }}</p>( J! m" b! w' y  i. {8 A
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    2 i& U7 o8 x/ C4 W9 H* Y* D( g
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>0 x% J" h  g+ W! r9 N6 O' @7 d
  6.     </div>( x" C  q3 i* N. Z3 w; F+ U
  7. </div>
    7 r( |* B! S# W4 e$ G8 s5 S; k

  8. ) z4 n8 a; e, Z
  9. <script>
    ) h% T/ Y& {  ?1 J2 B+ x+ ^# w
  10. Vue.component('button-counter', {+ J0 {4 Y; Y* I' B% {5 q
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',; @8 E4 K# D. H( B" L. \3 D
  12.   data: function () {. j: e, e: _: P
  13.     return {$ X; R8 B3 N- ]- v5 Q
  14.       counter: 0, \% [9 T6 K4 ?. F; o
  15.     }# g$ c( \( [2 `$ J
  16.   },+ _6 V9 H6 H, {& H0 O4 D% Q0 q* f
  17.   methods: {; w) i0 j/ u$ X* E- W( N6 z5 V
  18.     incrementHandler: function () {
    : f2 H) ]3 M* v1 Q$ Z: d
  19.       this.counter += 1
    - t2 ^1 W. T; p7 z0 u
  20.       this.$emit('increment')/ r7 o% [/ k5 x7 a# [; i  M
  21.     }8 |" P- E. T  P, _+ ~* }
  22.   },
    / H0 R+ D1 x" }8 n* g8 v2 m
  23. })
    + @) L4 M4 W# @' S" S" n3 n
  24. new Vue({0 f- k6 Y) [+ I0 D
  25.   el: '#counter-event-example',+ }6 F2 d4 S, y( g" z
  26.   data: {
    0 V9 ?- Z0 i, e9 m
  27.     total: 0
      t9 O' P+ u: C9 b" C& K+ C
  28.   },1 p+ m7 B" T% b8 s0 V
  29.   methods: {& O1 f) B: I* b9 C' E7 f
  30.     incrementTotal: function () {
    . o- U" ]! J/ q9 Z3 x& [
  31.       this.total += 1
    + z: _# o' e- F% k1 b" k2 g
  32.     }
    1 G1 F8 o) `( z
  33.   }
    / Y  b* J! O8 u" P% G
  34. })& f% y6 ?2 I9 s* K% b
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    * e9 {5 S2 @  l
  2. Vue.component('child', {* y1 k* H) Y& g3 D& f2 c
  3.   // 声明 props- {* z! N/ Z# ]- z
  4.   props: ['message'],. @- @4 e3 w+ f) D; ^" ^1 ]
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    $ U% n! D! J( ?. f/ e; n
  6.   template: '<span>{{ message }}</span>'  d% _2 L0 l/ [/ o; }2 K
  7. })
    + P( S! J) L* ^4 a  Z* Q! J
  8. // 创建根实例
    7 ^, `% o( N& g& m5 \
  9. new Vue({
    & ^1 h, H* L# Y! |' Q) v
  10.   el: '#app',/ ~. c7 `/ E! q9 v
  11.   data:{* r* s; g5 @% H. r: j  C/ Q
  12.     message:"hello",, }# b! Y; y3 H* y; b- [% p
  13.   }- c3 A- R, f) \, A+ z% f
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {4 Q" C; o. e) L7 \# O4 E& E* r
  2.     incrementHandler: function (v) {3 K" T6 l7 f/ t
  3.         if(v==1){3 w3 Y' a+ Q9 h9 n: s) i4 I
  4.             this.counter -= 10 V' {: Y$ z2 i0 I
  5.             this.$emit('increment',[1])" T* Z1 u9 _3 s2 B1 O3 j
  6.         }else{  c3 q1 J- A/ d1 Q) L$ l
  7.             this.counter += 1
    % a/ Q* Q& }, ]
  8.             this.$emit('increment',[2])
    1 l; W) v/ u2 m9 r
  9.         }6 M# [2 B2 E) V0 c, C0 B
  10.     }
    $ D- r2 H/ F9 `8 p* d
  11. }
复制代码

1 h% N! O6 N4 \( ^( p  X$ T% h, \; [, i1 s
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-16 18:44 , Processed in 0.058030 second(s), 23 queries .

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