组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它: , J+ L% C9 n/ S) C: A2 g
- <div id="app">
: Y" \& L9 H1 m2 h0 |% x$ A$ n' p - <runoob></runoob>
$ {+ I. F/ a/ n4 [' t - </div>
) n/ z0 v/ p x; e; j- h -
}* e& k! l9 E3 y1 _: g - <script>: Z: r: M, l" k: ]
- // 注册
( R4 r2 S3 T2 V$ g - Vue.component('runoob', {/ K! E$ n' v h, U- S
- template: '<h1>自定义组件!</h1>'! m) X# n8 P/ b0 q
- }), z9 W: k5 f Y1 u8 D: K
- // 创建根实例
3 Z0 B* u4 H. | - new Vue({& G* I5 Z8 s/ S( ^
- el: '#app'
( L+ O3 e( c# D, F0 p - })
7 \/ l0 u8 _/ h4 N/ A% Z - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: 4 C5 G1 V* l" n: g: z2 X" k
- <div id="app">
; A: d9 R5 _5 h) {/ }) v0 D - <runoob></runoob>
3 p$ T4 v& e: R$ H - </div>% |( M" p) b& J" w# ^6 b4 U
-
& {& x1 [" ^+ T" M; ^1 L* Z - <script>
) p% j; ^- {& j- s" m+ n; X+ C y - var Child = {
0 q. y# y& U+ G! a - template: '<h1>自定义组件!</h1>'
. |5 W7 }( Y. q+ h# m6 Q5 e - }
; y7 C+ `& g: D' [: c - " R: F8 a2 [ z. D
- // 创建根实例, ]& \# \) o9 L. J* t& y! H# S
- new Vue({
5 b+ f, K) B# t, D7 z4 N& s - el: '#app',$ d! q0 L/ o& B+ z* O Q( _
- components: {3 U& V1 p4 p' Z% w8 Q. |
- // <runoob> 将只在父模板可用
! g7 }4 _ Z7 P! q2 n8 k, w6 E& v& ]9 P - 'runoob': Child
/ P5 h+ i* l# P9 u& X6 ~# Z2 @ - }
; ?% w! ?5 ] Q - })7 {/ k! q6 F4 _
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例- O3 |4 A I, @8 b7 p2 y( d! s
- <div id="app">. Y* A7 X2 C& u- n5 r
- <child message="hello!"></child>
* o9 x) D0 i; [$ u - </div>
6 g% \2 W7 L+ f, p) m- Z) V -
+ ^6 }% m) b! C8 s - <script>
: N# v% F \7 ]1 z% m+ l - // 注册
3 _+ g) r, X7 S. X' a - Vue.component('child', {
) y4 G' H8 {" b; S - // 声明 props
6 [1 g4 M* R9 v6 f' c9 I8 h - props: ['message'],+ n9 u- u; K& f5 p" K
- // 同样也可以在 vm 实例中像 "this.message" 这样使用6 o, ]- G6 V1 N: |# Y2 M
- template: '<span>{{ message }}</span>'
8 `0 d! t8 [$ ]4 _) d& B% X- j: H* L - })
. z \. I7 n- r% R - // 创建根实例
% h5 j+ K1 s; F - new Vue({
7 G" @" J: \, k - el: '#app'5 L1 \! H/ k& p0 z- l2 R& `! r7 I
- })
G( `6 F+ z2 z; D$ f5 { - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例2 x4 d- \/ \$ J0 j
- <div id="app">
; C& F" h: l9 |' y. } - <div>
5 Y, E4 K& o* v( l8 r) S, L0 U( P1 k - <input v-model="parentMsg">
9 O. [( R: r7 }' G! a - <br>4 d/ q3 V% D3 g; F
- <child v-bind:message="parentMsg"></child>
: B5 ?8 N, o; A: c4 S. Y. ^ - </div>
$ m* r; S9 ^8 R1 E0 m! _! | - </div>
' e) W7 r& T* n1 x - . I% ?/ m; H2 i% C8 `5 D6 T7 o
- <script>
: |* u5 S- p/ a# m - // 注册1 h3 W7 s! e D+ r' _7 K
- Vue.component('child', {
) h5 y4 L, C- V - // 声明 props
* h$ h* e9 r+ U1 t2 s; o - props: ['message'],
# V3 m6 y/ q. b) N9 ? - // 同样也可以在 vm 实例中像 "this.message" 这样使用$ x: a- d: U. u# ^) l9 z
- template: '<span>{{ message }}</span>'
0 X f/ U( {4 k - })
9 G. D6 ]& {6 x' W4 d. a7 M - // 创建根实例5 p u, Y$ e) s+ y0 U
- new Vue({( k: G& y: }9 ]3 J7 r8 c
- el: '#app'," A7 n& B6 B7 s8 ~, O" T1 ]8 Z3 j
- data: {5 ]& H- l7 c, m. U
- parentMsg: '父组件内容'1 {& z. |, F0 G
- }2 e! A3 h0 q' r
- })5 j- Q6 m: j! U( u9 _
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
' p9 _$ ?+ r3 N: [8 F- <div id="app">3 c! ~% Y( z# Q& u: s, i% u
- <ol>" k! ~4 ?6 ~! G0 O0 p
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
$ I$ k! z% t% M0 y z( f - </ol>- }+ q' @ f, N; O; b) m
- </div>
/ v6 _6 K" z; T& m - & M% N, B) G6 L' P0 W* A% F' g
- <script> q+ d7 s* l' a; }+ N) N: F% p% G
- Vue.component('todo-item', {
- W$ i2 S0 N& Q$ V0 f1 W, B! _ - props: ['todo'],
! Z2 ~0 R4 V# f- y3 A) _1 O - template: '<li>{{ todo.text }}</li>'
. P) c# ?4 s/ m+ w; ]* r* j' S - })
, f1 _# B2 h( w, x - new Vue({ |* S! T3 @4 Q( _8 K7 ?
- el: '#app',
+ _/ M" x& E" f k - data: {! N' m3 W. U: |: S: v( G B
- sites: [
/ r) y' b' h7 [5 e0 G7 | - { text: 'Runoob' },
i; o% \/ R& i2 L - { text: 'Google' },! V- A* ?; B7 U, B8 H) Z* [
- { text: 'Taobao' }
9 X: t1 a) j/ }5 o% O, A8 } - ]
2 h0 Y1 k# n' j; ]. L - }9 A! ?- r3 u- a ?% m
- })" x4 b* L- p7 g. |* F1 Q0 l7 p
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {5 J; J; d8 T: e% K8 G1 v
- props: {
! d3 ]8 s* d! b3 n$ N - // 基础类型检测 (`null` 意思是任何类型都可以)% }& `5 W% _5 B5 s
- propA: Number,
" f2 d/ S3 U U6 J0 z - // 多种类型
9 L# A/ Z' f0 m% q5 F) A! B# Q2 C: ^ - propB: [String, Number],
3 T! C/ x# m) h, P' k$ o - // 必传且是字符串" U: A% A9 U, m/ ~, B
- propC: {' w( ]5 F v# J' Q1 v0 e- r: {
- type: String,& y7 @& _. l u: ^; K2 T) }
- required: true9 g* m( q- b& `; F/ H
- },8 Y) O4 Z( H4 o" g; \
- // 数字,有默认值' {: w0 A6 j* L+ B8 K. ~
- propD: {
0 [5 K4 n. h6 y4 F" Y$ h2 f6 b- |, m - type: Number,' o0 L3 w W0 W T0 p
- default: 100
' w7 Y5 L! w* B# `: f - },( u- b5 {9 U0 d$ S7 G
- // 数组/对象的默认值应当由一个工厂函数返回6 Q, @4 G( R1 c/ X' e! T
- propE: {8 n2 L2 j, [& Q# W5 o
- type: Object,
# D4 N" V e1 }! h! V( Q - default: function () {
& B! ?: S3 h7 E! J1 d% f0 ?3 h, V - return { message: 'hello' }
( ], C) @2 a' Z - }8 h2 {, R9 M# R- i6 q1 E6 N
- },
/ n% R+ @, x# F( ] - // 自定义验证函数
6 {. H% A; ~! P2 m7 m - propF: {) s8 M6 i% ^" z
- validator: function (value) {
* i' z E. T* V$ E - return value > 10
1 @) ~8 X# b) q# d& }* c - }
! O4 b/ s8 l8 x( H - }# Y/ f9 q; X1 E4 C
- }
k% s/ Q8 B, p5 ^' u6 P - })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array4 e; k/ p# ]4 D- y' D- y
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件& q# l Z) l& s4 l9 v
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例
5 F! ]( k8 O. e6 C5 G. F- <div id="app">
3 j+ P0 F6 Z0 m1 b6 l! } - <div id="counter-event-example">
0 ]" C. O, r9 g# `0 k5 @ - <p>{{ total }}</p>5 m5 v. _) j6 T$ K! }0 x Q4 f
- <button-counter v-on:increment="incrementTotal"></button-counter>
/ L, G2 \# {2 {4 x' P - <button-counter v-on:increment="incrementTotal"></button-counter>" k! I1 v. t+ c. d8 O6 z& a8 K
- </div>
/ g; s, ?, T' H0 h - </div>; d5 P$ k: O( f# C0 I/ K
- ! E- u- a& u- n
- <script>) U9 d. m' B) G5 _" P; L. r
- Vue.component('button-counter', {
3 ~! E/ s4 P/ T2 y - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',6 ]! h# [+ c: }" R; `, X3 k
- data: function () {( Q1 z" i* _0 }5 h& v/ m W3 O
- return {
8 S; y5 z$ N V) v$ H4 U - counter: 0
1 T2 ]. {0 w0 |$ U' U7 b$ w - }! e) I- N. J$ y; p
- },
9 }: ^8 d. E. f, ^" p( x; O/ G - methods: {
q3 N: C- W9 P - incrementHandler: function () {: v9 g; j, g, K3 ^9 y* U
- this.counter += 1$ Z$ j+ ?) ^0 s8 O
- this.$emit('increment')
9 C8 j/ |' ?: o8 R - }
/ v' M2 A, m8 v6 ]+ G; G& r - },% s& E) {( J* c d6 K3 }
- })! F6 M2 I' S. y2 V/ d' T9 v0 ~
- new Vue({
. Q" \1 m2 a" _! x - el: '#counter-event-example',
- g5 Z. P% G4 N; m8 v - data: {8 d( M4 S5 u1 D6 I4 J8 d" l. R
- total: 05 I6 q8 n! n: r6 b' ^' U6 L
- },
1 I( `6 i" ^! F' n - methods: {. n" _9 N; q& x( x
- incrementTotal: function () {) K$ ]- N: S8 A0 Y
- this.total += 1+ e/ u& ]5 f' e9 O4 `
- }
" W% P" Q X2 `8 v. X2 y0 d8 f# g - }# E7 i/ ^3 |& J2 z# r) L
- })- D9 F# _* S) S& l' w
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册5 I! A- M/ ~. G# |& I* Z: t( _% w
- Vue.component('child', {
8 T: J, i& ~, a1 B8 [2 Z# k2 b - // 声明 props
% p; ~$ ^) T; B R' f8 V4 ? I' h - props: ['message'],
/ E9 I' }+ ]# G4 P L% l4 K/ ? - // 同样也可以在 vm 实例中像 "this.message" 这样使用
2 C9 D+ ^1 g" p0 Z - template: '<span>{{ message }}</span>'
- R; j, F2 c" z3 I9 v - })3 G2 _3 O1 L# L7 g4 w5 y: G
- // 创建根实例3 I! S$ H& r2 ?
- new Vue({
; f5 R0 d5 z0 i. C" E - el: '#app',6 ~. P# \5 ^" q
- data:{
9 b) `; j' k) h0 R- u* d. \0 l1 i" w4 U6 A - message:"hello",5 f$ r$ H& K3 l( o. p
- }9 Z- d- `+ |# V( V) B
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {4 y/ L+ A8 n1 o3 q+ ?9 l
- incrementHandler: function (v) {* g4 p; S* R" J: l( t, q
- if(v==1){7 @! R! \+ Q( E# N" F, T
- this.counter -= 1, f+ R% p% c$ Q$ ~* _* v
- this.$emit('increment',[1])! i) R+ [3 C$ C1 q* q I+ v; D2 t( r
- }else{
3 ~" E, K: ]$ b9 u# ^ J: o - this.counter += 1
. v, K1 t* p+ c9 x9 o; d# t - this.$emit('increment',[2])
; u" v& j. I/ t- g0 j1 k - }7 T+ d/ S1 O D1 ~2 }$ |9 X; N
- }
* W5 @2 L7 C' }5 E& V$ T - }
复制代码 8 [: g! l. E3 N( e; D) Z p
% j6 K T; }. J# n/ q% q |