组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
3 q/ F7 W+ D* L3 t- <div id="app">% |; j4 q6 f: X, c$ o! z
- <runoob></runoob>. y* Q8 {3 v2 w* V+ D
- </div>
# s; n u+ C% [ R: I) g/ h! @ -
% ]( ~7 e& J# V2 n+ T - <script>) l; Y/ Y! G/ |7 h
- // 注册3 H) K9 f5 C+ C, S' m9 i0 ~
- Vue.component('runoob', {4 `, {2 M/ o! F/ O# U8 ?
- template: '<h1>自定义组件!</h1>'
0 g& y m; F0 [) j. Y8 H- v - })
) S$ c: V5 N1 \ - // 创建根实例
( J! G B) o+ P) O: D$ C - new Vue({
6 A* n" O* V7 @+ Z - el: '#app'
9 \) u. n9 g @ - })
5 O9 o6 g; Q1 k, W% u* m& Q( @ - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它:
! R2 O- Q2 o. y- <div id="app">
% S) h: S# v2 C - <runoob></runoob>
9 X# S, F$ |+ L; w- Q - </div>5 {7 v' T* e) V- b8 N" [$ T0 h
-
, s2 L4 X6 p7 _. B- ? - <script>/ I: |3 `6 z' U4 V" v5 S" b
- var Child = {& P' r0 a, b4 U3 u! I) b+ S1 u4 t- f
- template: '<h1>自定义组件!</h1>'. V. v- u: q2 [7 D. b
- }: r. K( U- l& N
- - U- V& l1 J% c+ ]" R- K/ l. Y( K
- // 创建根实例
' r5 g: V4 N: R, w" G$ [7 P - new Vue({9 `" b6 n3 L: n! x( s# L
- el: '#app',8 k4 e& T8 ~5 B# S- q
- components: {
$ @/ b+ }7 k9 l p& V - // <runoob> 将只在父模板可用
. G' w/ _4 ~$ a - 'runoob': Child- t# E$ _ ?8 L- O
- }
( c6 Q% F, T" i! G0 s - })5 K9 y* k6 y, p7 S# E/ n
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例& p+ U9 n; ~4 D: B& [, T7 z( r l
- <div id="app">
- Q- G1 o2 h1 \) \& S6 Q G3 P - <child message="hello!"></child>- v3 L) \& T3 P4 q$ [
- </div>
, C& q2 A- V! [3 a, U+ K -
0 n1 m9 Q O" T. V$ A h0 _ - <script>
- K0 t% t9 g* S - // 注册& ]* Z3 d+ a7 W! c7 Q
- Vue.component('child', {
: S4 ]- f0 q( u# P1 I - // 声明 props
3 D. k' \% z' p - props: ['message']," A( Q7 \) V, H& n
- // 同样也可以在 vm 实例中像 "this.message" 这样使用: Y0 x6 B) S6 t$ W
- template: '<span>{{ message }}</span>'2 G4 P1 {9 ^4 Z
- })4 t: q7 l4 a5 ~1 R
- // 创建根实例
8 _ Y" L& N. A y - new Vue({; }7 e0 n) B5 n* X u. `1 U
- el: '#app'
i6 [# t: _4 x - })
5 j! q6 n, N5 {- }) L+ x! p' w w - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例9 Q1 v. k( J* L" I
- <div id="app">
/ j8 O9 t8 k+ |( c2 } - <div>
6 S5 u0 D8 Y* R# v- M: w - <input v-model="parentMsg">
7 `$ Y0 ]+ B4 z; N/ i2 n( s5 R3 ] - <br>2 h0 x* o: g$ X' }4 n
- <child v-bind:message="parentMsg"></child>2 X7 h) u- g/ d1 P1 B( k; [( ^
- </div>3 l/ Y% j, v( N0 a! r; F6 E; w' T
- </div>+ x/ L1 @+ y/ ]8 h, i- `' B; T
-
+ m" L7 [# H; q/ F) k6 K9 j - <script>* y ?. Q/ O2 ^, b, {0 H0 q" b
- // 注册
8 Q, |1 {8 s8 m+ |; F - Vue.component('child', {* Z. O" G! E- [, p8 G
- // 声明 props8 b& A ?: j- M- Z, e( L/ j) E
- props: ['message'],; e# W' G* o& a, e! _! V# ^3 _
- // 同样也可以在 vm 实例中像 "this.message" 这样使用5 Z# J& @+ X' U P8 O Z1 t: F [
- template: '<span>{{ message }}</span>'
4 [ K5 Y$ T3 p% L/ C" | - }); R( b, ~9 b5 C; N m8 Q& b- Q
- // 创建根实例
) X. D# L9 K% Z( A: e! g4 n - new Vue({
% F" Z7 c% g% f$ @ - el: '#app',
! J4 \/ r( t1 S1 I" x5 S4 W - data: {
& g' m4 a1 F$ H) _# Y j+ }% S - parentMsg: '父组件内容'+ F, ]. T1 a" G% a6 y
- }
' [( z; k, Y4 f- a$ I# }" W! i( v - })- x l, ?8 U$ m' f, K
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例# \" u% E6 a, g4 m) w8 v
- <div id="app">1 D5 e8 p1 o( K Z* j r, d
- <ol>
8 {. {/ U" Z7 K) B$ ?0 j - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
- u7 p) h) t8 Y. r( M4 J( r - </ol>
/ u% R+ d6 C( }- ~ - </div>
- r) d+ e w+ W8 s, Q. z -
; |8 M! m. M, J% ?0 X) O - <script>* e5 X. m* G n1 o3 e
- Vue.component('todo-item', {, h+ F) w) h: x5 [7 z* u4 r6 O3 Y
- props: ['todo'],
- N1 Y5 j2 K' ] J# F% \1 n - template: '<li>{{ todo.text }}</li>'
9 c+ W1 {/ z! o2 T7 T& T - })
/ Z7 b* P! j1 j5 \ - new Vue({
4 ~4 z2 J$ T; s1 e - el: '#app',
, ~/ a9 I. d: O& X" E - data: {
6 s5 ^5 R* t# Y1 @/ {. y - sites: [
, v; ]% `. w. _ - { text: 'Runoob' },, k$ v2 t' @5 [& D
- { text: 'Google' },+ W4 `( k/ A- K0 Z3 x8 }! t1 Y2 F
- { text: 'Taobao' }
* ^2 G6 I1 Q: K4 t - ]) R8 i5 l g l+ y
- }
3 V6 c& R9 c5 i5 b0 p) H/ r# } - })
& {5 U# Q, ~% U - </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {9 c. `3 R2 f, ]/ Y; X7 J
- props: {
" I- Q/ a# \; a0 x - // 基础类型检测 (`null` 意思是任何类型都可以) m q, t. C9 I. S; k
- propA: Number,
8 L* Y& V! y! W1 L - // 多种类型
l2 y. C* h& v1 Z8 s$ c - propB: [String, Number],
9 N; { d! c6 `8 N' S+ G6 ~5 y7 M - // 必传且是字符串
4 F- q/ Q% Q" Q - propC: {
3 ^' U) y6 C; |" a8 N2 U2 E z3 y - type: String,
8 u# G2 y, g0 R - required: true- D8 m# N3 q3 y' M
- },% b" Q9 |9 m' E
- // 数字,有默认值
- r; Q# F) t$ o4 ` - propD: {) ?* Z$ Y) i8 v9 Z
- type: Number,# r1 G% W' d' I3 I
- default: 100
( Z6 S: }6 a4 _6 P - },
4 \0 {) Z( [0 a1 [: V0 A; ^ - // 数组/对象的默认值应当由一个工厂函数返回
1 }) R* Z+ b6 j# n - propE: {0 X9 f" @1 U0 ~( z; u8 B
- type: Object,3 a) G$ P, i3 I6 {$ b* K, ]1 k5 z
- default: function () {
$ [& w1 ?* X( v8 H. ?3 L - return { message: 'hello' }
2 x8 p7 A+ v' ? - }
; }9 N) e0 {# X$ q3 g - },
9 s% V/ |2 d( [3 ]0 @ - // 自定义验证函数* l. T6 }7 G) }2 ~1 n2 n
- propF: {0 F/ A; F* f0 _/ `
- validator: function (value) {
: a r8 O) {& N/ z8 ]' R - return value > 10
1 w* M) z! x, j" d* j; q - }
+ K; Q9 w. @* P- [* b! I - }
% i$ a( L$ c, R4 K& |7 G5 Z& m" { - }, z \# q, Q5 d5 J
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
- n: y% J3 U& I, Z# U9 }
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
o1 o" o. G7 v# _3 H) }1 `
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例% K2 c w6 T# V# \( t
- <div id="app"># D& Q7 Y. ]- E5 K7 ~4 E' K- @
- <div id="counter-event-example">9 b) T6 E# Z* o
- <p>{{ total }}</p>
& j2 } u3 [ j0 |- O* m - <button-counter v-on:increment="incrementTotal"></button-counter>2 O( A ]1 O Z; O4 R5 i( G
- <button-counter v-on:increment="incrementTotal"></button-counter>2 ^( l1 E% L5 i
- </div>
4 t; d; y( ]! z/ u' X - </div>& Z) ?* B1 }; G3 m: v9 d2 z: V
-
* ]5 p) {. z6 F. C+ Y: R - <script>
. s9 Y, a2 |2 z% X4 D3 } - Vue.component('button-counter', {% r7 j9 E' B& o4 L
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>',0 I) O: s; Y/ S1 q, o; |
- data: function () {
( ?0 d- l2 M% o$ f8 r1 W4 d - return {
( Y% b) `8 l( j* s# U' H7 n5 @& T - counter: 01 z. H9 N- d+ ?" V% f. }1 |3 h
- }
9 L! a8 I5 U" \* P# ] - },
& b. \* ?+ Q- r - methods: {, A1 r/ Z" D) C8 a8 n5 U
- incrementHandler: function () {
6 j% ^4 Q$ u3 k# i* i7 s - this.counter += 1
2 |! x' O6 a# G1 z+ X4 C - this.$emit('increment')
5 R1 O1 g' l# B2 s( u6 C - }
- L# e( t- x, p# L! O - },/ A, p4 z% c* Z
- })
! `: ~. G3 W9 x# m4 _, t. o: p - new Vue({
2 M' |% F& t% j+ S - el: '#counter-event-example',0 b p8 {& M, [" W
- data: {
$ B( M- T# v8 U1 b; {4 n - total: 0
) _/ y; t1 o3 k# \ - },
$ I& Q( i8 s- m0 l- b' R/ t: _+ V - methods: {
, c+ e0 q. D# H3 Z. |! D% d - incrementTotal: function () {) b, `4 F" p- I1 T0 D( s
- this.total += 1! ]& |0 S8 U, h7 z, j% ?: U# b: ]
- }$ z1 A3 b/ r- b# U% F$ X
- }4 ?: E0 s( n- l" [: w6 p; B
- }) ]) x, G7 \4 E& g6 q
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
) F' r0 r% t' o - Vue.component('child', {& f+ H5 w2 h4 ]
- // 声明 props4 v+ J: E% ~: F" G6 ^) D
- props: ['message'],
* k! V: W0 a2 x5 K* k3 f# h - // 同样也可以在 vm 实例中像 "this.message" 这样使用% B: m9 J, m- ?, @7 t
- template: '<span>{{ message }}</span>'
! B- S+ `+ j( W - })7 Y, U+ R- e% u+ ^4 R
- // 创建根实例& R% B) e W% M$ t3 E/ ^+ Q; w
- new Vue({; Q: u) p9 F) K
- el: '#app',
+ Q. w' u+ a6 E - data:{: v+ ]% s3 D2 B4 `5 G) `' R- i
- message:"hello",( ~( x4 f/ k1 G7 i
- }
% C" L7 j4 i4 K' T) z& u3 q9 h% D' t - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
! j6 z1 G' l8 e. T$ ~2 j - incrementHandler: function (v) {
+ Y6 C* U7 I, J - if(v==1){
4 |- s, T' y0 [, t8 f5 Y7 C( \ - this.counter -= 1
5 q$ F( I/ ~1 E; \# W/ B2 C6 l - this.$emit('increment',[1])2 x$ K! Z* ?; ^; `# `& j
- }else{; u( p" G4 i6 O# Y
- this.counter += 1
) Z" g" F6 O1 N% c - this.$emit('increment',[2])
- y9 i5 F) b V k# S! F - }+ M& Q+ {1 b; X/ a( |3 k0 t
- }+ }$ m4 w( t) U' O8 k( M! K P3 n
- }
复制代码
2 ?. X$ Z! @4 B# F% [5 B* Z
9 n8 }. F- R1 _8 D |