|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它: 7 n, V/ I- j8 F. J: {% T1 G
- <div id="app">
! D; t/ S' O( O: W. L J u/ \ B - <runoob></runoob>
1 h$ B$ O, g% M+ l; ^ - </div>
3 {& ^ c; R! Z6 Z0 `, P% j2 ] -
* a, j. c1 }( M! {7 r. { - <script>
7 X" C. O5 B6 p0 T# a( r8 O - // 注册
1 r+ H5 R) \) {. p9 i' ` X& [ - Vue.component('runoob', {
" K3 A0 j, k& G7 P1 l) q: f7 u) q: K - template: '<h1>自定义组件!</h1>'& J& D9 D o! f5 q# @
- })
$ U* P0 S b/ ?7 v+ J - // 创建根实例
: j3 e3 z. F' S _ - new Vue({- Q( s6 p! Q* U8 }1 D
- el: '#app'
# p( @4 B" p- q) x2 o: t" O4 C" s: `4 L - })) F$ V: s$ _ t" \: C( e
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: |: M5 }9 c2 ~! _# S- c
- <div id="app">
/ g" Z, D& C9 E9 P1 V4 C - <runoob></runoob>
, G6 o# ?* J+ ?4 h/ o# J0 } - </div>1 ^4 i' Q7 ~- p7 V( c) H
- 1 C0 p! ]3 ~6 c4 x, o% h
- <script>1 V7 k$ z# I9 I8 S5 b
- var Child = {
7 s6 Z* p) _9 T/ [( ?1 o8 T - template: '<h1>自定义组件!</h1>'
) W) S: F. g3 @. E$ m& F" t, S" r - }
" Q5 T& c' C7 s- _5 @1 G1 ~ - . b3 r, J5 [6 H5 Y
- // 创建根实例
5 u0 {! c1 h4 Z) u! Q - new Vue({
% `2 o; F" W$ m1 j - el: '#app',# ?, P: _- Y$ V; C
- components: {& s5 L" A0 H; L
- // <runoob> 将只在父模板可用) ~! u+ [/ L" E% ]+ L. {! f. e
- 'runoob': Child" o; A& n9 l6 j6 U. C4 [
- }
: z" {' E2 v* \1 m* O& F - })
* Z( B M) s Q* H n - </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例0 x2 V! S! [+ j$ Y" {; I+ K; j- {
- <div id="app">( l" O6 C$ ?3 L6 u/ _" o
- <child message="hello!"></child>
2 [& K1 e& ~8 Y - </div>. X0 Y4 W3 p' `8 r. g5 V4 C
- 7 v; P& y* [) A1 \
- <script>& v- y2 N7 w& K
- // 注册
% E4 P: s3 @! m$ F# R. j - Vue.component('child', {
! Z3 Z6 \. d7 ?9 R - // 声明 props" u* u( z% G2 G. b# Q }9 Z
- props: ['message'],
2 k4 v. g: ?! [' \# l) I! y) L - // 同样也可以在 vm 实例中像 "this.message" 这样使用$ x8 f# r: p ~
- template: '<span>{{ message }}</span>'2 ?4 [; J" q7 Z3 R' a8 l
- })
: q' m1 O8 a4 B7 `% B4 Q" @ - // 创建根实例
/ ^: g' V6 o3 p8 T - new Vue({
+ `( I: P1 ^1 g% ?( c% J0 v - el: '#app'5 n% ]% b. g+ I
- })( H1 C1 R3 H- {- o2 X9 z/ k+ j6 c- J6 q
- </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
. D" n! M( k7 Q6 d2 C- <div id="app">
E8 Z! Q; y s( t0 c" A! C4 i9 i - <div>- u% _0 r8 {; i/ s
- <input v-model="parentMsg">
! B9 _% k& i/ @ t - <br>8 o& C' Q* C& o. N- r; h
- <child v-bind:message="parentMsg"></child>8 t% D( B6 U3 ^: a9 J8 b
- </div>
6 r/ Y' }! v" H3 \/ ^1 n8 f5 { - </div>
1 E$ Q; t; F- q - 4 x, Z# h) p h: [; K
- <script>- j7 M; P& [! a) z/ h
- // 注册. J8 m8 T( D* b, Y
- Vue.component('child', {
r9 Y+ ^8 B. Z - // 声明 props- U9 Y: n. Y% H& t8 d, Q- W. R
- props: ['message'],
8 \, z& v! q0 b/ J* j - // 同样也可以在 vm 实例中像 "this.message" 这样使用
; l. b. y: P1 A( y - template: '<span>{{ message }}</span>'
8 J2 w0 v, A6 { - })! P' a- g9 P3 H' W# S
- // 创建根实例6 N7 N& |1 r1 @$ o/ O
- new Vue({
$ M. t' C! k& y; k - el: '#app',
$ n6 y3 [3 o9 E/ N - data: {
5 x+ i q/ q# Q+ c& Y - parentMsg: '父组件内容'. }% n7 H+ N) {( \: e
- }
3 f! P) e+ a6 X/ H* @ - })
3 L7 @! Q3 ?2 B6 \5 d - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例8 p) ?3 ?) e Q6 w _3 R: z
- <div id="app">+ _4 x1 w; }- u4 [4 i$ l2 N
- <ol>4 d8 J% I: V% s2 U
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>6 w0 t! z- n1 l/ J+ I* G0 o+ Z* o
- </ol>
7 s) X. K' X' T3 c% F1 I1 m y7 F - </div>
7 r) |3 B- y9 [' |0 Y! R7 Q6 O -
( G" p9 e( w& G/ G# h2 K7 e G3 ? - <script>
: r" w! N* X; y8 I4 y; y - Vue.component('todo-item', {" o; f% M2 b$ Q* I# e
- props: ['todo'],
- b, @$ Q$ b( ~1 \, } - template: '<li>{{ todo.text }}</li>', G# x$ ^. H- D$ |
- })
$ V* a; w, N$ q' o - new Vue({
: j: j9 [ R! b* I- t! \ - el: '#app',4 w: ]8 ^6 X) w8 A/ C6 T
- data: {9 s' x g l* O/ u3 E6 }2 T8 X
- sites: [
7 B4 d: W) A1 i$ P, O) f1 q7 s - { text: 'Runoob' },4 _3 G4 I, J* Q: B: L. B$ b( x
- { text: 'Google' },! `. y7 `- M4 F9 g9 c$ f, T {
- { text: 'Taobao' }
. L, S. q: p8 h5 E5 p, R# C - ]& T) S0 j: K! S' B& k% R" j1 U
- }+ F7 Y/ T8 ^! [
- })
6 j5 D& b& Q8 o: K# b* u - </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
; b- [. {, E' s4 G: I( u) w - props: {
) ]2 g( @# T) m( [& ]9 U - // 基础类型检测 (`null` 意思是任何类型都可以)
' Q0 F4 f; r- B" n/ F0 _1 b6 F6 ? - propA: Number,
" P9 { y- U' H3 b+ ]' {+ n - // 多种类型& s8 v4 [' o4 w/ x! ~; Q6 F
- propB: [String, Number],2 ?' k# ]2 [4 o6 h
- // 必传且是字符串9 J, U7 l7 c) y* ?
- propC: {* Y% i6 p5 z/ ^, q/ n
- type: String," S# E/ R5 A' {; w9 M
- required: true
E1 s# Z4 X; y - },; `. @9 O3 f5 z0 l$ k
- // 数字,有默认值% \# Q5 _2 R9 Y9 \
- propD: {5 Y. V. G. M9 [- o8 q4 \9 N( I; C
- type: Number,
$ v3 w* @+ n/ K1 h f5 a3 s - default: 100
: N. s; p4 m* B* [+ c* ~1 l( V$ m - },
, C1 I5 ^8 J7 `3 d |. s - // 数组/对象的默认值应当由一个工厂函数返回
+ ]- ~/ q1 t3 ~. O% B: f - propE: {7 f& H+ E+ G! z5 y, m+ \8 Q5 G! C
- type: Object,+ D0 X, B7 t* H; f' l
- default: function () {+ i: [0 n! ], k# g6 j- M( O: ^
- return { message: 'hello' }
) i3 {2 E& W" d( e& j# v) ` - }! V- t) _" i; A9 i$ t
- },& i; O4 R6 t' T2 g- \
- // 自定义验证函数 _1 ~ n% r6 x. s7 F! z
- propF: {. p# n0 M/ `# y- y5 G+ B8 p
- validator: function (value) {& H3 e" }6 R1 N9 l
- return value > 10' F+ ]) _" ~6 Y, j6 v
- }
% o' n/ E' o1 T4 a - }2 u* T* }) M y6 S: g
- }
! s2 m8 C0 }- V( F" y, K6 H - })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array# l- X- k3 h' `2 }$ S* L4 D1 o; q
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
6 ^# r) K9 \+ t$ M. O/ u. M
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例# U' N# S- Y. ~" t" v4 D
- <div id="app">7 z& V# L6 O1 a, Y% w( u* f' R
- <div id="counter-event-example">
& Z4 O8 c+ d2 T0 {0 M - <p>{{ total }}</p>$ f/ o+ C& @! I9 E8 `6 c
- <button-counter v-on:increment="incrementTotal"></button-counter>
+ s$ V& m* w7 m1 Q( a& e5 U - <button-counter v-on:increment="incrementTotal"></button-counter>
" d, V- g5 L2 O1 k8 {3 [2 k - </div>, z0 N4 Y+ n8 U- i: Q g
- </div>/ u4 Y0 b9 {& Y5 i+ H. O. Z/ o
- ( r0 q3 e" y) I# ]5 {) d7 u" j
- <script>3 L, X* [9 @* z' U+ x3 u4 M
- Vue.component('button-counter', {
y# m0 q+ V' D2 R3 x - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',4 M d+ W$ u( P$ C1 ?1 m' |
- data: function () {0 _% q/ f( ^- n! }
- return {- I& s+ a) m6 q T
- counter: 0
g$ U! R9 s9 l4 m" Q - }
0 A ^+ F# l) M - },
; o5 H, C& u& V9 R* z8 W - methods: {; x/ J+ k8 S P
- incrementHandler: function () {( v# \" y( v7 e7 D
- this.counter += 1
. B8 Q" \. y- `5 {7 X5 X A4 K4 Y - this.$emit('increment')
) h1 _+ F& ^4 l) c - }& N; z* W8 U% }4 W- k4 Z
- },
* ]& g x7 b# n Q, ?6 `) B - })
) n& y) d7 T! |: U& V* H* R7 C - new Vue({
' D6 @1 s5 L1 g) v! p5 s' M - el: '#counter-event-example'," b" |# U* N/ ?3 D7 }! L* x
- data: {
5 Z; i) D8 u. | - total: 0# E+ z4 ~# N, I1 Z/ W! J9 k1 H- v! F
- },
' \! v% b u4 n7 \& j - methods: {
# T. _$ q; b, N; X+ S2 i - incrementTotal: function () {
4 S' r3 y5 k+ I# O# j0 j; Z - this.total += 1, H, c7 ] a \. V$ v+ W0 F! e
- }# _$ O; W( F/ I$ h8 F
- }4 b* p' F ~1 d
- })& V0 m. t. Y4 C* t6 ^3 B+ H* r
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册6 m5 @+ K7 I1 n. V& D, o8 k
- Vue.component('child', {3 @0 }4 _5 G; Z2 `5 `; y G: i
- // 声明 props
0 K+ z# R$ k3 G! z8 t7 o' I - props: ['message'],% B& |% o) H8 T( u. M
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
7 f# D& q$ `3 A( b* e6 t# O - template: '<span>{{ message }}</span>'
7 j/ [/ S1 s* P - })4 u. r6 P- }, _% T X
- // 创建根实例0 ] o# u: E( L' n) v7 D2 Q9 w5 Q- N
- new Vue({/ z& ?' Z3 T9 A) b
- el: '#app',
0 i; c) i- ^9 w. m8 @ - data:{
6 L9 z2 D" e+ u$ R - message:"hello",
8 J% v/ ~" f8 K$ t0 _ - }( {8 a* q0 o7 N3 u( d
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
6 K: J$ B- {, K4 B* r8 S - incrementHandler: function (v) {) e6 d. d. M6 Y. b9 ?3 V8 R4 s
- if(v==1){5 E4 K) B6 M. j! H$ J! O b% F
- this.counter -= 1* u9 M9 B" T" u, B! K
- this.$emit('increment',[1])
) @9 A( w5 I; }8 h- O- v) K. u$ U) ^ - }else{' A1 ~ t) A2 Q4 | o
- this.counter += 1
2 L, s" _; D6 \' h - this.$emit('increment',[2]), \6 {% O; w! L8 C- a
- }
8 H; F4 j- E2 _3 D$ k7 ^0 T+ m - }1 |' v* K; ?) `5 M2 X7 b
- }
复制代码 - T9 C. ?4 e6 t M- q5 a, U9 Y
+ n# S* ~: h& R- {4 c
|