组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
& l; G7 t2 k, ~5 u% c5 K- <div id="app">, c$ F; W7 M* g0 a7 \1 K0 h
- <runoob></runoob>, [0 B E0 m( E* e
- </div>1 B) l/ F. h j: D
- / t% H1 o, B+ M" T) O& g& d3 a# y
- <script>
' m0 I3 P& X/ M! j6 D5 ]7 ? - // 注册
3 Q: P$ n$ ?/ }, p5 h3 l$ P- t& I; a. s - Vue.component('runoob', {
' q& z8 @' a8 Q1 G! } - template: '<h1>自定义组件!</h1>'
; L; ~ B. k6 O! y - })
_- y7 s: W, `0 o( Z" T) M7 z. G - // 创建根实例$ e4 ]* ^4 n9 X! E. D
- new Vue({
# F$ `0 O" D0 f - el: '#app'& `; T5 j* e$ L8 R0 D" e' n
- }) [9 h+ `$ K$ P. A
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: ! e; B7 }/ S$ @7 g. v/ C! r9 S
- <div id="app">
( E3 I% S i; X: A7 ^( R' X z( [ - <runoob></runoob>
, F# P0 A0 b) T0 l5 [$ c/ X - </div>, o3 \7 r% s Y! P' T% d4 \* a
-
; J: n+ v# x, ? - <script>7 i. Y3 i! U& c; O
- var Child = {% l. q/ _* m! U9 B
- template: '<h1>自定义组件!</h1>'$ R( @- e$ R p
- }
7 ]# f7 s* W( \$ ~; r -
5 u# @% u8 q) m9 Q& w* B$ o - // 创建根实例4 s1 s. a- K7 ` f* m6 x" A
- new Vue({ N- w$ _: C* |9 i% [
- el: '#app',/ z2 v( S. R/ M2 b' R$ M6 `
- components: {4 A% o6 W H" f# S6 o8 e+ G9 L
- // <runoob> 将只在父模板可用" R4 k! F/ j% I6 [& ^' a2 d0 S5 h
- 'runoob': Child5 }: ]+ [6 s5 w
- } r) x! F7 x( ~- q9 q
- })
* D2 I8 y: m7 p$ L( ~ o8 n6 I - </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例
& J: f( C0 l3 o2 X, n$ J- <div id="app">
% f% k$ {* |4 E$ q# b, A& d( X0 `' e - <child message="hello!"></child>
6 f. M, D2 Q4 u8 ~4 o - </div>/ D# z* J s+ `% w; R) b4 m
-
, h# ?5 r$ i5 Z' M - <script>
/ R2 W j( {& y" J- e* N - // 注册: a/ V3 M7 \" J8 w
- Vue.component('child', {
5 ?9 [# s8 b% m: a+ M; _" S$ h" ^ - // 声明 props+ E2 j2 B m/ s9 @8 _
- props: ['message'],
8 p" Y% b) n9 \! X. y- w - // 同样也可以在 vm 实例中像 "this.message" 这样使用
/ K& [% I9 m) X' S - template: '<span>{{ message }}</span>'7 a- o; n8 J. j- c" Q* I
- })4 S9 N! H# G' B; p
- // 创建根实例6 f' h+ C7 ?( m+ {: y
- new Vue({
6 H& u& L! r5 p. w, O4 ? - el: '#app'
I6 B! h6 v" P, L - })
. e/ w# x, [3 V0 E - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
0 K0 F5 c) a* {7 G- <div id="app">
3 H9 \$ e$ _( r" o: I( \% R - <div>* o2 G; L% c% o4 f- X
- <input v-model="parentMsg">
/ x. [4 j8 r" M0 h% B - <br>
% ^: a( Q N' L: I2 e$ Y1 S - <child v-bind:message="parentMsg"></child>8 r! o" c+ q# ~$ Y; L1 O
- </div>
3 z6 |$ e1 u4 O - </div>
2 ^# {! ^- C: l7 ]4 A( X6 L1 K -
9 ]4 b8 O8 c4 R& H5 K" O, V* L0 [ - <script>
3 R* q' E, @& c) j% @8 \; p7 m3 f - // 注册4 E. o' ^# g0 d# ]1 W- |# S/ D
- Vue.component('child', {
1 _1 Y; R w: \ u, B, f% Z - // 声明 props5 X! D. ]7 H$ ^! a- v/ a1 `0 U3 W
- props: ['message']," P7 s% o6 `! ?5 Y4 i9 M& q5 E( [$ c
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
& K; R5 d- V4 K7 b# o+ y - template: '<span>{{ message }}</span>' {8 F! N1 Q" B: \
- }): u/ T, [+ b( R% K5 [
- // 创建根实例
; q, b0 f0 z/ t/ b - new Vue({
i1 t* b3 s) m3 [ - el: '#app',
+ L' R# d$ K/ U/ K$ \0 Z - data: {
' ^2 x# V2 v# m' Q) [ - parentMsg: '父组件内容'
2 p9 |" j! v* U: T* v; T7 ` - }5 K5 N- Z- S, h: N4 L- Q
- })7 U! ~! ~+ @) E
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例# ]9 [4 i. c- g
- <div id="app">$ v+ `7 \# g4 u3 y! y' q
- <ol>
" a4 N D9 N3 I7 h- C2 q; Z8 I) H4 d - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
8 j4 v) i1 c! ?1 x1 _" U. _ - </ol>
+ \3 Z' x5 T0 A7 N" f$ v9 t' G - </div>3 q' J* [( O0 X& K- g0 n" @$ i
-
0 z( S9 M% ~- l2 _ - <script>3 l6 |! H( N* d$ q
- Vue.component('todo-item', {" [4 b% X9 g5 Z4 B! K" t4 f
- props: ['todo'],1 f+ S) k% E! Q* _" g _
- template: '<li>{{ todo.text }}</li>'
" T% h0 s! j8 C+ j" C+ z - })
3 `/ K5 ~4 l* \4 J% W R- G2 h3 J i - new Vue({
* E: a9 _$ j# d7 Y; ~: F; o - el: '#app',- }, U# u" [4 c! l- ^/ i. D+ b: b& ]; S
- data: {
; H/ M( [( T6 q- H3 p# u3 z# A* @9 h - sites: [
% t6 |* B) @4 u+ R% [ - { text: 'Runoob' },
* b5 {2 ?3 Q/ _, J - { text: 'Google' },
; k1 h- T8 A: u - { text: 'Taobao' }
( P) h* z% M3 K% a" l! J6 M - ]8 D# e2 O2 d0 k5 m
- }
3 c$ [ ]% F! M) S3 l% [8 K - })9 a6 u+ U% y/ ?1 b* ~( @/ t! Y
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
1 @: }, F" r$ ~( e - props: {2 M, u9 |! n9 F% a0 h
- // 基础类型检测 (`null` 意思是任何类型都可以)7 x0 I- P* Q! }8 i5 w* ~
- propA: Number,
/ B) I4 ]. B' e7 _4 P - // 多种类型
. p$ {7 G- g0 }. d - propB: [String, Number],
* k$ ]+ X# q+ F+ i/ |4 Q - // 必传且是字符串& k+ r& S* |* j1 I
- propC: {& E( m( E+ ^5 D/ Q: }* f6 }
- type: String,
6 R. \) O. d3 o; n) b - required: true# t5 o& O$ |/ V+ \# [3 s
- },
@& j L# o9 f- I - // 数字,有默认值. }8 p8 l: a. c
- propD: {/ ]& U- q7 y6 P8 _
- type: Number,
) W- U% n; m' e* ~) c- l - default: 100$ }8 r1 ~" { k; {
- },/ Z6 B3 O+ @8 a, P, A+ }* M4 N9 F
- // 数组/对象的默认值应当由一个工厂函数返回- y$ `( i Q" p! a" t
- propE: {3 ~4 H N- x: q$ D' M2 d
- type: Object,
, K0 q0 n, m% ?( T6 t8 q& @! l9 Z8 l - default: function () {1 v2 c# s3 d$ Z4 \% G4 M4 T
- return { message: 'hello' }- p$ t. A- l6 T% [4 J4 f
- }" X/ }' |8 a! N' F+ i, R L' s. f2 M
- },
V0 u% n8 g! S' V% w' B. \' R# R - // 自定义验证函数
1 f r5 W& L6 K( u* Z, _& r: d - propF: {) }& v7 A4 s0 v1 J
- validator: function (value) {
) E( \: O6 Z1 U2 Y; i! o - return value > 10' J) y G. l& ~! P7 T" A
- }
0 C! Q u; Z& Q/ ?+ R2 d - }
% w8 k5 ]: L7 o1 j- K! X - }9 s& F0 E+ t7 q g
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array4 o; h4 ?+ r# C& h/ a' S+ l9 `
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件) J% K7 B& z1 ~$ ?
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例
" |9 G8 K' w" ]5 @- \& O- <div id="app">
- v* C7 s4 J- ~" A+ E' ?& Z! ^ - <div id="counter-event-example">% M( e, A7 D% n9 N5 M4 Q1 |
- <p>{{ total }}</p>) U. @7 z. V0 k
- <button-counter v-on:increment="incrementTotal"></button-counter>
& I& v. Q- G, ]! [ - <button-counter v-on:increment="incrementTotal"></button-counter>+ C5 B6 {" g! @% V
- </div>: b% T. _) k, S+ c$ m! t V
- </div>1 Q/ S! y/ G, ]: [9 Z( J, L6 e4 v& o
- - R+ z0 z$ F7 ? E. H
- <script>
3 H& I+ {4 W, Z- ~3 ^3 l - Vue.component('button-counter', {
9 R5 O% V2 z6 y- G2 b! s5 o' Q. u$ A - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
3 Q5 v- m) f1 K! t0 ], Z - data: function () {
& e' ?% Y( c7 k. u5 D$ b5 v - return {
! ~4 I3 ~9 m( P' d - counter: 08 l. I5 G6 [& I6 h
- }
1 A5 y h0 h' k2 _ - },
" d8 H# P: b8 j5 w2 V: R - methods: {
- p8 r/ w: d3 @# k - incrementHandler: function () {6 ` w# F9 C% k4 z' q
- this.counter += 12 q; H5 D B7 H$ ?9 V
- this.$emit('increment'), Z) Z0 B7 ?, z' m
- }0 {2 C9 a e6 J5 s
- },
& k! p$ q: x5 g. e; F& M- h - })
4 L" R; y% i9 H - new Vue({! ]+ W+ X( a, o; _* H0 A; y. Q
- el: '#counter-event-example',
7 O/ i+ Z5 i( u2 G m- X( t9 w - data: {
) D6 r( z4 a+ L+ } - total: 01 @- u9 H1 N( d
- },
0 |; d% [! t4 X! @* P - methods: {( I& F2 J( w0 V2 y' w+ p* {4 P
- incrementTotal: function () {+ R7 v6 y. T P
- this.total += 1
5 d3 ^& I% E6 p5 [ - }
, v G- c' a% C' ?( |( H. K+ L - }
) {1 b, S: X, @6 r3 _" ^" ^ - }); n+ [3 L' s E, j
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册* Q: L D$ q# ? O( [0 F' J' A( l0 G
- Vue.component('child', {# P- d m/ P @
- // 声明 props
+ p8 T8 o6 t- k* H5 Y# h: J; [# S; A - props: ['message'],
1 d1 j1 A! ~% F! h. @. ~ - // 同样也可以在 vm 实例中像 "this.message" 这样使用
% [$ C$ d" c9 c( |* L - template: '<span>{{ message }}</span>'
# p$ [. ?& U3 ?* E - })% p, `8 n. M7 c; ]: G) m1 |
- // 创建根实例
) b# l* Z' _! M - new Vue({7 z, T% P1 d) [5 ]. U
- el: '#app',
; s9 f) T: G3 g6 l) `: a - data:{8 g) o( }4 g3 I9 X2 @7 E, @6 T; O
- message:"hello",
! N. w7 d* B; U# {' B - }1 G! l0 [; z: K" \; y% ?
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {( E6 d1 T, h7 E5 i+ x
- incrementHandler: function (v) {& K' C; m% {& C# [. S0 ?
- if(v==1){( |5 U2 ~5 X e- f2 i
- this.counter -= 1
: a( t, L' T1 ]9 K1 X: b J% C - this.$emit('increment',[1])
4 S1 Z! K* d2 \9 J; Q$ n7 m: M - }else{
& {, r1 [( O+ F- ^- q( M$ X8 V* Z% ^ - this.counter += 1
8 ^( _! H5 ^7 `# A - this.$emit('increment',[2])
1 [% t8 @; Y$ m& s, |: I - }
4 \- Y* V8 N* E# ]9 N - }% H2 L2 I. h5 z* Y/ E! O0 K9 J
- }
复制代码
?, R0 r4 x1 L4 S6 Z0 s# t
5 A8 Q! H( c7 U- j) v$ G |