组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它: ; F$ g, W; Y5 [% ]
- <div id="app">
k) g1 [/ Z8 }: Y - <runoob></runoob>
9 ^4 k- o, v' j& f1 m$ n - </div>$ ?) a( j; h( I8 Y. E* a) A
- ' s5 K8 v4 I O* ^' K& \- [
- <script>
" o7 H7 |( L$ ]7 x- Z* D - // 注册
# E; Z1 K) k+ q) ]/ |" K2 Z) v4 D - Vue.component('runoob', {$ E, t& C t9 D5 y6 Q
- template: '<h1>自定义组件!</h1>'
& F, q) [6 [5 k0 m/ I5 q4 s - })9 i( n! x; ^9 k' b3 W
- // 创建根实例6 t! q& |2 L, p- _7 X5 A' k* p9 R
- new Vue({! U/ i, Q6 x- \5 V
- el: '#app'
3 C( \# Y. L2 M; ~' b! l, e1 Y; { - })
" t% L: I6 |- y - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: % Z, \$ U/ X3 B/ A' M
- <div id="app">
7 ?% N5 M- \) o8 k, C8 P/ R - <runoob></runoob>
* [+ A% y6 t8 c# e% Y2 a. G* V - </div>
4 k, h$ l1 M! p8 x - , z% N" a9 ^6 |5 V2 b
- <script>
4 s1 [1 Y( m0 M; r4 d6 q2 ] - var Child = {
/ E, v* G5 f; P i; E6 m [1 M( L! U - template: '<h1>自定义组件!</h1>'
$ O9 o. j% a! U* ? - }
+ z, u( r1 K" {7 T- z) f4 T - $ m" V6 j9 p |- q9 j1 F1 `
- // 创建根实例; f' `4 r. t+ D: H& E
- new Vue({9 C! g# l# @ A# ^4 {: c
- el: '#app',8 }+ Y% K; r' I: _# L
- components: {6 W( s# Y5 l/ U2 C( V4 P+ S. v
- // <runoob> 将只在父模板可用9 w1 B7 w! n: k* Y
- 'runoob': Child
( m* E7 u3 m- } - }' ?& k+ b( h5 m2 [
- })
1 }5 m, P N# W( ~ - </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例
5 u+ ^# m! L$ m3 F1 e- <div id="app">4 f9 Z: Y) M8 ]
- <child message="hello!"></child>! ?. |2 \9 A I( F$ [1 [
- </div>
: y) Z. ~7 V) P -
7 @& \1 I6 V9 E1 |* t - <script>
; t4 r' }; B# v. T2 g9 M) X - // 注册
$ }0 B/ T; }+ a$ t9 ` - Vue.component('child', { x1 @( @2 n1 U5 w# Q& S( `8 Q
- // 声明 props( N/ E1 f/ f' k5 G+ _- J
- props: ['message'],9 @5 h& b5 s# K" W0 x; {9 H
- // 同样也可以在 vm 实例中像 "this.message" 这样使用' s5 T9 b* N$ U" o: i( c
- template: '<span>{{ message }}</span>'6 S' Y5 n% ?1 K1 f+ F; C
- })2 ?: i+ \3 J; Q4 D
- // 创建根实例
! I, Z m/ t5 w6 W% {: y# v - new Vue({% w" C$ h( A$ p$ m6 H" F8 K
- el: '#app': E# K4 L% b# m: c
- })
; |0 ], |6 d g$ c+ k/ l# |" Y- N0 ^ - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
& m1 f" S* Q" m! H+ y1 a- <div id="app">
/ _% M$ ]6 V/ h# c0 \ - <div>
. [) i& v% @& R5 E4 e6 l - <input v-model="parentMsg">
6 A5 l! a! Z3 U4 `! S3 e- A& S# v( N - <br>/ z- L3 Z* b8 ^$ o$ C# A! e' Z
- <child v-bind:message="parentMsg"></child>" g4 B. ^7 s( J. @8 u$ X/ }
- </div>
9 k) e9 ~% g* A K - </div>, y8 V6 I$ b0 Y
-
' l' [; w3 J3 P P, [ - <script>8 a% ^2 C- V. l/ \6 O# I7 U$ ~
- // 注册
9 c' @, B0 w( U' n+ J4 [ y6 M$ }9 ? - Vue.component('child', {
% j* ^& Z8 }- f4 q6 ? - // 声明 props
4 R j6 N5 W+ [3 w3 } - props: ['message'],# ~: G" J* i. G: H Z! |0 q/ [
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
& C1 z! o2 @: Q; y- A5 e - template: '<span>{{ message }}</span>'( B8 ^3 s! c, r, e* B
- })
0 O$ m# Z' f$ c; }8 T" p - // 创建根实例& O% c# ^* q9 Z" {2 D
- new Vue({
9 x2 d. a* T8 [' P& Y) z9 N - el: '#app',8 N7 k3 @. i* \' ~* R
- data: {
& W' V" s7 u4 ^0 H% G1 X+ y! L - parentMsg: '父组件内容'- k& b2 ^7 C+ p Y+ y9 y$ k j* r
- }
0 r }! ]8 S. ~" |! p7 S- g - })4 |/ c& x0 i- h/ S B4 n' ^4 d
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例9 S* ]5 X" a$ F& ^+ e! X2 \, J0 o
- <div id="app">0 l$ s \+ H, ?
- <ol>8 [6 ?; O7 T$ ^/ A. Q
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
4 m- N3 {, C$ z* l4 Y( e1 A' E - </ol>, i4 F# i) D. w# k/ S; d8 A" C+ G) b
- </div>2 j8 J: G$ n0 m. Z: E
- 7 n0 ?( K1 v9 h* W& L* t" C
- <script>. e: b# k' |6 p8 t) {: f( L9 L
- Vue.component('todo-item', {
3 v" N9 S3 v" u - props: ['todo'],
/ V% J/ Z. I3 D - template: '<li>{{ todo.text }}</li>'
' i8 ?9 J+ y, y# [ H6 ?. Z2 g& o! | - })1 _5 o2 e8 L, c! y5 y0 M
- new Vue({
9 e$ _8 A6 ?3 { - el: '#app',
# V+ o7 _2 e5 @* v - data: {
3 c% k# H. l8 k0 |) r* l4 W - sites: [- V; Z9 R* M" v- A9 f6 ]' r% o
- { text: 'Runoob' },
- Y* x, {* b; K( D - { text: 'Google' },. v4 Y" a- g& L8 |) H8 n
- { text: 'Taobao' }4 X7 U+ o# G$ t
- ]
& A5 E0 t/ U; Q7 _ - }
) t, q5 x# z% p: ^; S - })
) W$ I9 x9 K; `2 o# [% D - </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
3 G4 x; M \( S0 V ?1 { - props: {5 n# _5 a+ G7 u6 e- c
- // 基础类型检测 (`null` 意思是任何类型都可以)
) }" T8 o$ U7 O" R& O - propA: Number,
# X* O2 G8 B: g' c; P - // 多种类型
& @$ u7 ]0 }( n4 ^# v - propB: [String, Number],
( e6 L& i* t3 G - // 必传且是字符串
9 z$ N; S% J; v, T# Z- h+ g ^ - propC: {
6 v4 q$ k( p: \) X2 y) W - type: String,
" s# Z# ~5 s X5 m - required: true/ ^0 M% t( k7 _* f5 t5 [! v$ f3 R
- },# X3 H" g. X$ ]1 b& p8 P7 B) S' \
- // 数字,有默认值2 W2 ~% t! f1 L. v) Y
- propD: {6 B' p/ G$ M8 }
- type: Number,
( q4 Z L- m- k& J4 w3 ^+ t. X - default: 100( U4 \. `9 k E$ ?
- },
; o9 L( j8 N. E. w2 ?& [ - // 数组/对象的默认值应当由一个工厂函数返回4 O; H/ P% C& |0 {3 c
- propE: {
2 ]4 n" k1 W. F3 Q1 ] - type: Object,- }* [1 L( [( f5 q/ }: f) f( b f
- default: function () {
6 t) {2 L; N2 \$ \: Y - return { message: 'hello' }/ Z1 {; J" ~ o+ C2 q
- }
9 b% n) V- ^4 w3 Z - },
; O6 ?- q1 I" }4 T0 ], \% o8 m - // 自定义验证函数
) D4 `: m4 V! _* E5 J! \$ W - propF: {
0 j8 |/ q7 m7 k8 z" N! c* j - validator: function (value) {, L, k$ {: b8 `2 ~1 H
- return value > 10
6 \, M2 p- t0 J9 Y$ g4 ? - }& o$ O {2 C& n3 r5 [
- }. J. b7 A( q9 G$ i5 n3 S" c* G) T% p4 x
- }7 A {) J8 u4 W' E* h
- })
复制代码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
- <div id="app">, Z% j" V* p% I' z5 z# w
- <div id="counter-event-example">
2 B% f* _4 I- D: k2 x - <p>{{ total }}</p>
% u( a; E! F3 E - <button-counter v-on:increment="incrementTotal"></button-counter>
- f" V! k2 x V- k. v - <button-counter v-on:increment="incrementTotal"></button-counter>4 o5 e* l7 n: \- ~' t5 D
- </div>
. V" t% u' G) I4 @+ I7 A, ]; u - </div> M: w2 ]3 [( V+ S. S
- + \- Y+ p" x* w4 t
- <script>3 i( U7 F4 ~, ?8 a% z6 f
- Vue.component('button-counter', {
( Q7 e! ^, f/ Y7 i( f - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
+ ^$ `4 J! S( _; B9 [! m% n; a - data: function () {
$ E! P* K1 g# T4 M/ `6 y4 k - return {& P- Q& N' O, A [5 X1 q
- counter: 06 {, c- ^6 C2 L4 c) T
- }
; `! I& X! U1 A" A& J* B1 H - },+ O T% }0 ~6 k" p
- methods: {/ L8 `1 a6 w& w
- incrementHandler: function () {
, n, w8 e5 z4 D9 m - this.counter += 16 B5 Q, W) ]. f5 E; \; W$ f1 Q
- this.$emit('increment')
; Y- }1 T! u Q1 a - }
9 Z2 n2 @6 K/ _4 T8 f - },0 @, Q- ]6 E0 b' _3 r8 g! g
- })' y2 d' T' L- I/ F9 i Y9 r7 I
- new Vue({
5 x: y3 w: S1 g1 Z0 e - el: '#counter-event-example',
* Q7 b8 V( S9 Z+ w( I! g( a6 }2 A) N- F - data: {) f* A; @( ]2 ^: g5 ~* ^) d, `
- total: 0
# _. ~! H2 D9 ~) l/ w! V. r; @ - },
8 Y9 V1 P6 J8 Q$ z0 N8 J4 r8 J - methods: {
{9 D% T8 p" J8 T: g - incrementTotal: function () {
t2 l! D5 \' u - this.total += 1
* r# B9 N; O- q8 F7 O* F - }
& j* a+ B( ]) S3 {; E' {5 o" z - }" g: z! j/ k0 g! Q
- })6 ` A+ ?$ I( o! Y& I6 n* }) N
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
' E3 W p1 F! }) G. W2 v D% G - Vue.component('child', {
2 W. A# s8 i2 [. c: C$ W - // 声明 props- F y9 f5 U c. R+ ?) I
- props: ['message'],
, w% k. j# y- A. p - // 同样也可以在 vm 实例中像 "this.message" 这样使用
1 f! A8 o [: M( N' g( A5 r - template: '<span>{{ message }}</span>') M* G0 a8 S0 y2 F" k
- })
0 V+ Y% K: p) P% Z - // 创建根实例
7 ^6 \0 a4 X+ Y: n5 `0 }/ {$ b - new Vue({- A+ U1 c. H4 A) P# k" O! g
- el: '#app',/ M9 M Y$ J0 C% R. Q: {2 Q
- data:{* X! ]6 w5 u) o+ K
- message:"hello",& @ u# f9 x7 X. w0 m# [
- }
$ X$ |6 [6 _# u - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
2 _$ @8 v6 h# Y# j: O+ y4 `! @ - incrementHandler: function (v) {
! E$ p9 t$ g1 \5 X+ {* U) z+ B1 g - if(v==1){
0 v& K U9 S3 F - this.counter -= 1
, S \: f% \, _2 F9 ? - this.$emit('increment',[1])& `; }; c1 w+ m$ n/ E
- }else{
! p) w" E4 _- F$ i3 _+ \* ^+ D% f - this.counter += 1: r$ O( H0 A0 z2 N2 k1 W
- this.$emit('increment',[2])
8 P' D. P4 b3 |9 p5 s - }
) b; U* ]9 b# \% G0 \ - }( G# V) j% _1 e& P5 u/ U" ^
- }
复制代码
* s. k' Q. s" k* k1 w
% S9 a% `0 G4 z( b! R( S9 g |