组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
6 y( v; u0 w c9 c" j- <div id="app">
% h$ a. _5 x8 Y: i4 C - <runoob></runoob>$ d" ? I! f: R0 r* {3 m
- </div>( I: j8 f1 S- v* j: h3 F1 Z& z: M
-
5 [2 S ~* e+ w C! N4 [4 g; r - <script>
+ p0 T# Y: t. M - // 注册
5 \7 d, x2 Q- R Z, Q8 f - Vue.component('runoob', {
2 }& N2 A9 V6 p; d4 F# B9 S8 } - template: '<h1>自定义组件!</h1>'$ {* b" ?) W) C% Y( l" o$ R
- })* e: P: E9 E( F) m; n0 v
- // 创建根实例
; t. `6 S/ C/ f4 [ - new Vue({, R: s! A( ~6 N& A- N r$ Q
- el: '#app'
. H. i' i, _: E7 w - })* g' l2 V; a. {4 H
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: 6 f2 W; e; r8 q; R. e2 x! R
- <div id="app">0 t( U+ v4 S' `& Y$ k
- <runoob></runoob>) S6 y6 }- N+ y4 r/ O
- </div>4 F$ E, A* f0 t; \$ s+ R
-
* Y1 I! e6 F# W* \, B8 _ - <script>
! P7 \3 R9 O; R' g. | - var Child = {# l: h, Q" @$ G6 b! G# {+ M
- template: '<h1>自定义组件!</h1>'! |* b7 E, j3 m( h0 S4 n0 }$ {8 n
- }1 A; l6 q, t7 i; T# x
- 3 {3 V) @; c4 L
- // 创建根实例
- x" P; }) `3 r) h - new Vue({
) [* \. e; T. P3 v# G6 L, D - el: '#app',, a/ b. P* ~- `. N Z; f3 b9 c; O ]
- components: {
& g6 D( ?: |- S - // <runoob> 将只在父模板可用
- F1 @0 u' B! O$ ^8 S1 | - 'runoob': Child
; y8 d/ J* r: }1 E$ H2 M - }0 k {, O) ]: n1 n1 f. ^
- })/ @( Y( u7 w' F8 i
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例
3 p% ~+ X/ x* N/ N, w; D' X- <div id="app">
3 |; F5 \7 Z! ^! O* p7 M% I - <child message="hello!"></child>
9 ?1 M* ]0 f' R7 ~8 [+ W& L - </div>& Q1 k' u2 a3 \1 D& s* \
-
1 f8 J4 G( t1 G+ v. R3 _$ K - <script>
; I6 L2 N8 G& F, U, H3 z - // 注册4 ]) `0 U, Y( O) f
- Vue.component('child', {( Y" v) q& H( T! X! c/ w( M6 Y
- // 声明 props, m; P. ^) D1 \1 j. d! \
- props: ['message'],
, e$ O/ W( v& @" I - // 同样也可以在 vm 实例中像 "this.message" 这样使用
% W! X7 t2 i) k: a& O - template: '<span>{{ message }}</span>'8 s* w9 k1 d$ P
- })! t8 j* D* u: A/ N# x& k
- // 创建根实例0 Y3 r$ R- v- w* B% p
- new Vue({
$ l$ x3 P% `! c/ W) O - el: '#app'
N9 U# p/ L [' b: a - })
9 `# U; X' a" H% I5 [; f - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例% ~; v4 ^* b6 _+ D
- <div id="app">
0 a% _% q5 T- b" Q9 \1 ?2 K/ q - <div> j% Q* a" ?6 f- q" Z3 Q: O
- <input v-model="parentMsg">5 \5 O- C7 j M z, n; Z; I0 G
- <br>; x9 h7 d( P/ g0 p! ?
- <child v-bind:message="parentMsg"></child>) g6 W0 O6 w1 w% h
- </div>
4 z' q3 z& g5 H( W - </div>
% [* J: z$ p8 u* _& A9 H -
7 t% _' P e- j* }9 a - <script>9 E G/ e- G' j' b
- // 注册
1 I7 k( H% n6 {( ?2 U" v* c# r - Vue.component('child', {# d, @9 h6 |1 k, O; V9 U
- // 声明 props/ @5 M4 ~& @! x0 w
- props: ['message'],
( h3 k! ]9 ]. R$ K - // 同样也可以在 vm 实例中像 "this.message" 这样使用+ _4 b4 c2 E% m
- template: '<span>{{ message }}</span>'* I8 L, s+ p+ R; F9 w7 \0 J
- })8 y' _7 Z0 o/ ~) X% O9 R7 P; o
- // 创建根实例
X. c& f5 `8 F2 { z$ F - new Vue({9 X' [ D, D4 N2 X! B8 b9 J
- el: '#app',
' {; \3 J% A7 ]: Q. W - data: {) N! Z- J2 c- W% _# r8 i
- parentMsg: '父组件内容'& D# E/ o3 K2 N" Q
- }: C' m; y/ j. S6 h
- })% K: A8 ^% G c& Z8 U7 B$ f) M
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
' h% Q' q9 E3 ~- b/ [9 `: D- <div id="app">
; F! ?: _8 P: q/ Z - <ol>, A) ~% V5 J4 s% D9 w
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
5 G" T3 C: ?- {* I: k* {$ W - </ol>
- A0 M R9 j( d2 f# m5 z - </div>
6 D, }8 i3 ^0 g* z( Z - ( ?0 J1 L8 V8 g$ B+ a* D
- <script>
5 F. _1 [6 |5 f, O5 q" A5 s" [ - Vue.component('todo-item', {# k% ]4 O$ i3 {* ]
- props: ['todo'],$ d0 x2 J+ t! D5 u) v: Y% D, d( x
- template: '<li>{{ todo.text }}</li>'
- N, [4 e5 ~0 O9 A6 K2 G - })
) V$ u8 M' q$ R$ R& p" F" h - new Vue({
1 U$ L8 S8 k0 n) w7 x - el: '#app',% Z6 z* {# }( d" s
- data: {1 G o9 F0 W u2 v- V5 n0 `* _! ?
- sites: [
' ~1 g. ~9 a0 n: Q; V! i - { text: 'Runoob' },
# U& j0 C- B: ]& w8 ?, J5 a. G# E( k- e - { text: 'Google' },; k( ?' N) [: |7 p7 z
- { text: 'Taobao' }2 U H: E; t( v2 [
- ]
" S% \! L( P" I$ l8 T6 k5 y ` - }
8 {- C: F& D+ h+ @ O. m( x - })
" l0 T4 h; B _( v - </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {3 ^: `. J7 n& p, z7 m6 g) ~
- props: {
( ^2 a5 |0 P F; l9 e. d* a$ Q - // 基础类型检测 (`null` 意思是任何类型都可以). R j9 {6 z0 n! x: ]& U9 |6 f
- propA: Number,
- Z1 a! j; T4 |8 A" S6 Q) T# K9 ] - // 多种类型! d! \" _4 x# p; A, M, z
- propB: [String, Number],7 U9 Y; Q: q# q/ R k
- // 必传且是字符串) w: ~+ z4 ]5 }3 o
- propC: {
4 J" r' ]) D1 ]5 \1 l4 ^- v - type: String,
; E+ ~9 O# {: H4 [$ S# e& B6 f0 R - required: true: q& c, N: x) @/ W, b0 g
- },
- @9 F3 n) D+ q - // 数字,有默认值
6 A' _, O/ S; b R( L3 y/ t - propD: {
6 D5 s2 N8 d& o" | - type: Number,. ~1 I0 N$ A- y
- default: 100$ Z+ G Y2 `* s7 \- a" Y) j
- },: M# g: G, o: G" \& y+ g8 U+ d N; T6 T
- // 数组/对象的默认值应当由一个工厂函数返回; m" h( D1 i9 D8 L6 C
- propE: {6 f% {1 ^( Z3 u4 k' i0 s1 R
- type: Object,
1 G, Z+ t5 A" V; {" i( ` - default: function () {
! G) i/ r( s+ Y* P - return { message: 'hello' }- ~2 C& p/ n2 E/ s/ h# `/ X
- }
& ]& x: @- U- }9 Q! S - },+ l. Q* c5 p3 w. p q& N% W
- // 自定义验证函数
: P& I/ {5 K) `" n$ O x - propF: {
9 ^; a# M: |: g% B+ ?, V$ u1 a8 ~) m - validator: function (value) {
% Q; f- F. E v - return value > 10
# h( D6 e+ C1 s/ R- n. r - }. u+ l2 A* L, c I8 r( f P
- }6 G& \% y7 k4 t$ L. n+ g
- }
! |7 t+ k5 C) k$ _' E$ d( P9 A - })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
( ~8 a" Q. Y1 Y% y4 b5 I! h' N
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
7 P1 Y- J! V& V! P1 x" ]
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例. n& u4 ~/ F( a- L
- <div id="app">
1 D9 Y/ M7 f; _& Y" x - <div id="counter-event-example">! D' ?1 k9 u. A# ]4 E
- <p>{{ total }}</p>
3 D! H- U) k0 c7 B' A - <button-counter v-on:increment="incrementTotal"></button-counter>
% l7 o7 T6 G! u& a F/ I" {6 k - <button-counter v-on:increment="incrementTotal"></button-counter>
) I; j8 q4 P/ K3 E l! J - </div>! Y# g( e" N" e% O, k6 J, p
- </div>" M) O/ H8 l1 v2 T; h2 y
-
# D T3 ~5 y: n6 F; b& f - <script>
! S+ Y& W) N5 G& l5 s - Vue.component('button-counter', {
. X; h$ B7 p3 L/ ] - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',% y m3 |4 A) P( z
- data: function () {5 b+ {2 V) ]. b2 q' a! [
- return {
8 {$ Z& p; o: V; O - counter: 0
/ |+ E1 e. h9 h1 ]0 T - }
/ }4 ?1 }6 }& R, e) R - },
5 y) `1 ` h" Y! e/ O6 E - methods: {# n* }$ }4 D0 n4 ^
- incrementHandler: function () {9 W g% f7 H3 f
- this.counter += 1
1 f4 N( r7 _* b9 { - this.$emit('increment')( f3 l) a2 [" j$ }4 c
- }
8 O( j* f. b0 B9 f - },& u* U4 y; ~" T1 Z0 l9 }4 q0 u
- })% B: p! X! h2 D
- new Vue({
8 M& g4 r6 y. S Q - el: '#counter-event-example',0 D7 |$ Q3 w$ q
- data: {+ Q8 _0 C- b& j$ O3 y4 {* c
- total: 03 }" N# z8 R; p- u$ m) Q8 t9 E: B
- },
3 K/ Y. M$ P1 T2 v5 u% \% ? - methods: {
, j% Q) Y* j& k - incrementTotal: function () {7 Y$ Q5 }( v. V& N
- this.total += 1, G. @! e T( S* ?9 k3 C
- }
4 @8 ]% R' {) Z - }/ f0 ]% t% C6 M" H% r3 O0 i# ]
- })
( P0 a5 i7 l" G9 k# x$ Y - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
- G* @2 m8 g$ f# t8 L. S' m - Vue.component('child', {) n+ _5 P; G) Y+ {: E& {6 ^7 K
- // 声明 props( S7 j# \" P3 D
- props: ['message'],
" `+ o( z; c8 V - // 同样也可以在 vm 实例中像 "this.message" 这样使用7 [) k8 G6 z; F; q2 i5 I% C
- template: '<span>{{ message }}</span>'
2 w! t! T+ V4 s7 ?- a3 m# _' X - })
8 x2 x9 |1 w S9 n) m - // 创建根实例
3 p! p9 n: r) _ n) f2 a, ~; ^: q - new Vue({
; c3 b. T" o' m+ N! M8 ? - el: '#app',
5 @' L) K9 U5 G# q9 ~( g$ x6 v - data:{8 a2 L: H+ k, G( F. }) O
- message:"hello",3 Y* w: d0 P+ g' l* N0 a# i
- }
p5 ~* d9 f8 Y3 E/ |/ r - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {, m+ ^* W( F9 x: W
- incrementHandler: function (v) {4 j5 o# n& O- O2 m; N" p4 s) k `6 W
- if(v==1){
4 | r9 ?# J% O9 I. A9 D$ B6 o - this.counter -= 19 |/ Z' h/ w3 t; I% l. Z
- this.$emit('increment',[1])
0 h3 M# j1 }, Z. b$ h - }else{
& R# g* u# c: h; B( s - this.counter += 1
4 ?6 y& ]3 K* g# |" y9 j - this.$emit('increment',[2])
! S( r1 h5 N7 n) N2 S+ W0 |# n - }% s! T) a2 l1 e" a
- }; f9 E- r" m, C0 R7 K1 D7 j! p. e" u
- }
复制代码 6 L7 P5 B4 X4 i+ @$ n4 L
, t$ P0 x+ f, I- ~/ E* Q |