|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
- u; g0 c( z" h I3 E/ \8 V- <div id="app">* h) Q! M+ \' t7 a3 E# l. V, n* y* q/ o
- <runoob></runoob>
) ?# M& A5 |, G' N+ Y/ `" b) [ - </div>
% Y+ ~% w0 ]; _ -
, w. G9 f3 v7 ~% W; D - <script>0 T7 D6 a8 H4 r9 F- f
- // 注册
; l3 X" Y- l- v+ n( i" \8 m, j6 a - Vue.component('runoob', {
5 Y& k" Q K3 ?+ p - template: '<h1>自定义组件!</h1>'5 R7 q( l, Q+ K2 U; J7 X
- })5 L7 f m- N8 F/ x# C0 r% d% M
- // 创建根实例5 S& }# k+ }0 d% \) Y6 @
- new Vue({4 R+ I2 h J9 K/ U/ E
- el: '#app'
% E6 n C2 C7 d/ W - }): ~- s8 k L4 D& r/ D3 Y
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: + T! O; D: U2 _7 t$ U( F o
- <div id="app">/ O* f4 B6 @" J, J& i
- <runoob></runoob>
9 t( R, z9 n! V6 z8 r+ r4 K - </div>
& H/ v/ Q" h! X$ B1 P -
! |$ W9 m/ r0 a. ^6 A: a! n - <script>) A7 p7 {6 X# t
- var Child = {
2 t4 r K! V: \+ S - template: '<h1>自定义组件!</h1>'& W7 a) r, F3 ~
- }! L Z; O9 o4 \' D
- 5 _1 A/ k' I, K% [% r
- // 创建根实例
% ~2 _( t3 j. O N/ v; e4 } - new Vue({
8 l6 k. Y8 o3 W1 p+ O - el: '#app',- }6 S0 S7 ]( c) d
- components: {- \& T. i8 c; R6 V; v7 c
- // <runoob> 将只在父模板可用
& H7 k6 R, b. b' A% _0 `1 f - 'runoob': Child
# n- P6 M% N" k - }9 C: C$ Z8 z) q z* \+ j
- })
. H7 }( {# P" p3 p4 a6 b8 J - </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例! r9 i. U% V( R1 N" ?
- <div id="app">
( u% X2 W# ^1 w# {- D) |8 {" R9 \ - <child message="hello!"></child>- _. F4 a0 b3 c4 ^7 O6 T" f
- </div>. s, R/ Y% h; m# H
- 9 |" Y/ [+ Q- [: `' q1 l
- <script>
; @9 ~# P% ~- f( r, ] - // 注册0 h6 z# Q ?6 `% H; d9 W
- Vue.component('child', {
% n* a; T% Y/ `! V% `$ Y - // 声明 props
. U+ z- \6 ^1 y7 o - props: ['message'],9 _7 b: s$ w- E/ K1 N# K" S% C
- // 同样也可以在 vm 实例中像 "this.message" 这样使用' V+ `) E+ h2 L* U$ G& R$ R) T7 q
- template: '<span>{{ message }}</span>': \# _. u5 I; [% G
- })8 k3 H1 Z2 | t3 g5 ?0 s G
- // 创建根实例' e" g3 f) x3 } d* [+ F" G
- new Vue({2 I* |9 O: a$ O6 ^
- el: '#app'
0 O2 Q2 ]3 ~: q' k - })
' h! P2 B8 H# h9 `# B - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
6 q) O2 B# r# Y2 o1 G, a. E* E1 [- <div id="app">
7 C- E' `9 k7 I& ?7 q- F/ Y$ h - <div>3 z |) y8 S- J3 H$ T
- <input v-model="parentMsg">
. L; I" }$ ^0 g- b - <br>
6 g8 w2 X& D G5 g6 ` - <child v-bind:message="parentMsg"></child># R u) k9 K; C8 F1 l
- </div>
e/ F8 l7 `. [4 u - </div>/ g- K6 s# B" R& z; N7 u' x* L
- - M- k( P4 h; g2 ]# e4 _
- <script>
* g& D; l0 Z9 e9 o }* j - // 注册
' |* ?( D$ n& a3 R/ b) a' W1 C# D0 ]# { - Vue.component('child', {
\; Z. b4 \* y/ d; { - // 声明 props4 Z4 @- ~* |3 b8 O& G
- props: ['message'],
/ B) y6 X+ a( y7 x( c6 K - // 同样也可以在 vm 实例中像 "this.message" 这样使用
, y' q% Q6 G; Y2 X( | - template: '<span>{{ message }}</span>'
& m, X; h- F/ i0 } - })
, d+ w0 n- p# d0 } - // 创建根实例3 X% [; S& I; E+ |) t. j; o
- new Vue({* Y \3 U/ R& u0 E4 c" e
- el: '#app',) Z- T4 x' }: o8 p' w8 h
- data: {
- Z. x+ a1 \. _+ `* [1 h - parentMsg: '父组件内容' _1 }, V- F9 e5 N) y( v
- }
; E* R+ \/ t( B# { - })9 [2 j. H- i, P# {; v
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
) e# D$ n# a* X2 ?* Z# \* [0 k, j- <div id="app">9 B* e/ n4 Z q/ a: c, N
- <ol>. j/ R; g% F4 n5 a/ g c/ s" d7 P
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>6 N6 y4 X$ F; T; N1 Y- o @" ^
- </ol>
1 A5 ]: s# M. K - </div>
$ X: S0 _, ?3 R5 q- z a# E - , B2 a! o0 R, w9 M4 u* H2 s
- <script>
/ N1 N: A. h5 z7 t' x0 u( m - Vue.component('todo-item', {) e4 E/ n7 b* o$ J) I
- props: ['todo'],
4 y2 W3 t! F/ k( g$ O0 F+ z - template: '<li>{{ todo.text }}</li>'
& B. L* Y# j6 h% r5 v$ x6 I9 h - })
* b5 x/ `, e! c! l/ Y# K. _, t7 L) b - new Vue({" w3 t, L5 z; X, N
- el: '#app',4 m( _4 p* |+ V. s$ v% Y
- data: {4 [' s( w. G# E
- sites: [1 l% a: N7 o8 z+ _
- { text: 'Runoob' },
2 q1 Z) b4 s1 U! B5 W& \ - { text: 'Google' },2 v, k9 W. N/ s3 F6 x
- { text: 'Taobao' }9 U9 M( L1 c' M: U# R$ U
- ]
7 A, U# X. s8 i' f' }/ k0 X - }" a/ `3 B9 y$ \
- })2 m& m7 k2 ?2 X4 Y3 Q. p
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {* U, r! r& p2 _- d' p; [
- props: {" k. M: m& j" U7 a& ~2 k
- // 基础类型检测 (`null` 意思是任何类型都可以)
, U& C- @# M& q0 B* ]6 A+ H* x - propA: Number,
% i0 U6 q# g" l t* { - // 多种类型( o: K0 L- z0 I' v6 c
- propB: [String, Number],
7 j h' U+ n3 |0 L9 {& k - // 必传且是字符串
! H, r) u! A1 P$ l - propC: {. J/ [; b* D( p+ G# U
- type: String,
! K. _: B- g3 @2 _ - required: true7 l* o V6 \- {4 n f( M" ]
- },7 @- [9 A7 U2 x4 p
- // 数字,有默认值
8 ^/ a L( F$ w3 g - propD: {+ A8 l( j; m4 e. Y7 f1 _$ o
- type: Number,8 |6 ^9 o, L* r8 ~
- default: 100
6 ^) g) x& r8 F4 a - },3 w5 s/ R2 E. }; k
- // 数组/对象的默认值应当由一个工厂函数返回
* I! d& s6 F$ L2 t \ - propE: {1 S- Q! R9 u2 j6 v6 O4 l+ Q/ Q
- type: Object,9 g3 \! f( j3 Z$ q8 H) p' u
- default: function () {( X9 S" `( m6 a L7 s! e
- return { message: 'hello' }4 i! k/ I% e5 e+ U) ?; R8 L" r3 r: {- h
- }5 O- h$ k( w: {4 i. T5 t
- },
* R7 _, s5 n7 W6 W# U. b- m% _" J - // 自定义验证函数
& w1 D! G. M# s/ ~ - propF: { O) a) c7 U; m9 J2 `9 I% `
- validator: function (value) {
3 M+ x9 r1 ~' ?6 f. P( o) t - return value > 10
7 W( L1 s- g# d- N" e- j1 S - }- Z$ W0 X" U- j7 C- ?$ R) [
- }
1 I1 @) e S: U1 w1 h - }
3 X( C2 E& F( d: b6 i - })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array- u) Q9 t, R+ I1 {, M2 c! M4 j* z% z
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件" i- ]9 k) H! q: o: K6 p! ?
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例$ @6 |6 ~/ e4 g0 r. g
- <div id="app">
/ R. \* P3 w- ] - <div id="counter-event-example">
% L2 B9 T$ @* Y4 T - <p>{{ total }}</p>
( N2 U) L w' i8 [ - <button-counter v-on:increment="incrementTotal"></button-counter>7 ]$ B* C' `6 ?( I2 _2 G1 l: q- o6 G
- <button-counter v-on:increment="incrementTotal"></button-counter>" d" W- ~* p, r) z( f
- </div>9 H2 D0 K; r7 t* p
- </div>" E! Y5 {' D% ?6 E7 i$ i: A
- 7 F8 r4 J% ~# v& E0 M! J$ N- }" k
- <script>$ h. f4 k: E# g/ ]2 f
- Vue.component('button-counter', {/ i+ ] N2 P# G+ ?
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>',3 b: _+ ]& T* r* p
- data: function () {
. P) e P8 `8 D7 g- H5 S - return {
5 A0 _/ O v9 ]8 t9 H4 { - counter: 0
: D9 x7 z, ^* V; w" ]+ F8 G - }
8 F1 g" K R5 N8 T& C - },
5 s3 e) B: `6 B, j) p - methods: {
+ Y6 M' v* o; n7 t" d- T4 ~ - incrementHandler: function () {
8 g/ p5 \2 X/ P - this.counter += 1) H' E- X* e3 E! Z; ?2 I, Z& b0 B
- this.$emit('increment')
3 x; ]8 c2 ^1 x& c' u1 C - }
1 @, z$ ?& `/ ~5 t - },9 E/ U. n& t! Q& \3 F. i' c- `; Z3 l
- })
8 u" G7 m; I6 R0 V- d! E2 W, d. [ - new Vue({5 p& E ~1 e5 ^4 d/ P+ ]
- el: '#counter-event-example',
& h, i* l5 y8 L5 O9 h' K t - data: {
: t5 }2 m# Q; w3 c, } - total: 09 \; k+ [$ L' h0 M
- }, Q$ n9 m4 ~% R
- methods: {
/ c9 O, F5 ?7 p0 I1 c - incrementTotal: function () {- s# ]( F1 N5 R. A: W
- this.total += 1
+ z5 r0 ]9 u9 W- x/ r- j# [ - }9 s0 U, \1 o7 A( X% f9 _
- }
4 l- f. ?8 S. y - })3 G% }- M( T T6 j! Y. W* E
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册3 y4 t8 |& o! l! b0 F7 I' _" f
- Vue.component('child', {
: B5 z4 t1 {+ S# u1 Y - // 声明 props1 [; r" G: K* ]$ D* ^ m# S
- props: ['message'],) R, _8 X# N$ U& o7 w
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
& c) t8 K& x- T& W - template: '<span>{{ message }}</span>'
% b0 D9 x% w) T+ Q# D - })2 k# a" z+ C( d
- // 创建根实例* B: {. ~( \. G2 M
- new Vue({+ S) ~* b. K+ _ C, L0 n: |
- el: '#app',
3 I. x# J# ?8 O7 P+ V, F- m - data:{
, ~/ |% z) G+ a+ p' n4 {/ U - message:"hello",/ t \. g0 g9 F9 \# Y4 ]- [) r% h
- }8 q8 L1 [9 M! E8 e
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
4 X' H2 Q% f3 R1 } - incrementHandler: function (v) {
5 ]' H1 J: f7 w- f3 I X3 D. F - if(v==1){
^0 i2 e6 m% A8 }/ z - this.counter -= 1
! A$ q. U1 @. ]# o8 [ - this.$emit('increment',[1])' Q# L3 L! C1 d6 M/ d- A8 E
- }else{, g/ `- @( F* V+ b2 X) ~" ?. A
- this.counter += 1
: Q8 |) i+ n5 t3 u! C1 T - this.$emit('increment',[2])
( ~4 E/ J: K( @ - }
! o4 H- O. F! j3 @; j - }
# _1 m' w. A+ e6 J7 G! k - }
复制代码 ; W4 J: _* a* o) K: U
+ v2 c- X% X4 K$ [7 A/ k! z2 g
|