|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
' T, B; g* o% b' S% S- <div id="app">- [0 R8 e1 g5 _
- <runoob></runoob>6 ~% @1 T2 F4 T6 w; j0 a, S# W
- </div>
5 T1 ? Y8 z7 b, y" ` C -
& R% O: S3 K! @8 Z8 Q4 T" g3 N - <script>
* N- B+ F @/ \9 I4 E, B# S9 v* Y! V - // 注册1 j- R5 m0 }' e: @. J" {' A0 q
- Vue.component('runoob', {
8 ~* M. ]/ v9 E- J! e/ Z - template: '<h1>自定义组件!</h1>'4 G+ B0 o7 N, K/ A" }
- })
9 F5 z g7 B6 w - // 创建根实例: d! h* D" E- G8 z
- new Vue({# z* n. y& j* j2 l, \/ F8 _
- el: '#app'
( U! q# \* r3 [' q - })
) X w! w& ^7 |: c - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: # s2 |' X% b0 R* I! ?5 p C `
- <div id="app">5 j) P7 S+ G* l
- <runoob></runoob>
( }7 D1 K$ s, x9 w- D/ B( q - </div>
) F4 D, t% c* o -
! {; Y, k) K- q2 \ - <script>7 U* E) Z( c9 c: M$ P+ f
- var Child = {
/ Z; H( w& D: e0 M# u& L4 R - template: '<h1>自定义组件!</h1>'
% T6 j( `# h9 v( j A8 R2 a - }7 ^" ^0 P5 }) p4 |
-
% Z9 S! q7 m: V0 ^ - // 创建根实例
9 m5 _. t4 p1 j- B( B - new Vue({) A9 [5 o. c$ z) ~6 l/ b& T
- el: '#app',
) A$ |$ h* V' z# e - components: {' w: H+ I1 S9 z$ {
- // <runoob> 将只在父模板可用7 M. V' l! j$ E1 s4 h
- 'runoob': Child. R% t/ @) O* |( {/ a5 k& t$ C7 F
- }9 H! B0 h* ?/ `: I( R i! z' |% ^% F
- })
1 U5 }% _! Q6 l7 a( V8 P7 A9 v - </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例
: I, l1 z" S( {5 f6 h- <div id="app">- F' b, p% C* T1 t, \
- <child message="hello!"></child>
2 k0 k+ |" M9 V4 R$ H; ?+ @ - </div>2 \. b5 B4 H, V, t
-
: V0 ]5 t! |- E+ y$ N2 P( E- t - <script>, S4 V3 A, Y! G z' ^
- // 注册) n3 N3 G u/ Z9 p8 W O
- Vue.component('child', {' P7 g8 B9 h9 i9 b
- // 声明 props
5 T% p$ K/ h6 _- \/ T7 B+ L, n; R - props: ['message'],
2 Z* g5 i# e; I& Z - // 同样也可以在 vm 实例中像 "this.message" 这样使用
8 ]3 Q/ P7 o' c* j1 l( @1 y N - template: '<span>{{ message }}</span>'
/ k& k2 B3 v& ~) N - })
5 T3 S* z& n6 Z8 J; P; G - // 创建根实例
; }/ n2 d7 U' e1 \& p+ F" u - new Vue({
. L+ ^2 p, A( J) ^ - el: '#app'5 u& E1 e9 Z4 ?4 N! R
- }). p$ w% _+ k6 X6 G
- </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
5 u/ w( w, S: [) t. G' T* @- <div id="app">$ Y* d" @* r, t# y
- <div>; e" B `/ W( C1 e+ i* n
- <input v-model="parentMsg">
3 g7 H7 ^, E) j- b* X/ Z' e3 [8 z - <br>* G+ p# k) t2 W% a/ n8 ~1 w F4 R
- <child v-bind:message="parentMsg"></child>. w$ K( w' e) B: p$ `7 v
- </div>
& d, k9 X3 _$ F: I8 \2 \8 | - </div>( y* k, n5 P( t& D( c
- h) [2 S7 i4 V8 y' I2 B8 d
- <script>6 ~" K' u: T: S) L# T
- // 注册
9 D+ O/ `8 v' x; m - Vue.component('child', {
G) G8 T/ O$ ]. K - // 声明 props
9 M. g4 _3 q/ X$ G' X+ a - props: ['message'],1 r0 w, `7 m+ r7 e* J6 Y
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
7 [# z- O. z2 |% ^4 R - template: '<span>{{ message }}</span>'
" [9 s: [: }7 o5 A( z- p# H8 B - })
2 k; ]3 A3 \6 z$ M - // 创建根实例3 \# P- z& Q4 c& ?) P: @5 L
- new Vue({# V* s3 z7 \( U
- el: '#app',
: G9 |2 F F9 n6 b& w+ r- [ - data: {
4 b+ R; j$ q* Q) A - parentMsg: '父组件内容'
' R9 Q. b: }5 b5 U/ b2 z - }
1 O) q- ?: V7 _ - })
% Q! v1 f1 o* z. o: F; Y - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
7 D# q, R9 p. [) _$ o. u- <div id="app">+ [) d5 g- z& [& }
- <ol>
! G( x7 `" k0 O6 X8 |) K/ m - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
9 W" f4 f A, k3 f - </ol>5 U) F1 C, {4 Z7 J
- </div>
" N4 e7 \# `+ w0 p -
6 ~3 f; Y7 ^7 ^ - <script>8 I2 V" Z1 {6 Y0 {' i
- Vue.component('todo-item', {$ Q5 D: M3 a0 l* \ ~
- props: ['todo'],
% `, m* j) u/ W$ c- f$ w - template: '<li>{{ todo.text }}</li>'
3 F( e9 _: N) i+ @ - })
% A" {1 C n2 \# g - new Vue({/ t, N; ?2 M( k9 |2 ^& }. w( ]
- el: '#app',
1 Z0 o1 N' J2 u& J - data: {' m- E+ p/ U5 r8 ?
- sites: [
! Z8 H8 h+ _5 \) a7 k" m - { text: 'Runoob' },
. V1 `0 T* ]* }; R - { text: 'Google' },+ v$ p9 l! a4 l) P" t& e: T& @; ?; x
- { text: 'Taobao' }
. S) b0 Q5 ]. a% u' Q; s0 I - ]
+ T8 D& ]+ r1 m2 `: S2 y - }7 Z# w; h& }8 G: E. T0 W( [, w9 h
- })% J) p/ r' k( h5 l1 g. `$ b) y
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {# t9 Q0 F" C. Q4 L. Y3 ?
- props: {
/ o' ]5 m3 S2 Y - // 基础类型检测 (`null` 意思是任何类型都可以), M( \. o: {$ V: W: b9 d9 ]6 }
- propA: Number,
; X1 }" A9 u' ~' P8 `6 R - // 多种类型
9 Y, Q, R6 c9 x' E* ^2 ~ - propB: [String, Number],
$ K2 k# k+ M6 E; x& ^( K9 s; g; [ - // 必传且是字符串
0 V& d6 `/ h) G9 |/ x - propC: {
9 N7 Z \/ p1 ]# Y - type: String,
0 _- L# b0 v+ p- r2 N - required: true
- c+ ]+ `* r# M* L" B/ X. ? - },7 j+ o2 A' _; z* b9 g0 B1 ?
- // 数字,有默认值* P/ W8 n8 ?# Q
- propD: {
1 g% M6 @4 e; o: x - type: Number,+ U, K5 _, |! Q9 {4 q7 F P" _
- default: 100
( F6 k0 l/ K4 S - },
# E: f8 j, U: D. z' [/ a5 k - // 数组/对象的默认值应当由一个工厂函数返回
5 Y' q$ W9 L$ d- c9 {" D7 c( t - propE: {' V! h! Q, ?2 H. g3 L: m# K
- type: Object,
4 [4 s& F' a9 s8 G6 ?/ v - default: function () {: @) l% G4 _( N, o/ N
- return { message: 'hello' }* O! q9 s8 [6 D
- }
9 J$ G! W2 s( U2 [ - },
2 S- T+ @: r" l& s7 [. U+ s - // 自定义验证函数
& T) e% N) A4 F0 K; O - propF: {
. @1 b' w% F" Y6 o - validator: function (value) {- i) k/ Z" r+ i) h: ?; A' w& r: `
- return value > 10$ U( s; f* D2 F4 @# [
- }
$ E+ l& A" w" ^1 U7 c - }
' t+ i" Y& g1 v: x - }' z0 {, w* Q7 l4 e1 f( X6 Y
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
3 C. P6 X: A" a$ g6 ?+ \
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件7 o9 c) J9 ~, l, W t+ t4 X" {
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例+ F' o8 R, {5 L0 V
- <div id="app">
# y+ n4 a4 u3 y- y% M, f0 m* Q - <div id="counter-event-example"># n; O2 i8 _! G( Y8 A0 Y4 ^. s9 F! L
- <p>{{ total }}</p>
9 U: Q9 |; S t5 z: R; y - <button-counter v-on:increment="incrementTotal"></button-counter>
/ K4 f+ n0 ~) O3 W9 b - <button-counter v-on:increment="incrementTotal"></button-counter>
5 N# Z' ]; K# \" I# i - </div>
( i7 Z4 P" n- X - </div>
7 i$ G6 j0 f" Z# c( U -
& f/ Q0 D$ q |2 T! M, A8 A - <script>
6 q3 g8 F9 N* n - Vue.component('button-counter', {4 ^5 T# O4 D4 b) L" t
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
8 r! _- \. T- v/ k: Q | - data: function () {: @! z: f1 f. @6 v( W: r( e2 y
- return {
% i. ~6 w$ M C3 M2 h7 Z0 l% E - counter: 0$ m' w O1 H. {% ^. F' s, W1 U/ S
- }
. P' x$ u) z* I+ {' B - },
8 |; ]! `# E+ m) n/ f - methods: {
7 B: i2 X6 `5 z* b0 z0 } - incrementHandler: function () {
+ M1 A- k7 l. W* ]! b) M, w - this.counter += 1
7 V6 R( J1 |3 b3 ]4 e$ E0 { - this.$emit('increment') l5 `' O; z$ U) f# D1 g
- }
2 b9 r5 _ N& ?& s6 ? - },
; V1 u* {9 U9 \+ O/ M4 b) m - })% q |: t' n, L0 R) }5 U
- new Vue({
/ ?9 U& g7 F. l" t# r# n - el: '#counter-event-example',
' j) D9 B4 y1 A- y2 C- L, [ - data: {
$ q$ C& Z- B1 W" U3 f - total: 0; [) v# c# _0 {
- },! `' s7 d1 I6 Q: }: ~
- methods: {0 T# l1 r' ] f7 e- w5 h
- incrementTotal: function () {
* J" A; R9 K S+ r8 b - this.total += 1
' p5 Z* R' Y9 R/ m - }, s# ?3 Z" h4 ]: a0 ^5 T0 e3 N
- }
5 x% L% t3 t) T) z - })
2 Z2 a$ n0 y* l1 D& S+ X; b; n8 o: v - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册- h) d+ p- h; ^. }5 F/ F" T5 G
- Vue.component('child', {
) d9 k9 o0 C0 K( Q - // 声明 props
( I1 a% V/ x2 E" Z# B3 q! Z) D) y - props: ['message'],
' M' B$ w- o- j1 O/ e" T! \+ ?$ _ - // 同样也可以在 vm 实例中像 "this.message" 这样使用
+ K3 F7 C3 q1 j3 H& K% [! W: ]3 H - template: '<span>{{ message }}</span>'
8 q$ ~' \) J+ ]- Y - }). n+ @. P7 a! d0 o% d7 t5 f
- // 创建根实例 U5 }, g3 h# u4 _5 }; d9 Q7 E
- new Vue({6 y4 y1 P; Q) b7 h6 f; l
- el: '#app',
# h, ?4 Y, ^: Q* z - data:{+ ]" a5 v+ E2 x+ R3 J- q; J
- message:"hello",, d7 x, F9 }6 [3 ~4 @- N/ X
- }
k/ N! a- ]( J/ y - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
$ ]+ ?" k& Y, T! g. U# \ - incrementHandler: function (v) {) D: m2 \: L' Z( H; P
- if(v==1){
. N2 q2 [+ V, @- T$ X2 s - this.counter -= 1
& J# K+ a$ E& F. C: V - this.$emit('increment',[1])/ s* ]& [$ N9 z0 K) Z7 V0 Z
- }else{* M( R8 d) ]7 z& n7 c
- this.counter += 10 w0 |" M2 _* L7 v3 b* k
- this.$emit('increment',[2])- o9 {* W( y4 ?+ l8 a. D
- }
6 F0 j0 A9 z* o) z$ w) w - }
+ U& G6 t! B' v& N6 m- Y1 p - }
复制代码
1 U. J3 y" m6 |# k
, o7 d4 W; t& ]* z) L$ A. | |