组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
@& \2 Q) v# F# l# I- <div id="app">% G( b) B; D# p! s8 J
- <runoob></runoob>
% H& }- b: a3 r) K; Y: u, d - </div>" m" Y7 J3 \3 ^6 r) A4 t5 z
-
* H) C( m( n( f( q - <script># k, F+ ]9 C" o; K, ~+ ?& \
- // 注册: K6 |( @6 a1 q2 ~. B( F4 w7 @
- Vue.component('runoob', {7 S x% |1 `1 L+ K& k4 [
- template: '<h1>自定义组件!</h1>'1 Z K) `$ B/ |3 _
- }), P7 G2 r" U; a2 C% a0 v& H
- // 创建根实例
?. S8 ~# \; ?/ g: E. A - new Vue({( Y5 M9 |; b$ B: P
- el: '#app'* L5 _ r4 Y5 S3 Q- e
- })/ W( D8 O- A% [3 \/ ~ J* G
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: # Y/ z7 f. d$ a
- <div id="app">- h: m4 y& O" A
- <runoob></runoob>& J/ k. w! C+ O3 `+ q
- </div>
7 i" {4 u( ]4 ?( v1 w2 p -
4 v7 ?) N# i3 p8 Z- B" ]0 G7 y - <script>9 g9 w/ Z/ K. [; G. M# a6 H
- var Child = {
9 L/ K1 |/ | t7 a3 n - template: '<h1>自定义组件!</h1>'" h$ U6 M& J; K# ~% [5 n% q& _) z
- }
$ n6 [" q! O. Z3 I, X - 2 o# [$ G& W' |+ x6 P, ?
- // 创建根实例
! p) _9 P8 [9 b2 g7 X( x3 \8 m0 D - new Vue({( u" \ ^) ~( g [. ?, {* e
- el: '#app',
# M8 X$ ]% e: }4 @ - components: {5 B9 t ?# [% g( {- O6 r& V8 T
- // <runoob> 将只在父模板可用
; }8 F6 _0 Y, a5 e6 o* z, v - 'runoob': Child
9 w4 [# {5 h9 P: M, } - }" i/ M, I" x; |" u" L, V
- })
6 @5 }( a4 y& M - </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例7 F& B; |* g- B! N2 ^
- <div id="app">
9 T$ U0 r0 \, A e* F' a - <child message="hello!"></child>" E+ w# A- o/ d+ X* t3 g
- </div>
- a! v g) L: v" r6 n! X5 ] - ' r1 X+ b W/ o) |) h9 ]
- <script>
" s, o& _5 v0 W& o( H; T - // 注册
- o2 H2 W7 f! P% i' ?# W - Vue.component('child', {; p. m8 K! L2 b. w! K8 I+ B0 q
- // 声明 props
1 ^, V: {( q) E4 y0 K O- Y - props: ['message'],
2 T- n$ v3 p) R: J/ C - // 同样也可以在 vm 实例中像 "this.message" 这样使用
4 w% D4 z( V) B9 J/ P - template: '<span>{{ message }}</span>'
& s. Y8 C+ r! v" L% ^, p - })
1 k2 }0 a, \: v" u/ ?6 q( R0 L4 k - // 创建根实例' v& o, J, J) t. ]8 S5 c8 d# O
- new Vue({- h$ t# |( @4 p8 Z; t1 F# p
- el: '#app' C t3 c5 j8 s
- })
7 S/ _' u1 o B( \# _ - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例; v% w1 _# R5 U& o/ g
- <div id="app">/ P" q4 M, B3 N; v! T
- <div>
b) C* A. n' r% {3 Z9 T. _ - <input v-model="parentMsg">
; Z0 t" G* w }0 h- j - <br>
3 O. f* G! ^8 a6 ]: J! I - <child v-bind:message="parentMsg"></child>
x" {* G9 h* Z, `6 [ - </div>
" X$ w; w2 Y2 T; V: z1 r - </div># e0 f+ j3 ]/ l$ Z+ \
- . T0 u! A4 ~! f/ t2 ^
- <script>4 ~8 f& I& R" L$ t' r0 ^3 l% J9 C% a0 B
- // 注册& y7 Q6 j; h. q7 J( R0 n3 g
- Vue.component('child', {( Y. F) Z* g8 x! m7 j7 b' ~) v- u
- // 声明 props" A7 c4 r: ?6 \/ i$ c$ w6 P
- props: ['message'],
0 G& l1 t. p4 `9 } - // 同样也可以在 vm 实例中像 "this.message" 这样使用
0 b, `& p/ x9 U - template: '<span>{{ message }}</span>'5 X6 T& R; }& A. {" ^7 A& E
- })
4 {) C5 I" l8 Q& A - // 创建根实例, h% R. ^# H) q) V% s6 u
- new Vue({
3 ?; F- V- A7 T5 M - el: '#app',' i: ~, T) f( t
- data: {0 r" j, A7 ^: {1 Y
- parentMsg: '父组件内容'" c) _( C2 a& ]3 q. n
- }
3 V! w1 Z$ ~* |8 D8 D: y - })! {/ T. ?+ o. g' e" c
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
) b6 A) |! I2 p) N; l& L8 e) p! g- <div id="app">
% ~. C& g7 i0 e0 m7 |) f/ F% e+ I$ s - <ol># w6 [5 K; Z/ M2 K2 Q
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>9 O& c9 e1 C2 k% _
- </ol>
% w# X0 k/ C! | p - </div>8 I/ U3 H s: ~" F9 W
- # X; [: F2 q" B; J |# T
- <script>
, |3 P0 @; `. R( d* r L - Vue.component('todo-item', {
' \1 D, H7 y; c/ H6 V3 n3 @. \7 S* h - props: ['todo'],+ h3 e% [1 ~3 x8 _; w, s
- template: '<li>{{ todo.text }}</li>'
/ Y7 w- |6 k6 G" k - })
0 ~! l8 ?. z0 P$ ^4 i: n% S/ f - new Vue({- `+ k( e R3 p7 c+ j
- el: '#app',0 z0 b M+ D$ a7 V( y
- data: {
" T! t/ k& _/ C - sites: [* [, Y. w0 X; I/ M
- { text: 'Runoob' },5 D. `! s- \! [ x& J: R
- { text: 'Google' },- _5 R+ m4 @- O2 |
- { text: 'Taobao' }/ L# j' Y$ L+ c# V. B8 R6 d
- ]7 K3 A9 }6 [2 n9 A9 g
- }
1 `; J7 ?; C* R2 Z - })8 G1 t0 d# R2 s+ N
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
, ~" d" n/ E( N4 A! J% o" a# ] - props: {6 C. M0 T4 r, ] l, V3 V9 H! F
- // 基础类型检测 (`null` 意思是任何类型都可以)9 S* b b9 `8 X' F c3 ~, Y
- propA: Number,
2 q& K0 |% h' y. ^3 q9 ~ - // 多种类型9 Y3 [( M. H* m1 l3 k
- propB: [String, Number],
2 w4 R$ z) r5 `) o3 h - // 必传且是字符串2 E5 I3 L4 ~' _5 s A
- propC: {
+ Y8 G( z$ l* d J - type: String,
# z) w, n& Q) d! t4 q - required: true
8 W0 _' c) G8 Y* i# O% q7 { - },* D" R7 K! m9 B: P: @
- // 数字,有默认值' O3 q& e, u9 Z; B- D3 W! J8 E) Z2 }
- propD: {8 {# K+ k3 L" M4 i: C: }8 H* B
- type: Number,
* R# t, c# H& s - default: 100
$ Z; C5 G1 G2 K7 x$ T - },
6 } o M; l+ n' V& k - // 数组/对象的默认值应当由一个工厂函数返回
/ M/ Y7 J+ f$ @: K0 K( ^ - propE: { @2 V7 j( U) z6 }
- type: Object,% S' a" ^" m; c, Z( n$ X F: x
- default: function () {$ e6 _% y4 X7 j
- return { message: 'hello' }
4 C* ?8 p: Q0 h5 W - }
9 W$ s" u9 Z. K; q1 }$ }8 `/ ~ - },9 ]" w& d# [* a- c& j& b( ?
- // 自定义验证函数0 m; H. t& ~5 \7 X
- propF: {
: L ~! a" K! H - validator: function (value) {
+ ?' @' J5 \; ]' } - return value > 10* ~/ Q7 [2 x: `7 Q+ j$ c
- }
( Q7 D6 B. O* { - }
4 X2 `9 b. A2 P b- K& r - }$ E: c$ M# {. g, l- [1 q2 Z& r$ S
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
0 r3 V7 R# u) B |7 \/ C
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件& _$ Y% r" Y! ?4 q; Y
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例
5 \/ q. g, c/ M) o2 o1 q6 Q6 t* L- <div id="app">0 e0 f. h% L5 n% `
- <div id="counter-event-example">
- E+ b/ I; j, e2 x - <p>{{ total }}</p>6 f' g5 A5 p! F7 V
- <button-counter v-on:increment="incrementTotal"></button-counter>
D+ d7 W8 w$ ?! L - <button-counter v-on:increment="incrementTotal"></button-counter>
! j( E9 V H1 R$ k. C7 R - </div>( |' }0 c3 |6 s. X) s( B- n$ P. w
- </div>
) V' E: h& w) X$ d - ^ v9 M* L7 \/ }" ^
- <script>
3 z7 ]$ \) l0 Z" u' H! @ - Vue.component('button-counter', {
/ ]: l7 z( u2 o; a9 y - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',' |' u {2 Q- t8 E6 [
- data: function () {
6 ^5 V; O4 p) B5 P; j - return {. p& ]; p1 R5 u# f' z8 u0 w
- counter: 0+ v6 s: _* u: N0 K3 k' F1 M/ _0 [
- }
1 y5 t& v' k- M' o k - },9 x& g& @! N0 s0 I9 w6 H; o
- methods: {
0 m) R' [& K1 m5 M8 k& D - incrementHandler: function () {
' w7 h0 ?* }7 q2 p7 y - this.counter += 1; k( m1 w/ C( ~% [9 C& X9 r8 O
- this.$emit('increment'). R/ M- M; @0 I+ q' b9 v
- } C4 r; h' o9 G K
- },' |8 Z. J. L( y6 u
- })
# u3 |3 ^( H0 d - new Vue({
- g+ J% |$ V- ?- k9 i* o. z- ~ - el: '#counter-event-example',) G1 y' W9 p% j5 [% f% }6 ?
- data: {8 ? t! l$ t$ C
- total: 0% F& E$ P9 g& k0 P
- },
/ f" C* L% o2 q# x( Q; A2 ] - methods: {
8 c# b- {! T5 W8 ]3 Q9 s - incrementTotal: function () {
( ^5 T. S/ I: n. I; D, h, d7 y# k- z - this.total += 11 [( `7 [8 \0 f! v" o3 A! o
- }5 `4 W% b0 V# u/ \. C) _. l$ x, r
- }
! n4 t# F+ H l - })" \& f( A; i( H$ _" W
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
. @8 j4 r' N5 n1 V, [" t4 D0 Q$ I - Vue.component('child', {
5 E; a( q8 ?* p9 A! O4 W - // 声明 props M% J% K; `9 _. k8 ]6 }6 [3 `6 x
- props: ['message'],5 S Q7 N1 d6 ]+ A- T
- // 同样也可以在 vm 实例中像 "this.message" 这样使用! S! B6 M" }1 F0 N9 w0 i
- template: '<span>{{ message }}</span>'
0 W) Q3 g. f: G4 s n6 o3 R - })
/ j* l6 s, `+ }/ M5 U' d# j' \ - // 创建根实例; I A" [7 p" F" D
- new Vue({
+ o7 H' R6 V+ V3 ^; d1 ?) Q6 B - el: '#app',
1 y- }# w/ \ j5 s - data:{
; w5 w' p( X& q+ } - message:"hello",4 D9 W3 N" Y. r9 C; o& L/ C
- }
$ i! s* _( l; y, V) `- O# E - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
/ |! w+ R% X2 V h' S( v2 T - incrementHandler: function (v) {
- U6 @) v4 f7 F* e: m - if(v==1){# {6 f. D/ o- F# ^
- this.counter -= 1/ w# V% K; p2 \
- this.$emit('increment',[1])( j3 b; c0 P+ g' O; k# Z3 n
- }else{) ^$ \* i) e- A+ P9 ~
- this.counter += 1/ J6 ~/ m. x6 d$ F+ r' `& w
- this.$emit('increment',[2])3 k1 r- s. Y2 r
- }$ u) i% q9 O" W1 S
- }9 j) o: C/ j- ?* u& V2 f& a
- }
复制代码 ; a7 s! {- C+ ^# g: a
3 |: M; M7 n5 \ |