组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它: . J3 w, p I0 _/ S
- <div id="app">
( ?, V8 {- r; H7 v9 [. b) q& l8 e - <runoob></runoob>, k9 X2 |: c7 j, H! p: ~0 n
- </div>
! {/ {' Q, }: W/ S$ R! T* z - 7 H6 o: e% I- C
- <script>
; U/ P6 N) i# y! v1 M8 o - // 注册5 X# \; g. M- ?
- Vue.component('runoob', {
- E# Z' c- t* r; l7 i - template: '<h1>自定义组件!</h1>'' Y$ Y& H& S/ }/ |- w2 U1 |$ I$ n
- })
2 z9 h Z i) K5 y6 B - // 创建根实例
3 r+ b* I- Q/ ]! }. j5 N s - new Vue({6 Q# ?$ W8 X) j# q. I& [! D
- el: '#app'
/ k; s: @) U- B/ F% B - })
0 C: W6 H- {2 B! G3 F - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: 0 b2 J. A2 T7 y) \% b
- <div id="app">
* O* @% `! {" M7 V2 h* @/ L - <runoob></runoob>6 @1 c" S; x: g6 i% `
- </div>
$ Q6 j' [6 ^4 l m) B7 E -
( H9 e( L* \( f2 S- r. g/ o. U" w - <script>) K- M2 |1 ^- y1 b
- var Child = {
; `% o Z. D1 Y0 C) x; N5 x - template: '<h1>自定义组件!</h1>'
8 R$ e1 D+ h7 i( ^" X( P - }8 T& o v# I; C$ E9 F
-
! f6 [0 p3 l6 n! T/ C - // 创建根实例
; g9 x9 C! B# f% { - new Vue({3 u# O7 i8 S: D- G) @: n2 K" O/ _
- el: '#app',3 y$ ~% @7 I/ y& k# m
- components: {
" X) k1 R5 l$ h6 p% R - // <runoob> 将只在父模板可用
, B+ C1 y: {9 f/ H; l5 u% f - 'runoob': Child+ f) ?3 \9 B3 @+ x: z
- }, h+ l9 {% H. Y" e
- })& Q K' o* b( z5 Q4 \
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例, h& {5 b; o. C G- g+ V
- <div id="app">- c4 m2 ]6 X' D" E) ]
- <child message="hello!"></child>3 `& T& u; }2 v7 a% A
- </div>
! D3 g( r$ t6 Z! x0 U z O" h -
4 O: O( u: y) ]5 p/ W- t - <script>
; g: M* y# ^9 R - // 注册
1 ~* o8 E7 t9 b. a* A3 q - Vue.component('child', {$ x$ Z; _2 S4 J5 v8 F$ H$ Y: ~
- // 声明 props
1 ^4 i. Q1 N# [( m. ~8 O0 e' P1 i - props: ['message'],# e: I) _) U8 @ ?* D
- // 同样也可以在 vm 实例中像 "this.message" 这样使用# x* C. C7 K) g& K; N. {8 l2 O; E8 J, A8 C
- template: '<span>{{ message }}</span>'
; F' L+ ?5 G7 [% W I4 T( g* u+ } - })
P# P$ P3 ?6 z* x/ O% v' T - // 创建根实例
7 _/ F+ u* o: }% x2 O' }& _ - new Vue({
/ a9 Z' t" V: }# F( E$ X) h - el: '#app'; x0 T G" `; T- Y/ Q& l+ Y {
- })3 ~8 D# i! z% X! Z
- </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
6 W9 [. M+ z' D' D, p6 i+ |- <div id="app">
, i" U1 y- \, k) m3 V - <div>
5 H/ r; e. q2 j9 \. c* _- R - <input v-model="parentMsg">
: d5 ~9 T; Q, o# U! R - <br>/ j3 f2 z) n z: I
- <child v-bind:message="parentMsg"></child>
3 R6 I$ h5 ^- [4 V3 A! s - </div>
& G, j+ M- R/ u7 V0 H1 n7 T - </div>
9 P+ q, w" M+ e$ {4 ?' T: F - / T0 W9 {% d( L6 ~7 c* T* q4 w
- <script>
% x6 [% y4 d/ P) h% Y8 I( A9 ~* X - // 注册9 W- T/ z& V% F
- Vue.component('child', {
% N6 P, Q b0 P& I c- v5 a - // 声明 props, h0 @0 ~) ~4 i6 u1 r( ?% ]
- props: ['message'],7 X- C* ~. v1 ]7 B. a/ Z! {5 z
- // 同样也可以在 vm 实例中像 "this.message" 这样使用+ [, z* p# L2 r$ L1 \
- template: '<span>{{ message }}</span>'
# B* g- Q7 k5 J1 P7 g - })- q P- z8 q! I4 L# y) q0 I. u
- // 创建根实例5 d; ?) c) L% }
- new Vue({
7 a- y( M* F+ l: x - el: '#app',, D" K' B2 g m6 u- _) v9 g( }( s
- data: {
/ c& \: }" J+ T4 S9 s& U - parentMsg: '父组件内容'
4 O3 {1 e& g# D - } u" X) ?- u9 t4 ?1 x7 o* u$ j0 f# G2 T
- })
8 ^/ K }8 [3 D' F8 m8 w - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例9 k) k) |# h, ^
- <div id="app">1 J5 N# j* B# d6 ]( z
- <ol>! S! ^7 X. ~/ m k5 y! _
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>" Q+ \; b, j: {5 \- `- ^
- </ol>
5 @ k5 E/ U9 F7 b9 O l - </div>
& X+ C9 A% F- y1 p E$ i4 H -
! P! X$ K6 d& C; ?4 D - <script>
. W1 [# O) g7 I2 G: N; B# w - Vue.component('todo-item', {% O$ ?$ M- B) D6 R4 d$ ]
- props: ['todo'],# R9 k* o- I+ r' b& {4 F) `
- template: '<li>{{ todo.text }}</li>'
3 y6 G7 s/ m. C, a- c - })+ o, h3 y8 q" _) d7 n2 b/ _' e- \/ @
- new Vue({! e* Z! R' X" k8 a7 x
- el: '#app',1 e5 X9 A* D0 ?9 r. O: ]
- data: {
5 R0 b3 M1 a/ V! ] - sites: [
) |& p8 R* K+ E8 c: N - { text: 'Runoob' },
' ~* ]% {/ J9 `' V - { text: 'Google' },7 |+ V* }9 ^; ?, K& E
- { text: 'Taobao' }
" S, x. C- C) ^: g* M" t# K - ]1 c& F6 z/ j( n$ z8 D
- }
2 A8 ~8 J7 Z, @! j/ J - })& e+ u& Q. a9 B$ @6 L! O" ], g! N% g
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {, e9 t" S9 ?! x/ v" C" @
- props: {4 d( p7 {! o" z2 ~: G0 J
- // 基础类型检测 (`null` 意思是任何类型都可以)
9 m: Z; d+ I! G' ]0 f4 L0 [$ s - propA: Number,
9 b" X5 }" {. n$ [, L5 t2 a - // 多种类型
$ f8 i7 J% `4 U. f: g/ Z - propB: [String, Number],' e0 _& o0 g9 O) m0 Y" C
- // 必传且是字符串
+ ?) u. G- i, W$ ` - propC: {2 ~6 r' Z/ f$ }7 y4 l1 @8 q
- type: String,+ T, N% {' W* E
- required: true
+ _9 ~4 U4 s% x - },
+ r- J1 G! [3 {+ g' g% l) D - // 数字,有默认值4 @/ S. J0 c' p0 q7 I
- propD: {! h7 [+ _% i% f) `
- type: Number,, p" p7 U' c) K9 K3 u
- default: 1002 R& r0 D3 c# |
- },
$ b- \" w, }8 [3 \3 T! U - // 数组/对象的默认值应当由一个工厂函数返回0 H9 K( T+ A1 ^
- propE: {
. x: [& [ I7 p# r( q* H - type: Object,$ Q! h9 f( t" B* E7 A/ d
- default: function () {
) n' c$ x4 n5 I8 J0 N) M$ \ - return { message: 'hello' }1 o1 Q% m d8 p. n6 m9 p5 V* q
- }9 [* H) B% |7 o1 d
- },
6 T: B- ?+ `5 ] S - // 自定义验证函数
! [! t( s1 r% \ N - propF: {
7 r& P9 z2 d' P$ o2 J4 [% J$ [& O - validator: function (value) {; d1 o1 \. e" p( H. K. p. E0 {
- return value > 10
& \7 W7 | C2 N5 F; X- ] - }2 b" l- @# ~8 Y; V! M: G- G
- }
, ]; ]1 G5 |9 q8 x - }
/ B1 p% T1 h/ `- d - })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array4 {. F) d+ j$ N6 G- j' M3 z6 [ o
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
8 N+ A8 h( e h/ Q
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例+ Y6 c9 |# C4 |# ^" T
- <div id="app">
0 o! X2 S% K: x) j - <div id="counter-event-example">
- w4 Y9 G; }+ s; K) f2 R4 W - <p>{{ total }}</p>/ F+ Z3 s1 `. w: c! c) ]
- <button-counter v-on:increment="incrementTotal"></button-counter>" i' _5 s- Q3 c4 j
- <button-counter v-on:increment="incrementTotal"></button-counter>: q) W1 K1 p" O& _; n8 O$ I
- </div>
# l- q* f& h I( c6 ]1 O! d. N% i - </div>
) k7 A& a. E( E+ l, m( z - ( m4 t. X( c/ M2 R
- <script>
; ?& {: b% h& E ]$ f" [% d - Vue.component('button-counter', {. n$ P6 A7 G$ e Q+ Q1 n* L
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>'," s+ P9 X& m8 t8 h- S
- data: function () {& \/ v- K. d7 w& {8 N
- return {
( N" m1 M6 }# q; _! J - counter: 00 f/ [9 {( }4 `
- }
9 W# B8 h% Y7 X& }( s1 F7 g6 } - },
) ^* ~2 }' ~# J9 D9 F; _ - methods: {' B, g1 p3 T/ e% q
- incrementHandler: function () {$ W2 j" ?7 K+ q2 @
- this.counter += 1
6 i/ _; a" f1 b: R2 L6 Q4 r r - this.$emit('increment')2 n+ Q$ S i; Y. F2 c
- }) N% o" T, ]: P, y& b
- },
0 o6 U: m1 R0 T: `9 }' v - })
3 T" p7 F3 _' ~. @8 o - new Vue({+ T3 v6 k! L6 l i$ ?5 a
- el: '#counter-event-example',
5 g3 j: G0 a& o S0 Y - data: {. f. u# |2 U I- u$ v) D
- total: 0% ?( g I$ m9 k) s
- },. j6 R; N: K% A& x, _7 C
- methods: {( ]" T' r5 C) S$ Q/ Z/ E8 _
- incrementTotal: function () {
% e4 D/ G9 ^+ c& T8 s" s( e X. W - this.total += 1
5 D' w7 {: W# ^1 K8 A+ f - }
6 u k6 a6 h, v6 @, H7 O - }9 X9 X5 ]# J( M: B/ k
- })
+ i4 N1 A8 l, a+ }! z( b1 N1 { - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册- `- H S5 w1 k; I2 s
- Vue.component('child', {5 ]% Z4 A+ D l4 X% Y
- // 声明 props9 m5 U( Z8 C, K- y+ I8 X0 c" Q
- props: ['message'],
9 C9 K& B" s' H+ C& d - // 同样也可以在 vm 实例中像 "this.message" 这样使用* G0 g, _4 k* L6 N; P: ^1 {
- template: '<span>{{ message }}</span>'4 s- c) n" l+ _, M* k) d
- })" d" |4 @8 v/ C& s
- // 创建根实例
# p7 F+ Y5 d! b& l9 {1 S1 G) p6 y - new Vue({0 P3 r/ Y! R3 m! B& }8 |
- el: '#app',% X! I8 V; F2 l7 L( G6 C1 e5 r
- data:{5 Z5 v- H, _: m7 |/ A5 `1 M2 q
- message:"hello",- G; Q* n6 _) l5 i2 E$ [
- }
1 C) \1 ~8 a' ^) {2 ^6 h% U - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
/ a9 v1 t1 h- X# k3 G - incrementHandler: function (v) {% r% W5 J' J, y% [- ^% R, f6 Z+ R# N
- if(v==1){
' f1 Q" o6 V) z* k: s% i5 n - this.counter -= 1
) s, Y" q6 y; X: @- j) x8 q5 ? - this.$emit('increment',[1]) O: d$ y" b9 z' j2 ^# `
- }else{
2 T( b- ?6 R; Q2 R0 V - this.counter += 1: g! i8 r0 t2 ]
- this.$emit('increment',[2])
! x" ^" _# q( _$ p9 q - }9 E r6 k4 _; V! _) c$ ~9 y, w5 M
- }8 W6 F$ C, e2 p4 ?
- }
复制代码
! p1 j; f& `# x4 J0 z/ Q+ K4 L
3 T; F' M4 h& l& ?' }, E9 E/ P6 F' d/ V |