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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 11475|回复: 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,并使用它:
; F$ g, W; Y5 [% ]
  1. <div id="app">
      k) g1 [/ Z8 }: Y
  2.     <runoob></runoob>
    9 ^4 k- o, v' j& f1 m$ n
  3. </div>$ ?) a( j; h( I8 Y. E* a) A
  4. ' s5 K8 v4 I  O* ^' K& \- [
  5. <script>
    " o7 H7 |( L$ ]7 x- Z* D
  6. // 注册
    # E; Z1 K) k+ q) ]/ |" K2 Z) v4 D
  7. Vue.component('runoob', {$ E, t& C  t9 D5 y6 Q
  8.   template: '<h1>自定义组件!</h1>'
    & F, q) [6 [5 k0 m/ I5 q4 s
  9. })9 i( n! x; ^9 k' b3 W
  10. // 创建根实例6 t! q& |2 L, p- _7 X5 A' k* p9 R
  11. new Vue({! U/ i, Q6 x- \5 V
  12.   el: '#app'
    3 C( \# Y. L2 M; ~' b! l, e1 Y; {
  13. })
    " t% L: I6 |- y
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
% Z, \$ U/ X3 B/ A' M
  1. <div id="app">
    7 ?% N5 M- \) o8 k, C8 P/ R
  2.     <runoob></runoob>
    * [+ A% y6 t8 c# e% Y2 a. G* V
  3. </div>
    4 k, h$ l1 M! p8 x
  4. , z% N" a9 ^6 |5 V2 b
  5. <script>
    4 s1 [1 Y( m0 M; r4 d6 q2 ]
  6. var Child = {
    / E, v* G5 f; P  i; E6 m  [1 M( L! U
  7.   template: '<h1>自定义组件!</h1>'
    $ O9 o. j% a! U* ?
  8. }
    + z, u( r1 K" {7 T- z) f4 T
  9. $ m" V6 j9 p  |- q9 j1 F1 `
  10. // 创建根实例; f' `4 r. t+ D: H& E
  11. new Vue({9 C! g# l# @  A# ^4 {: c
  12.   el: '#app',8 }+ Y% K; r' I: _# L
  13.   components: {6 W( s# Y5 l/ U2 C( V4 P+ S. v
  14.     // <runoob> 将只在父模板可用9 w1 B7 w! n: k* Y
  15.     'runoob': Child
    ( m* E7 u3 m- }
  16.   }' ?& k+ b( h5 m2 [
  17. })
    1 }5 m, P  N# W( ~
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
5 u+ ^# m! L$ m3 F1 e
  1. <div id="app">4 f9 Z: Y) M8 ]
  2.     <child message="hello!"></child>! ?. |2 \9 A  I( F$ [1 [
  3. </div>
    : y) Z. ~7 V) P

  4. 7 @& \1 I6 V9 E1 |* t
  5. <script>
    ; t4 r' }; B# v. T2 g9 M) X
  6. // 注册
    $ }0 B/ T; }+ a$ t9 `
  7. Vue.component('child', {  x1 @( @2 n1 U5 w# Q& S( `8 Q
  8.   // 声明 props( N/ E1 f/ f' k5 G+ _- J
  9.   props: ['message'],9 @5 h& b5 s# K" W0 x; {9 H
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用' s5 T9 b* N$ U" o: i( c
  11.   template: '<span>{{ message }}</span>'6 S' Y5 n% ?1 K1 f+ F; C
  12. })2 ?: i+ \3 J; Q4 D
  13. // 创建根实例
    ! I, Z  m/ t5 w6 W% {: y# v
  14. new Vue({% w" C$ h( A$ p$ m6 H" F8 K
  15.   el: '#app': E# K4 L% b# m: c
  16. })
    ; |0 ], |6 d  g$ c+ k/ l# |" Y- N0 ^
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
& m1 f" S* Q" m! H+ y1 a
  1. <div id="app">
    / _% M$ ]6 V/ h# c0 \
  2.     <div>
    . [) i& v% @& R5 E4 e6 l
  3.       <input v-model="parentMsg">
    6 A5 l! a! Z3 U4 `! S3 e- A& S# v( N
  4.       <br>/ z- L3 Z* b8 ^$ o$ C# A! e' Z
  5.       <child v-bind:message="parentMsg"></child>" g4 B. ^7 s( J. @8 u$ X/ }
  6.     </div>
    9 k) e9 ~% g* A  K
  7. </div>, y8 V6 I$ b0 Y

  8. ' l' [; w3 J3 P  P, [
  9. <script>8 a% ^2 C- V. l/ \6 O# I7 U$ ~
  10. // 注册
    9 c' @, B0 w( U' n+ J4 [  y6 M$ }9 ?
  11. Vue.component('child', {
    % j* ^& Z8 }- f4 q6 ?
  12.   // 声明 props
    4 R  j6 N5 W+ [3 w3 }
  13.   props: ['message'],# ~: G" J* i. G: H  Z! |0 q/ [
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    & C1 z! o2 @: Q; y- A5 e
  15.   template: '<span>{{ message }}</span>'( B8 ^3 s! c, r, e* B
  16. })
    0 O$ m# Z' f$ c; }8 T" p
  17. // 创建根实例& O% c# ^* q9 Z" {2 D
  18. new Vue({
    9 x2 d. a* T8 [' P& Y) z9 N
  19.   el: '#app',8 N7 k3 @. i* \' ~* R
  20.   data: {
    & W' V" s7 u4 ^0 H% G1 X+ y! L
  21.     parentMsg: '父组件内容'- k& b2 ^7 C+ p  Y+ y9 y$ k  j* r
  22.   }
    0 r  }! ]8 S. ~" |! p7 S- g
  23. })4 |/ c& x0 i- h/ S  B4 n' ^4 d
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例9 S* ]5 X" a$ F& ^+ e! X2 \, J0 o
  1. <div id="app">0 l$ s  \+ H, ?
  2.     <ol>8 [6 ?; O7 T$ ^/ A. Q
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    4 m- N3 {, C$ z* l4 Y( e1 A' E
  4.       </ol>, i4 F# i) D. w# k/ S; d8 A" C+ G) b
  5. </div>2 j8 J: G$ n0 m. Z: E
  6. 7 n0 ?( K1 v9 h* W& L* t" C
  7. <script>. e: b# k' |6 p8 t) {: f( L9 L
  8. Vue.component('todo-item', {
    3 v" N9 S3 v" u
  9.   props: ['todo'],
    / V% J/ Z. I3 D
  10.   template: '<li>{{ todo.text }}</li>'
    ' i8 ?9 J+ y, y# [  H6 ?. Z2 g& o! |
  11. })1 _5 o2 e8 L, c! y5 y0 M
  12. new Vue({
    9 e$ _8 A6 ?3 {
  13.   el: '#app',
    # V+ o7 _2 e5 @* v
  14.   data: {
    3 c% k# H. l8 k0 |) r* l4 W
  15.     sites: [- V; Z9 R* M" v- A9 f6 ]' r% o
  16.       { text: 'Runoob' },
    - Y* x, {* b; K( D
  17.       { text: 'Google' },. v4 Y" a- g& L8 |) H8 n
  18.       { text: 'Taobao' }4 X7 U+ o# G$ t
  19.     ]
    & A5 E0 t/ U; Q7 _
  20.   }
    ) t, q5 x# z% p: ^; S
  21. })
    ) W$ I9 x9 K; `2 o# [% D
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    3 G4 x; M  \( S0 V  ?1 {
  2.   props: {5 n# _5 a+ G7 u6 e- c
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    ) }" T8 o$ U7 O" R& O
  4.     propA: Number,
    # X* O2 G8 B: g' c; P
  5.     // 多种类型
    & @$ u7 ]0 }( n4 ^# v
  6.     propB: [String, Number],
    ( e6 L& i* t3 G
  7.     // 必传且是字符串
    9 z$ N; S% J; v, T# Z- h+ g  ^
  8.     propC: {
    6 v4 q$ k( p: \) X2 y) W
  9.       type: String,
    " s# Z# ~5 s  X5 m
  10.       required: true/ ^0 M% t( k7 _* f5 t5 [! v$ f3 R
  11.     },# X3 H" g. X$ ]1 b& p8 P7 B) S' \
  12.     // 数字,有默认值2 W2 ~% t! f1 L. v) Y
  13.     propD: {6 B' p/ G$ M8 }
  14.       type: Number,
    ( q4 Z  L- m- k& J4 w3 ^+ t. X
  15.       default: 100( U4 \. `9 k  E$ ?
  16.     },
    ; o9 L( j8 N. E. w2 ?& [
  17.     // 数组/对象的默认值应当由一个工厂函数返回4 O; H/ P% C& |0 {3 c
  18.     propE: {
    2 ]4 n" k1 W. F3 Q1 ]
  19.       type: Object,- }* [1 L( [( f5 q/ }: f) f( b  f
  20.       default: function () {
    6 t) {2 L; N2 \$ \: Y
  21.         return { message: 'hello' }/ Z1 {; J" ~  o+ C2 q
  22.       }
    9 b% n) V- ^4 w3 Z
  23.     },
    ; O6 ?- q1 I" }4 T0 ], \% o8 m
  24.     // 自定义验证函数
    ) D4 `: m4 V! _* E5 J! \$ W
  25.     propF: {
    0 j8 |/ q7 m7 k8 z" N! c* j
  26.       validator: function (value) {, L, k$ {: b8 `2 ~1 H
  27.         return value > 10
    6 \, M2 p- t0 J9 Y$ g4 ?
  28.       }& o$ O  {2 C& n3 r5 [
  29.     }. J. b7 A( q9 G$ i5 n3 S" c* G) T% p4 x
  30.   }7 A  {) J8 u4 W' E* h
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    2 c' T% c6 i: j: W% c6 w/ D
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
      o; y% u3 G4 B/ v; c
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例6 M8 |% J: t0 C" _. r) b. P- o
  1. <div id="app">, Z% j" V* p% I' z5 z# w
  2.     <div id="counter-event-example">
    2 B% f* _4 I- D: k2 x
  3.       <p>{{ total }}</p>
    % u( a; E! F3 E
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    - f" V! k2 x  V- k. v
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>4 o5 e* l7 n: \- ~' t5 D
  6.     </div>
    . V" t% u' G) I4 @+ I7 A, ]; u
  7. </div>  M: w2 ]3 [( V+ S. S
  8. + \- Y+ p" x* w4 t
  9. <script>3 i( U7 F4 ~, ?8 a% z6 f
  10. Vue.component('button-counter', {
    ( Q7 e! ^, f/ Y7 i( f
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    + ^$ `4 J! S( _; B9 [! m% n; a
  12.   data: function () {
    $ E! P* K1 g# T4 M/ `6 y4 k
  13.     return {& P- Q& N' O, A  [5 X1 q
  14.       counter: 06 {, c- ^6 C2 L4 c) T
  15.     }
    ; `! I& X! U1 A" A& J* B1 H
  16.   },+ O  T% }0 ~6 k" p
  17.   methods: {/ L8 `1 a6 w& w
  18.     incrementHandler: function () {
    , n, w8 e5 z4 D9 m
  19.       this.counter += 16 B5 Q, W) ]. f5 E; \; W$ f1 Q
  20.       this.$emit('increment')
    ; Y- }1 T! u  Q1 a
  21.     }
    9 Z2 n2 @6 K/ _4 T8 f
  22.   },0 @, Q- ]6 E0 b' _3 r8 g! g
  23. })' y2 d' T' L- I/ F9 i  Y9 r7 I
  24. new Vue({
    5 x: y3 w: S1 g1 Z0 e
  25.   el: '#counter-event-example',
    * Q7 b8 V( S9 Z+ w( I! g( a6 }2 A) N- F
  26.   data: {) f* A; @( ]2 ^: g5 ~* ^) d, `
  27.     total: 0
    # _. ~! H2 D9 ~) l/ w! V. r; @
  28.   },
    8 Y9 V1 P6 J8 Q$ z0 N8 J4 r8 J
  29.   methods: {
      {9 D% T8 p" J8 T: g
  30.     incrementTotal: function () {
      t2 l! D5 \' u
  31.       this.total += 1
    * r# B9 N; O- q8 F7 O* F
  32.     }
    & j* a+ B( ]) S3 {; E' {5 o" z
  33.   }" g: z! j/ k0 g! Q
  34. })6 `  A+ ?$ I( o! Y& I6 n* }) N
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    ' E3 W  p1 F! }) G. W2 v  D% G
  2. Vue.component('child', {
    2 W. A# s8 i2 [. c: C$ W
  3.   // 声明 props- F  y9 f5 U  c. R+ ?) I
  4.   props: ['message'],
    , w% k. j# y- A. p
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    1 f! A8 o  [: M( N' g( A5 r
  6.   template: '<span>{{ message }}</span>') M* G0 a8 S0 y2 F" k
  7. })
    0 V+ Y% K: p) P% Z
  8. // 创建根实例
    7 ^6 \0 a4 X+ Y: n5 `0 }/ {$ b
  9. new Vue({- A+ U1 c. H4 A) P# k" O! g
  10.   el: '#app',/ M9 M  Y$ J0 C% R. Q: {2 Q
  11.   data:{* X! ]6 w5 u) o+ K
  12.     message:"hello",& @  u# f9 x7 X. w0 m# [
  13.   }
    $ X$ |6 [6 _# u
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    2 _$ @8 v6 h# Y# j: O+ y4 `! @
  2.     incrementHandler: function (v) {
    ! E$ p9 t$ g1 \5 X+ {* U) z+ B1 g
  3.         if(v==1){
    0 v& K  U9 S3 F
  4.             this.counter -= 1
    , S  \: f% \, _2 F9 ?
  5.             this.$emit('increment',[1])& `; }; c1 w+ m$ n/ E
  6.         }else{
    ! p) w" E4 _- F$ i3 _+ \* ^+ D% f
  7.             this.counter += 1: r$ O( H0 A0 z2 N2 k1 W
  8.             this.$emit('increment',[2])
    8 P' D. P4 b3 |9 p5 s
  9.         }
    ) b; U* ]9 b# \% G0 \
  10.     }( G# V) j% _1 e& P5 u/ U" ^
  11. }
复制代码

* s. k' Q. s" k* k1 w
% S9 a% `0 G4 z( b! R( S9 g
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-6-18 21:06 , Processed in 0.128586 second(s), 22 queries .

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