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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

( b4 F' L. d' x$ P$ i9 J2 `
  1. <div id="app">
    . U# i9 F9 b2 S9 V! `
  2.     <runoob></runoob>0 V9 k* n# e7 ^  c0 v3 m" q
  3. </div>
    * U4 \3 t8 n4 x$ V7 ?# c( |

  4. 8 ?* I1 B  W& T3 G
  5. <script>0 Q8 a* o- `9 I$ {" z+ f/ b
  6. // 注册
    , H: k  ^: t7 q9 A( n: W
  7. Vue.component('runoob', {& p8 f& c3 t$ {. W: S2 O
  8.   template: '<h1>自定义组件!</h1>'
    , M% c$ P! d( h
  9. })9 q5 l- Q* i4 k% l$ {+ M
  10. // 创建根实例$ j2 L; V- V* i2 O5 D
  11. new Vue({7 }2 n9 J  ~( ^3 X- k  g& @8 J/ ?0 f
  12.   el: '#app'
      q& X; g& h3 v3 Z& q$ R
  13. })9 l, r1 n. l, q4 a+ f. W/ n' ^
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
9 z' M! p# @$ E$ {9 W" |% S
  1. <div id="app">
    4 k0 I# D2 i( s- p+ ~; l
  2.     <runoob></runoob>
    2 v1 ?; |; x; w- ]. [
  3. </div>6 d& S6 e% a! o. a; z( c- I4 R5 u

  4. 6 H. K) s) \6 l
  5. <script>
    5 E7 s! w$ K$ }
  6. var Child = {6 M  \4 ~- A3 f: |. P* ~6 T( u: w9 y
  7.   template: '<h1>自定义组件!</h1>'
    5 h& }% B" P* H% k: ]- k
  8. }
    4 u" \  X# C+ f* y
  9. 5 H2 {8 I' w% }2 F* O9 h
  10. // 创建根实例8 F$ K+ j8 A* @1 r
  11. new Vue({7 M' M* E& F  Z/ J7 }6 M" n5 r8 @
  12.   el: '#app',! y' J. k1 J! t' v. W
  13.   components: {
    7 j7 Y: u! f" @5 B% q, z- ~
  14.     // <runoob> 将只在父模板可用
    - A5 `; L: x; f/ h' N4 L
  15.     'runoob': Child/ G/ I; Y3 ~, b
  16.   }
    4 B# M7 S: U& n. ~3 h/ P! @
  17. })6 I% {$ |2 ]/ E, W; m9 a" h3 n8 T- N- o& f
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
" H1 O6 E9 y& G" F8 v
  1. <div id="app">
    : ~4 d$ F1 {2 C) s
  2.     <child message="hello!"></child>
    2 a' l% l! i' t& q: J/ ]
  3. </div>
    4 ?( y: E: q9 M# l
  4. . ?0 g( l1 ~- ^2 \
  5. <script>
    ( m' T) [. D: U+ U( w* \$ \$ B$ p
  6. // 注册
      m, x1 ]2 k; t' w! z
  7. Vue.component('child', {2 k5 y  ~# a  [& }5 I: J) P: y9 J
  8.   // 声明 props5 b9 q9 b- L% K7 \4 x
  9.   props: ['message'],
    + ^( n5 I2 X. [" ]
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    " |1 b5 X$ S6 |7 u  c
  11.   template: '<span>{{ message }}</span>'
    0 E& L- y8 U- u7 G2 l- i  F
  12. }); B& l, q6 o9 S) A, }
  13. // 创建根实例9 B' @* I5 x6 k. x, Q' U
  14. new Vue({$ F6 o# ~6 C7 f" H' E# u! p- b
  15.   el: '#app'( U* T/ f6 C) F+ F* ^" z# f2 `
  16. })  u6 Z7 z( k- f3 e2 V3 o( g
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例5 ~; J2 i1 H" \3 `- l) m
  1. <div id="app">6 U  Z) U: s$ Q
  2.     <div>
    ( B4 ]* i8 C, A
  3.       <input v-model="parentMsg">
    : L' j" d8 r* v+ N' N4 j0 H6 ?% Y5 J+ J
  4.       <br>% n  j5 |  i' f! A. s( f% d
  5.       <child v-bind:message="parentMsg"></child>
    ! s: {7 y8 B  Z9 q4 q9 d
  6.     </div>
    . V; _& S8 M  y$ _" X
  7. </div>
    + Q% @6 Y9 p5 b1 B0 T; J8 }9 w

  8. . J( Q( l; s3 z, b1 b" n4 |$ }
  9. <script>
    % Q2 I7 \: n  B! S
  10. // 注册
    ' b5 b9 v0 A" `# ]( m& a
  11. Vue.component('child', {
    ( \# |+ J4 m- @8 t' n3 T
  12.   // 声明 props  R8 F0 Z6 b5 B3 Y! p. K" h/ l
  13.   props: ['message'],
    3 y- ?2 G. T2 A4 O! T7 m
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用$ U7 X) f9 @' }8 I
  15.   template: '<span>{{ message }}</span>': W: u5 K9 Z/ N7 l# x
  16. })
    ' K9 z2 d9 t7 T+ g
  17. // 创建根实例2 ]: A; w9 A4 F* b2 n
  18. new Vue({; L, Z' a! x6 K( p" P
  19.   el: '#app',
    : a) c3 O" O" u& N, w3 x
  20.   data: {. U6 ~5 m& f5 j) s0 g1 M5 ~
  21.     parentMsg: '父组件内容'
    : ~5 G8 p/ P1 t5 a! E) ]
  22.   }
    7 {( `1 }% e' A. F# h1 l
  23. })
    7 Q; v" M* |7 F4 p+ S  q# r
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例0 z" D& J+ r  t' L6 n* D2 G
  1. <div id="app">
    " R% l! c! T, f& _
  2.     <ol>
    , Y' ]9 w- ]6 B
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>0 \' H. i6 o+ X3 i0 y% B
  4.       </ol>
    * ?" {, g: p2 I4 W7 V2 `
  5. </div>+ W1 \2 P- p* ^' L. Z' @& |

  6. / y( ?- j0 w" i5 @* v6 @
  7. <script>& i* L  D8 Y. ?6 `  w5 a
  8. Vue.component('todo-item', {! H5 z$ K8 {1 }) i
  9.   props: ['todo'],
    - c2 h) h. ^& K. c
  10.   template: '<li>{{ todo.text }}</li>'
    3 m8 y$ c3 \1 B- d! Y/ Z; i
  11. })
    $ I) E4 W; c( O8 l. C; ^: }" h+ T
  12. new Vue({
    # H" L, N. f" @' Q4 V2 A' ^; x
  13.   el: '#app',) e. X2 c" W+ [/ j5 u
  14.   data: {0 B1 B( U" F! _  [
  15.     sites: [
    1 P  V1 }7 d$ x+ X
  16.       { text: 'Runoob' },
    ; x+ t( W; C# ]% c# F3 }* s4 a% m( n
  17.       { text: 'Google' },
    . A- Y; R  b" \* b( B
  18.       { text: 'Taobao' }3 |; Q0 ~" v! [& `* }
  19.     ]
    ( S* q" |6 s% h
  20.   }
    7 _1 T6 g5 ~! @
  21. })
    ) J! R! |* L: X- L! g& p3 i# [( L
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    + j( i, z; }% B% B  _) X
  2.   props: {/ Y0 N4 R+ {5 ?
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)' `4 V5 I4 {' b! r/ m+ R
  4.     propA: Number,
    ; ]+ ^. f! Q' x) S4 }
  5.     // 多种类型
    , R- b% q) h" w6 L/ }
  6.     propB: [String, Number],9 r0 L. x1 D6 l* G  S( [1 z) R$ e; V8 t# b
  7.     // 必传且是字符串/ ?" o4 E: E1 ^+ W; C8 t
  8.     propC: {/ j* U, j1 Q# _* P' k8 l$ O3 K
  9.       type: String,
    5 a0 D. p/ p1 Z# X0 X) x3 [* a
  10.       required: true
    ( v) S- t8 E7 C
  11.     },8 l2 A: G6 n3 K2 M) O! T
  12.     // 数字,有默认值
    ) z; ^2 ^+ `7 w7 n3 F5 {8 P4 t0 Z
  13.     propD: {
    2 ]. o* p4 e% F; ?" C. ~
  14.       type: Number,
    : E+ g1 X2 A2 `* Y
  15.       default: 100
    0 K3 P0 M: w" m; c
  16.     },
    3 y6 B8 v4 o* @1 Z  }3 y* R
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    2 t7 j$ C8 N  P) d
  18.     propE: {& K/ W8 M5 q1 w$ u4 l2 A2 ]* |
  19.       type: Object,
    , a$ H( F8 g+ X( n2 M2 n2 z  e
  20.       default: function () {
    * `% ~: G5 `7 O$ a' v$ }
  21.         return { message: 'hello' }/ X9 w5 p! E8 i
  22.       }
    2 @* k- B3 I" V2 V. u
  23.     },
    9 ]3 I" M) Y( r5 w
  24.     // 自定义验证函数
    ) ^* K9 K. y8 U8 E: D
  25.     propF: {
    - M% t4 s' M" }, j: D6 W* e
  26.       validator: function (value) {
    ; T. Y$ Z, \( H8 v8 h
  27.         return value > 108 Q" Y7 o/ l+ X: q- E& G. `+ r% t
  28.       }* V3 _) k- V# Z
  29.     }
      L- `+ G3 T* g) B% d; {5 d  F
  30.   }- A9 P2 d, E. U4 D
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array: F, u4 S6 N1 s1 a( E" L3 a
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    7 E4 e3 B9 ?& G8 a% l$ K
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例  {4 y3 N1 h$ l3 k
  1. <div id="app">1 d3 b* a6 `0 T0 B
  2.     <div id="counter-event-example">
    # j& l+ I3 x  @" ^# q
  3.       <p>{{ total }}</p># t9 T& X, N8 p) p: o
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>0 W% h0 n$ X9 E6 S" N# p  ^% }0 G
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>+ e  N5 ]$ W3 b, r, l0 V7 C
  6.     </div>9 f4 i: H% a( c6 K6 z
  7. </div>
    : f# U% O3 w; B( c: ?

  8. # f) `* L' o! J$ t9 u0 ~* ]& Z: p
  9. <script>
    3 O3 w9 G5 h2 g0 [
  10. Vue.component('button-counter', {* o7 n6 D% @9 ^2 F, J" c% R
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',9 O& O' q" q+ u: G) P
  12.   data: function () {; B6 E/ Y+ ]; m" F- Z
  13.     return {
    $ s. d& [7 p2 T6 s! z# e
  14.       counter: 0
      \5 Y$ {7 D1 I) o4 M5 t0 s
  15.     }
    3 Q2 o" X$ r( I# g0 u
  16.   },
    - l% U2 ~/ O5 M6 L* H0 u
  17.   methods: {- A- Q5 \! h( E- A8 N5 B0 j
  18.     incrementHandler: function () {
    7 B! z$ D5 l! c/ f* g5 b% J
  19.       this.counter += 1
    - f6 z0 _" E  k" V
  20.       this.$emit('increment')+ Z( f5 Q( ~  Y: c! k) X9 P
  21.     }' U5 {% H* x# c, n
  22.   },3 F! _( i) b" b8 c
  23. })
    / e; Y( [* V6 C( v; P8 a. o! e
  24. new Vue({; f5 N6 J4 K/ O. e+ g8 m+ Z
  25.   el: '#counter-event-example',
    8 F0 S/ F$ }/ z
  26.   data: {
    " S# _7 t5 w: b& z; o* ^; f% ?# c
  27.     total: 0
    3 r$ m9 F" M0 c) r- J
  28.   },
    / F- g: Y( Q  k9 @" s9 m3 ?9 L
  29.   methods: {
    " |5 s- e7 h% w& `/ g
  30.     incrementTotal: function () {
    7 q( A# s/ g" h) A0 j! b) e# d
  31.       this.total += 18 l2 V6 C" P! @6 ~+ f
  32.     }/ Y! q7 d  U9 T$ g
  33.   }
    : c9 r. |+ X. s0 _
  34. })
      p* L  F/ _8 s+ L7 P
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    / D/ o( Y$ l/ l  h8 x" B
  2. Vue.component('child', {
    & I: w5 J+ M! {) k# y
  3.   // 声明 props$ q( Y) G2 z9 F$ W/ H1 y, H, O' u
  4.   props: ['message'],  c! b3 k1 I8 W$ \% G, s+ T, E
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用, [! b; I' ]& b6 H6 a8 k* {. W( h
  6.   template: '<span>{{ message }}</span>'
    5 \: i2 Y- K" {! P3 ?# i
  7. })
    ( `) J* m/ J" `$ o8 ~
  8. // 创建根实例
    1 ], A2 T) P9 G3 y3 n  I
  9. new Vue({- i" D$ i7 e. o, k# b1 S' `
  10.   el: '#app',
    8 |) O" i% k/ e9 B" B0 K5 h5 _
  11.   data:{7 _, B5 {) p! _9 d+ b3 y; F% r& L8 D
  12.     message:"hello",
    ' e& C( m: ?6 f/ I5 ]" x8 Z
  13.   }
    . w: S7 Z! ^8 p8 G( ?  A3 ^. P
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    8 w. ~- Y- N/ n
  2.     incrementHandler: function (v) {+ n% f* C( t4 r* }2 n
  3.         if(v==1){
    , S8 y& Z& {; C, A
  4.             this.counter -= 1) Y( B& |/ N1 d, f' D9 u2 h
  5.             this.$emit('increment',[1])
    # p6 o' N# [4 e" |0 w# W1 o
  6.         }else{. ?+ `! h8 p4 y* V9 f& S
  7.             this.counter += 1  ~  I! L+ _* s: Q
  8.             this.$emit('increment',[2])
    / _2 ?8 F( d; n% b( L( ?
  9.         }
    8 \+ g# k8 f* L- {" W
  10.     }& ]& w$ K. `: y' `' x
  11. }
复制代码

6 v% x  D- x7 d# U
& Y' h7 \9 n8 j/ R/ Q
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-20 00:19 , Processed in 0.169117 second(s), 22 queries .

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