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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 11009|回复: 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,并使用它:
. J3 w, p  I0 _/ S
  1. <div id="app">
    ( ?, V8 {- r; H7 v9 [. b) q& l8 e
  2.     <runoob></runoob>, k9 X2 |: c7 j, H! p: ~0 n
  3. </div>
    ! {/ {' Q, }: W/ S$ R! T* z
  4. 7 H6 o: e% I- C
  5. <script>
    ; U/ P6 N) i# y! v1 M8 o
  6. // 注册5 X# \; g. M- ?
  7. Vue.component('runoob', {
    - E# Z' c- t* r; l7 i
  8.   template: '<h1>自定义组件!</h1>'' Y$ Y& H& S/ }/ |- w2 U1 |$ I$ n
  9. })
    2 z9 h  Z  i) K5 y6 B
  10. // 创建根实例
    3 r+ b* I- Q/ ]! }. j5 N  s
  11. new Vue({6 Q# ?$ W8 X) j# q. I& [! D
  12.   el: '#app'
    / k; s: @) U- B/ F% B
  13. })
    0 C: W6 H- {2 B! G3 F
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
0 b2 J. A2 T7 y) \% b
  1. <div id="app">
    * O* @% `! {" M7 V2 h* @/ L
  2.     <runoob></runoob>6 @1 c" S; x: g6 i% `
  3. </div>
    $ Q6 j' [6 ^4 l  m) B7 E

  4. ( H9 e( L* \( f2 S- r. g/ o. U" w
  5. <script>) K- M2 |1 ^- y1 b
  6. var Child = {
    ; `% o  Z. D1 Y0 C) x; N5 x
  7.   template: '<h1>自定义组件!</h1>'
    8 R$ e1 D+ h7 i( ^" X( P
  8. }8 T& o  v# I; C$ E9 F

  9. ! f6 [0 p3 l6 n! T/ C
  10. // 创建根实例
    ; g9 x9 C! B# f% {
  11. new Vue({3 u# O7 i8 S: D- G) @: n2 K" O/ _
  12.   el: '#app',3 y$ ~% @7 I/ y& k# m
  13.   components: {
    " X) k1 R5 l$ h6 p% R
  14.     // <runoob> 将只在父模板可用
    , B+ C1 y: {9 f/ H; l5 u% f
  15.     'runoob': Child+ f) ?3 \9 B3 @+ x: z
  16.   }, h+ l9 {% H. Y" e
  17. })& Q  K' o* b( z5 Q4 \
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例, h& {5 b; o. C  G- g+ V
  1. <div id="app">- c4 m2 ]6 X' D" E) ]
  2.     <child message="hello!"></child>3 `& T& u; }2 v7 a% A
  3. </div>
    ! D3 g( r$ t6 Z! x0 U  z  O" h

  4. 4 O: O( u: y) ]5 p/ W- t
  5. <script>
    ; g: M* y# ^9 R
  6. // 注册
    1 ~* o8 E7 t9 b. a* A3 q
  7. Vue.component('child', {$ x$ Z; _2 S4 J5 v8 F$ H$ Y: ~
  8.   // 声明 props
    1 ^4 i. Q1 N# [( m. ~8 O0 e' P1 i
  9.   props: ['message'],# e: I) _) U8 @  ?* D
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用# x* C. C7 K) g& K; N. {8 l2 O; E8 J, A8 C
  11.   template: '<span>{{ message }}</span>'
    ; F' L+ ?5 G7 [% W  I4 T( g* u+ }
  12. })
      P# P$ P3 ?6 z* x/ O% v' T
  13. // 创建根实例
    7 _/ F+ u* o: }% x2 O' }& _
  14. new Vue({
    / a9 Z' t" V: }# F( E$ X) h
  15.   el: '#app'; x0 T  G" `; T- Y/ Q& l+ Y  {
  16. })3 ~8 D# i! z% X! Z
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
6 W9 [. M+ z' D' D, p6 i+ |
  1. <div id="app">
    , i" U1 y- \, k) m3 V
  2.     <div>
    5 H/ r; e. q2 j9 \. c* _- R
  3.       <input v-model="parentMsg">
    : d5 ~9 T; Q, o# U! R
  4.       <br>/ j3 f2 z) n  z: I
  5.       <child v-bind:message="parentMsg"></child>
    3 R6 I$ h5 ^- [4 V3 A! s
  6.     </div>
    & G, j+ M- R/ u7 V0 H1 n7 T
  7. </div>
    9 P+ q, w" M+ e$ {4 ?' T: F
  8. / T0 W9 {% d( L6 ~7 c* T* q4 w
  9. <script>
    % x6 [% y4 d/ P) h% Y8 I( A9 ~* X
  10. // 注册9 W- T/ z& V% F
  11. Vue.component('child', {
    % N6 P, Q  b0 P& I  c- v5 a
  12.   // 声明 props, h0 @0 ~) ~4 i6 u1 r( ?% ]
  13.   props: ['message'],7 X- C* ~. v1 ]7 B. a/ Z! {5 z
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用+ [, z* p# L2 r$ L1 \
  15.   template: '<span>{{ message }}</span>'
    # B* g- Q7 k5 J1 P7 g
  16. })- q  P- z8 q! I4 L# y) q0 I. u
  17. // 创建根实例5 d; ?) c) L% }
  18. new Vue({
    7 a- y( M* F+ l: x
  19.   el: '#app',, D" K' B2 g  m6 u- _) v9 g( }( s
  20.   data: {
    / c& \: }" J+ T4 S9 s& U
  21.     parentMsg: '父组件内容'
    4 O3 {1 e& g# D
  22.   }  u" X) ?- u9 t4 ?1 x7 o* u$ j0 f# G2 T
  23. })
    8 ^/ K  }8 [3 D' F8 m8 w
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例9 k) k) |# h, ^
  1. <div id="app">1 J5 N# j* B# d6 ]( z
  2.     <ol>! S! ^7 X. ~/ m  k5 y! _
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>" Q+ \; b, j: {5 \- `- ^
  4.       </ol>
    5 @  k5 E/ U9 F7 b9 O  l
  5. </div>
    & X+ C9 A% F- y1 p  E$ i4 H

  6. ! P! X$ K6 d& C; ?4 D
  7. <script>
    . W1 [# O) g7 I2 G: N; B# w
  8. Vue.component('todo-item', {% O$ ?$ M- B) D6 R4 d$ ]
  9.   props: ['todo'],# R9 k* o- I+ r' b& {4 F) `
  10.   template: '<li>{{ todo.text }}</li>'
    3 y6 G7 s/ m. C, a- c
  11. })+ o, h3 y8 q" _) d7 n2 b/ _' e- \/ @
  12. new Vue({! e* Z! R' X" k8 a7 x
  13.   el: '#app',1 e5 X9 A* D0 ?9 r. O: ]
  14.   data: {
    5 R0 b3 M1 a/ V! ]
  15.     sites: [
    ) |& p8 R* K+ E8 c: N
  16.       { text: 'Runoob' },
    ' ~* ]% {/ J9 `' V
  17.       { text: 'Google' },7 |+ V* }9 ^; ?, K& E
  18.       { text: 'Taobao' }
    " S, x. C- C) ^: g* M" t# K
  19.     ]1 c& F6 z/ j( n$ z8 D
  20.   }
    2 A8 ~8 J7 Z, @! j/ J
  21. })& e+ u& Q. a9 B$ @6 L! O" ], g! N% g
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {, e9 t" S9 ?! x/ v" C" @
  2.   props: {4 d( p7 {! o" z2 ~: G0 J
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    9 m: Z; d+ I! G' ]0 f4 L0 [$ s
  4.     propA: Number,
    9 b" X5 }" {. n$ [, L5 t2 a
  5.     // 多种类型
    $ f8 i7 J% `4 U. f: g/ Z
  6.     propB: [String, Number],' e0 _& o0 g9 O) m0 Y" C
  7.     // 必传且是字符串
    + ?) u. G- i, W$ `
  8.     propC: {2 ~6 r' Z/ f$ }7 y4 l1 @8 q
  9.       type: String,+ T, N% {' W* E
  10.       required: true
    + _9 ~4 U4 s% x
  11.     },
    + r- J1 G! [3 {+ g' g% l) D
  12.     // 数字,有默认值4 @/ S. J0 c' p0 q7 I
  13.     propD: {! h7 [+ _% i% f) `
  14.       type: Number,, p" p7 U' c) K9 K3 u
  15.       default: 1002 R& r0 D3 c# |
  16.     },
    $ b- \" w, }8 [3 \3 T! U
  17.     // 数组/对象的默认值应当由一个工厂函数返回0 H9 K( T+ A1 ^
  18.     propE: {
    . x: [& [  I7 p# r( q* H
  19.       type: Object,$ Q! h9 f( t" B* E7 A/ d
  20.       default: function () {
    ) n' c$ x4 n5 I8 J0 N) M$ \
  21.         return { message: 'hello' }1 o1 Q% m  d8 p. n6 m9 p5 V* q
  22.       }9 [* H) B% |7 o1 d
  23.     },
    6 T: B- ?+ `5 ]  S
  24.     // 自定义验证函数
    ! [! t( s1 r% \  N
  25.     propF: {
    7 r& P9 z2 d' P$ o2 J4 [% J$ [& O
  26.       validator: function (value) {; d1 o1 \. e" p( H. K. p. E0 {
  27.         return value > 10
    & \7 W7 |  C2 N5 F; X- ]
  28.       }2 b" l- @# ~8 Y; V! M: G- G
  29.     }
    , ]; ]1 G5 |9 q8 x
  30.   }
    / B1 p% T1 h/ `- d
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array4 {. F) d+ j$ N6 G- j' M3 z6 [  o
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    8 N+ A8 h( e  h/ Q
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例+ Y6 c9 |# C4 |# ^" T
  1. <div id="app">
    0 o! X2 S% K: x) j
  2.     <div id="counter-event-example">
    - w4 Y9 G; }+ s; K) f2 R4 W
  3.       <p>{{ total }}</p>/ F+ Z3 s1 `. w: c! c) ]
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>" i' _5 s- Q3 c4 j
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>: q) W1 K1 p" O& _; n8 O$ I
  6.     </div>
    # l- q* f& h  I( c6 ]1 O! d. N% i
  7. </div>
    ) k7 A& a. E( E+ l, m( z
  8. ( m4 t. X( c/ M2 R
  9. <script>
    ; ?& {: b% h& E  ]$ f" [% d
  10. Vue.component('button-counter', {. n$ P6 A7 G$ e  Q+ Q1 n* L
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>'," s+ P9 X& m8 t8 h- S
  12.   data: function () {& \/ v- K. d7 w& {8 N
  13.     return {
    ( N" m1 M6 }# q; _! J
  14.       counter: 00 f/ [9 {( }4 `
  15.     }
    9 W# B8 h% Y7 X& }( s1 F7 g6 }
  16.   },
    ) ^* ~2 }' ~# J9 D9 F; _
  17.   methods: {' B, g1 p3 T/ e% q
  18.     incrementHandler: function () {$ W2 j" ?7 K+ q2 @
  19.       this.counter += 1
    6 i/ _; a" f1 b: R2 L6 Q4 r  r
  20.       this.$emit('increment')2 n+ Q$ S  i; Y. F2 c
  21.     }) N% o" T, ]: P, y& b
  22.   },
    0 o6 U: m1 R0 T: `9 }' v
  23. })
    3 T" p7 F3 _' ~. @8 o
  24. new Vue({+ T3 v6 k! L6 l  i$ ?5 a
  25.   el: '#counter-event-example',
    5 g3 j: G0 a& o  S0 Y
  26.   data: {. f. u# |2 U  I- u$ v) D
  27.     total: 0% ?( g  I$ m9 k) s
  28.   },. j6 R; N: K% A& x, _7 C
  29.   methods: {( ]" T' r5 C) S$ Q/ Z/ E8 _
  30.     incrementTotal: function () {
    % e4 D/ G9 ^+ c& T8 s" s( e  X. W
  31.       this.total += 1
    5 D' w7 {: W# ^1 K8 A+ f
  32.     }
    6 u  k6 a6 h, v6 @, H7 O
  33.   }9 X9 X5 ]# J( M: B/ k
  34. })
    + i4 N1 A8 l, a+ }! z( b1 N1 {
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册- `- H  S5 w1 k; I2 s
  2. Vue.component('child', {5 ]% Z4 A+ D  l4 X% Y
  3.   // 声明 props9 m5 U( Z8 C, K- y+ I8 X0 c" Q
  4.   props: ['message'],
    9 C9 K& B" s' H+ C& d
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用* G0 g, _4 k* L6 N; P: ^1 {
  6.   template: '<span>{{ message }}</span>'4 s- c) n" l+ _, M* k) d
  7. })" d" |4 @8 v/ C& s
  8. // 创建根实例
    # p7 F+ Y5 d! b& l9 {1 S1 G) p6 y
  9. new Vue({0 P3 r/ Y! R3 m! B& }8 |
  10.   el: '#app',% X! I8 V; F2 l7 L( G6 C1 e5 r
  11.   data:{5 Z5 v- H, _: m7 |/ A5 `1 M2 q
  12.     message:"hello",- G; Q* n6 _) l5 i2 E$ [
  13.   }
    1 C) \1 ~8 a' ^) {2 ^6 h% U
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    / a9 v1 t1 h- X# k3 G
  2.     incrementHandler: function (v) {% r% W5 J' J, y% [- ^% R, f6 Z+ R# N
  3.         if(v==1){
    ' f1 Q" o6 V) z* k: s% i5 n
  4.             this.counter -= 1
    ) s, Y" q6 y; X: @- j) x8 q5 ?
  5.             this.$emit('increment',[1])  O: d$ y" b9 z' j2 ^# `
  6.         }else{
    2 T( b- ?6 R; Q2 R0 V
  7.             this.counter += 1: g! i8 r0 t2 ]
  8.             this.$emit('increment',[2])
    ! x" ^" _# q( _$ p9 q
  9.         }9 E  r6 k4 _; V! _) c$ ~9 y, w5 M
  10.     }8 W6 F$ C, e2 p4 ?
  11. }
复制代码

! p1 j; f& `# x4 J0 z/ Q+ K4 L
3 T; F' M4 h& l& ?' }, E9 E/ P6 F' d/ V
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-16 09:24 , Processed in 0.118970 second(s), 22 queries .

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