组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
) c6 D8 P- k# C5 r- <div id="app">
) l& z: \# W' b' V1 { - <runoob></runoob>
8 n& x. g- W3 @1 i7 ~- w% U6 d" b6 Z - </div>
5 b. q) A8 u+ m( e& Z0 ?8 u4 ]. O - 4 F, E5 b1 L* w% Q3 g
- <script>/ ?2 v2 Q! b* r! N
- // 注册
: K {) m r) ~7 l - Vue.component('runoob', {
/ o7 |8 \6 T5 r: K - template: '<h1>自定义组件!</h1>'
. \* {, C! {* |. Z - }); S0 N) e# b( h8 s4 ?$ Z9 c6 }
- // 创建根实例
+ G: Z7 k1 \' T5 J' ^( b+ o$ a$ n - new Vue({
1 D" x9 W7 x) E$ O, S/ q7 u2 b - el: '#app'
& W/ k$ O5 Z! p* |0 u% r: b - })
& n5 A/ x3 K; J* `4 D: P" v - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: # q% ^3 x g8 W& m) g' Y' R" D; U
- <div id="app">
9 h8 ^" a, I9 ]9 X( ` M - <runoob></runoob>% G% R" a( `9 N5 u+ h# F
- </div>
2 h8 i7 n9 I0 V! `' h1 F5 y% O -
# c. @& S/ e/ v5 M5 @; h4 o9 A - <script>& H: o7 b: |2 U9 R/ [ d
- var Child = {8 c# {0 Z% S' W2 }. `; U3 H# o
- template: '<h1>自定义组件!</h1>'. I X' w3 f4 C6 Q1 M
- }; a; J, n' v8 G! [5 A8 O, |; e
-
. F6 a; r! t, C0 ^ - // 创建根实例7 m2 @% Q, E, T$ L! p9 S2 D
- new Vue({$ S& C% |0 U# g2 l% U7 g( @( r
- el: '#app',( @8 I3 Q1 e+ L8 U/ K
- components: {& h3 v1 j G6 x8 s& G
- // <runoob> 将只在父模板可用
% t! p4 ^. c8 @% O+ w6 A9 h - 'runoob': Child5 u5 T ^' i' e) `/ l9 _- ]0 f, W2 I3 n
- }3 p: m! q3 l; j
- })2 t2 b8 f* C5 K' m& W, r
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例, I+ |1 |7 |; \3 L
- <div id="app">0 w- B% X0 C; _# W
- <child message="hello!"></child>
0 z% [- s0 S1 e6 l7 H - </div>
8 v. r6 _# y; N6 D - ' a z% j& u3 d. g, { u
- <script>( W# O2 ~( b& Z+ ~
- // 注册
2 f0 o/ f; w G( ^9 y0 @& V - Vue.component('child', {- i8 O9 S/ [9 a ?1 }; w
- // 声明 props
- ^. Y, b# c# A- o! M( m - props: ['message'],
9 b# X3 e- ?5 S - // 同样也可以在 vm 实例中像 "this.message" 这样使用" d4 D* \) q7 l' S1 ?% d
- template: '<span>{{ message }}</span>'
# W7 |. c* j& B, |9 z7 m8 R( Q - })- O1 j4 Q) f3 U) D l- [# {0 _
- // 创建根实例7 Y- u/ u# w+ G, c: @% t
- new Vue({
0 z7 L4 K; p% J) A; e - el: '#app'1 g' I9 }5 {) B4 z$ I: {
- })+ j$ p- p% @' H4 L) x" i. A
- </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
) S3 l6 ~9 X( j- <div id="app">2 o; P* e0 D+ |/ _, p% e
- <div>
) [1 S$ c0 k. d; W - <input v-model="parentMsg">7 J5 N9 a' a' O Y2 r1 A
- <br>
2 d- }' ^, F8 z/ o2 s! y& z - <child v-bind:message="parentMsg"></child>
0 K1 _. I/ C( @; n8 y - </div>
) n5 U" I0 X$ C& K - </div>
8 v8 |' k) m2 E1 G j7 i3 O - * V) P0 f. C: F8 Q; ~: w" x) `7 f
- <script>
! E( X. A3 @3 ?* G! I4 t; s3 P" ^6 A - // 注册) v) |/ U7 S: n1 s$ w+ I
- Vue.component('child', {
* h0 {' v' N; ], ~4 e5 c0 U - // 声明 props/ }% X8 k8 {& o& H0 C0 X: E- G
- props: ['message'],% P* C1 H; c# ~# V- P/ T
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
! l q3 N. i$ }) }# ?. w4 T9 y7 m - template: '<span>{{ message }}</span>'
0 B% f/ m( o# c6 _) }' o) c - })
9 i' n7 [( J6 | - // 创建根实例4 e+ |+ f2 s. y0 z0 ?' Z
- new Vue({" j6 _5 p1 c8 T4 T' z
- el: '#app',
7 H4 |* c4 |% H1 K% n: ` - data: {
d6 [& ?& v# r - parentMsg: '父组件内容'
, D$ G! e+ z6 e% _+ B - }1 O) I+ U3 Z. z5 p( k8 u4 o
- })' K0 F8 u3 t# F: R4 N
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例- P/ H4 F% W$ n2 z1 T
- <div id="app">5 X+ y4 N2 ^$ `9 o
- <ol>
+ n- q2 a6 J a# P _ - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>* h& M+ u4 ^" ]% _: U
- </ol>
& V+ [; R; T+ R* m3 s: P8 {7 X - </div>( ]9 W# i2 K' w7 V% G) P
-
; |- L7 X$ M4 z3 Q G+ t - <script>* R$ v4 f. T. b1 h4 d
- Vue.component('todo-item', {! X$ V/ V+ z& G' i3 s
- props: ['todo'],
8 w' p/ K, O/ `9 y3 W. V6 d, Z - template: '<li>{{ todo.text }}</li>'9 N) ?& v5 y1 Y: }/ F9 F
- })- `6 v& o, S+ w) y
- new Vue({
) q- ~4 f, y' d' o - el: '#app',, ~3 P! a2 g& o3 r: l: x
- data: {+ B/ {* } \! O1 p3 o* C! \
- sites: [
# K! X: b' l. H, {7 @ - { text: 'Runoob' },6 r* S/ T6 H! |+ |. t
- { text: 'Google' },
! v, W/ v! ~# P# G3 V( i' U: P5 m - { text: 'Taobao' }/ Z3 b# T, D. I# W( g1 Z
- ]! I" ?4 u7 S( A, F" h$ r. v
- }
( `2 g' o( R3 Y2 W( B - })' {7 k$ M4 V& h0 S( T
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
: L, _" a3 ~0 @! t$ n4 w- e - props: {8 b# I1 S" ]2 f9 e
- // 基础类型检测 (`null` 意思是任何类型都可以)+ v) u1 S" S; M
- propA: Number,: v0 k) k0 M; I+ R
- // 多种类型
! \1 I2 M* |/ j7 L" S - propB: [String, Number],# _6 g2 @; G2 w2 d i6 a
- // 必传且是字符串
# ]/ e) I" J+ P& o+ ]( p7 H - propC: {& f& [. R2 z* K% Q) d
- type: String,0 G" {, y1 T7 |: h
- required: true# ^. b' V- f6 g, ]
- },& U7 E& A5 d/ \& Q; u
- // 数字,有默认值0 L/ F' C3 m! b8 O
- propD: {
: {, u3 F) I# q7 V$ k! o - type: Number,/ d; O1 j- X! T: ` n+ l/ v
- default: 100
: Z4 i% M' v% X, u6 e - },
" Y5 X, ]+ g+ b- I - // 数组/对象的默认值应当由一个工厂函数返回
! _7 |" X7 Y5 ]* h$ @' [: _4 v* E - propE: {" v. h) ~; j, C- l: p( _ P. n* @
- type: Object,
- X9 P; \ h" `& f - default: function () {
0 s \* [; R1 t - return { message: 'hello' }
2 r# ], E! u g; q9 b4 Z - }& A1 Q5 ?: b7 a a* l! m
- },/ g' q, {! s: D
- // 自定义验证函数
5 m( p% s0 C1 [ - propF: {$ i: ~; ~" {2 D- K
- validator: function (value) {
& s) h8 Q3 ]% [3 m+ z7 P! p# y - return value > 10
) w- m8 X) p- w1 V8 ?8 { - }
- K. i! G0 j1 h% `2 Y% i. O - }
, w8 x& G: ]1 D. X, ]+ ]7 W - }
& C) `1 }1 n: r; r8 B - })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array+ Y: S7 |; c7 f
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
$ Z1 s4 n" e' H- S i, Z1 O
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例" ]6 [( L; U5 {' [
- <div id="app">$ D. S! I+ _3 F7 z2 T2 I- a0 M
- <div id="counter-event-example">5 p* n. T5 W4 c8 M8 O9 F' U% O0 Q
- <p>{{ total }}</p>6 r$ J9 z+ m) b# q
- <button-counter v-on:increment="incrementTotal"></button-counter>
9 @; s! o' K1 {8 c - <button-counter v-on:increment="incrementTotal"></button-counter>& p* n. b, @; H$ K. N- z
- </div>
7 E/ Q8 ^1 a, V/ ?1 F - </div>5 y' C1 }- m+ }/ P
- ( U3 s! Q: G* G0 w
- <script>
( |3 K6 l6 i9 h2 ~ G6 C& t2 n - Vue.component('button-counter', {5 a/ M$ j G2 G8 X6 J3 `! _. ?+ A/ i
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>',+ n, E X1 m. U9 t6 J0 N+ Y
- data: function () {
3 u9 h6 g( H [' _ - return {% H1 b- j! h% q; o9 v
- counter: 0
3 F" ?% Y7 d9 }/ W- }. k - }
" I9 f4 N- z T0 O, z0 Q2 [ - },
4 b! P9 ?4 W" r, P$ i: f' t - methods: {$ R# ^' F z/ k# G' `7 G
- incrementHandler: function () {# m/ K9 l* o& K" `" Z+ W" u
- this.counter += 1 t, ]( ]/ t& ?2 h
- this.$emit('increment')
4 U, w" f. B: } - }! l9 Y1 P0 W+ W' U' L
- },1 s% B) F# I8 f1 k: l, u p% T
- })
4 I9 g9 t: U( t - new Vue({0 k$ t+ d$ d0 S* n
- el: '#counter-event-example',
3 @# }/ u3 N7 }1 W7 T" x. j - data: {9 B( z2 ^* C5 F1 u5 ]! P+ k
- total: 0) o z* G7 b- k2 z1 Z
- },( I0 S' ]0 p0 ^) T- I: W% g% p' M. L
- methods: {/ I* D1 S* j% Q9 h0 u; Y
- incrementTotal: function () {! }, P0 I6 q0 J
- this.total += 16 U5 n; X# r6 I8 N7 x
- }4 X7 s: g, z) ~8 o H' @
- } Q/ I% F5 Q3 f9 p2 s9 ]$ F
- })
- }% k0 N, O! `8 c9 _9 S0 i - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
: y1 |0 ^! @) x" k6 ~ - Vue.component('child', {
" A/ t# o9 D1 }% M4 _ - // 声明 props6 l% \* t ~5 A: ?6 e8 y5 J
- props: ['message'],
+ q2 W' y$ D( A+ \$ Z$ Y - // 同样也可以在 vm 实例中像 "this.message" 这样使用# v' t- r6 Q B
- template: '<span>{{ message }}</span>'9 D0 N4 K, s8 c
- })
# r( k, a9 `, N1 \# D - // 创建根实例' d* B5 |5 M1 ^# O
- new Vue({' q% @% I3 z% I( P. G1 I
- el: '#app',$ ^! H4 Y @% {# ?3 |+ [
- data:{
& ?: m2 V" `/ I5 o% W - message:"hello",+ q' ~9 C2 z2 Z& \: v/ h |8 ^2 P
- }
% c% R9 b# i; {1 ^0 K9 q, F - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
: @( h7 @8 W/ D; w7 C2 u2 J - incrementHandler: function (v) {
! y5 C F g( o: s, X0 j& S& d - if(v==1){
0 l1 K p3 @/ u4 M T# D- q8 ] - this.counter -= 1- a$ I/ I* Q% S2 q$ U* D9 {2 K: B
- this.$emit('increment',[1])
' W4 p; V! L' \7 W - }else{+ @& T6 O7 P P1 N5 r4 z, n$ j* |( ~
- this.counter += 1* U8 y9 ?$ N5 g$ p
- this.$emit('increment',[2])1 M0 }( a, ?6 x
- }
; X2 [: Y1 j- J0 l8 r3 \ - }
# c8 G( W6 {1 C5 f - }
复制代码 , z2 u+ ?. V# Q7 G4 B
# p; x: L/ b9 Q! [- z
|