组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
/ {0 k# o% t6 z! @+ [: D% p( Y; R- <div id="app">
1 x* c% r9 |- h - <runoob></runoob>1 K3 y3 L2 Y* _
- </div>
7 f6 H3 f. v, k, H5 s -
+ G" [' w% I7 @6 d7 l5 t - <script>) c+ w* m5 b. y
- // 注册% C- ]/ {4 K, a9 W" I
- Vue.component('runoob', {
0 `4 e Y- K% m - template: '<h1>自定义组件!</h1>'
C' J8 r5 Z6 y! @/ h - })0 _0 w' W7 _5 B5 l( d
- // 创建根实例$ c9 a5 \% L. V' u/ L, v1 M
- new Vue({8 z* v9 }3 z9 A: ]' m7 n/ L
- el: '#app'
& x: { S5 R' c" ^ - })% L0 F2 D# C. @" p& {9 O6 F* O
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它:
* O% ?( O0 z* t4 B3 n) \/ ?% ~. ~- <div id="app">
% J! G7 i4 z, A/ f# g% g/ I$ l - <runoob></runoob>
+ `3 @0 z. Q! p5 } - </div>+ |" b5 |9 i" T2 I( B, O
-
' B) B, S' k; C* v% M+ T7 Q* l5 Z( ? - <script>' F8 Q4 g9 `. z# [
- var Child = {5 W- U( M, R$ q" X/ l& k/ g
- template: '<h1>自定义组件!</h1>'
" I# p- u+ \+ K8 W1 {$ z" k/ J# E - }5 v& j3 R$ F, y& ~0 d) d
- ) o: O) _" C9 l1 Z1 W
- // 创建根实例2 i6 } o9 H0 d+ I
- new Vue({
8 ^: v x) V- a' Z% } - el: '#app',
. ?) H( `5 E5 q( Y - components: {
$ d& p' C% ?2 G" S4 ]1 |$ I - // <runoob> 将只在父模板可用/ z0 A) K8 z2 ?
- 'runoob': Child
Z1 s& x, V) y0 C - }
0 v% _- I% l$ m- E8 o - })6 n, _1 c: H" L5 `2 c
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例
2 O% C' N+ w- J! `- <div id="app">
7 D. o/ @4 W6 @0 b s - <child message="hello!"></child>
7 O2 m2 O. t* c/ } - </div>" x- Y! h" o, n! [+ T
-
3 E3 h3 d1 T$ u& ^5 h: f9 B - <script>% i' D$ x `9 @; ^
- // 注册
S- d0 p& O0 R! ^ - Vue.component('child', {# }) b ~5 V# _0 `2 t. s
- // 声明 props6 a! h% ~; E5 N9 o4 v1 _0 a3 y) y% q
- props: ['message'],0 `( i" Y* s& F& z
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
2 q- V F' p" ^" \1 H0 D3 Q - template: '<span>{{ message }}</span>'6 [6 r0 @$ U# f0 g
- }), I; ^+ n0 F( v, M1 l
- // 创建根实例
: ~( ~( h. E/ O - new Vue({
8 f' w; h; m# p9 E; x, C( z - el: '#app'# K9 |+ m" l4 Z" s& F
- })+ A+ u W$ K. s& ]7 x4 m
- </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
6 e/ E: ]$ {+ o" K' f% z- <div id="app">
8 n; l! i1 V6 j# @" i! w( Q - <div>3 x" P' b% x% H6 p
- <input v-model="parentMsg">! A ]6 l9 [. y
- <br>/ }- Y3 I2 S4 H7 _: Y9 h, k* Y
- <child v-bind:message="parentMsg"></child>: Q8 X' Q$ e3 k/ h# s6 ^
- </div>
|% r; o/ Z) V3 O" W - </div>
: U& |5 l7 D4 c, T N8 ?- w - / o5 g4 V6 Z0 _
- <script>8 f4 P! N& _! {
- // 注册% A$ Z( w8 Q- ?* C: m l" N
- Vue.component('child', {( a$ x6 b7 O; X( @ E# u, u
- // 声明 props
9 s: V* c# g2 M. j - props: ['message'],
2 T# B" ~' J/ d& A4 t6 |+ W - // 同样也可以在 vm 实例中像 "this.message" 这样使用0 B7 f3 n+ x7 y, E& J) {4 ]: S- ]
- template: '<span>{{ message }}</span>'
# ` \) A i7 n9 u, z2 O! k/ X& q - })8 F- d# p h" f4 ^8 X
- // 创建根实例) B. p& l9 n' T) m P+ w: `5 o V
- new Vue({
9 r( E6 }6 C7 \ - el: '#app',
6 U! d6 E* S3 p$ r1 U8 P - data: {4 x+ R8 F( H. }1 w* p P
- parentMsg: '父组件内容'
. {# b8 r0 ~* l5 E4 K% ]7 Q1 X - }
5 G5 E& x! y7 g, | - })
+ T% t( y) [' q: \1 W2 y7 N - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例% m$ ?3 H1 W. z
- <div id="app">( I. a& q+ i# h. H2 f, k+ u2 P
- <ol>( M) h Z, L r. X" D8 k0 J- N' b
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
" e# g6 ^% w0 D, _: ? - </ol>& m" [0 Z8 W) d. {5 r
- </div>
# O# Q. D5 A2 L: \& Y: ] -
5 P: ]5 O; v t8 K2 f1 F - <script>% v" j7 Q' u9 Y7 k9 B
- Vue.component('todo-item', {* K9 V8 j% L. W
- props: ['todo'],
- e! U* b/ p. x% w% S* W6 { q - template: '<li>{{ todo.text }}</li>'7 }/ z g1 E6 y- p1 @- Y
- })
9 ~7 o/ K9 X6 _1 L4 }, m - new Vue({. Q3 G, E& n! F' L
- el: '#app',
2 E9 [8 Y Q! q9 f% H: Q - data: {
, k/ U7 o" k$ v* {: E- x - sites: [
E1 D, {" s: s* c' M o" x; N( t% S6 i - { text: 'Runoob' },
$ T" t. `3 }8 B3 p+ t( x - { text: 'Google' },
3 @& F h5 O" {# b: r - { text: 'Taobao' }
$ X9 [" W. _% ~% b - ]0 s' O6 p2 }$ l; [& `; j4 \% J) U
- }
1 R0 b4 M* t: e8 ?( V, b; q) I - })
: B& G* N: \$ N - </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {2 z% v( i2 p3 Z- L. ^1 C
- props: {
: T Y' \, }2 C9 i) H - // 基础类型检测 (`null` 意思是任何类型都可以)
1 v; ^9 ? W9 c - propA: Number,
3 s* o( _$ S k' l/ y" k# l& X, x - // 多种类型& n& c9 I) n/ E- p2 \
- propB: [String, Number],
6 |; X6 U) j' t& y, ` - // 必传且是字符串& f) T9 t, h, k: L/ c
- propC: {+ l% A) d- W- I5 \4 z7 l1 ?8 i0 P; I, |
- type: String,
: \* L9 M8 Q7 \ - required: true' N4 y3 I* ~: K: \2 a
- },
0 Z3 p6 `7 a. K5 O" H% a4 A/ s - // 数字,有默认值
, c" r* b' s/ a" M - propD: {
4 g% O' S3 v [* k: K - type: Number,
. E( }5 c* D& ` - default: 100
L; G9 [6 ]( n& ^1 o- k2 I4 s7 r - },
, c9 `# W/ I! ^5 j7 I7 [+ y - // 数组/对象的默认值应当由一个工厂函数返回
' h$ j# D4 {" [% s* O( q - propE: {
1 y/ r: H& J* \: u - type: Object,
. L& m- ~# i: H/ T3 _5 o - default: function () {+ G" |3 r% v# }4 `/ y, ~
- return { message: 'hello' }
$ s D& ]5 Y% H7 j ~ - }; N) | k$ X7 S# k4 n; P+ i
- },4 |6 @7 a2 N4 A D$ o- R* X/ `
- // 自定义验证函数
) r( Z0 I" U3 m5 J v: D- { - propF: {
: U" z6 K2 i/ ]9 f/ _1 _ - validator: function (value) {2 R! A \6 y' G1 l8 t- |( T. V% J- W
- return value > 10; q7 J% X3 L l+ q+ f# W
- }
0 N& @1 C" _& n# m, o' U - }( h6 g4 U C' h. i% J H; ^, ^
- }
$ L% M5 q4 Y$ M2 Z - })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array* X3 B8 u4 X/ W0 Z7 a
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
2 m K7 H' ], o$ g
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例
8 H# i& _; k- x% b( s- <div id="app">
- r/ p, Y, s% d/ C- h# a8 f/ z - <div id="counter-event-example">7 w' h& J* G5 J
- <p>{{ total }}</p>
: V# X. g: S& t+ a - <button-counter v-on:increment="incrementTotal"></button-counter>
) h7 A: d' V/ \. \5 n - <button-counter v-on:increment="incrementTotal"></button-counter>3 w+ A! L9 L! y
- </div>
, j. B5 N& e* c6 n - </div>, T7 h1 m& h% N5 @+ ]( X) b
-
1 O3 n4 M1 H: f - <script>
$ _; ]& m3 v+ j6 f, s1 t8 g - Vue.component('button-counter', {
8 z/ H+ R5 e; u% _9 }9 Z9 o, J - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
9 f) |" X# ~" g4 B d. { - data: function () {
- ~7 F' o) W2 O% D- V0 q6 u - return {
9 _! J/ Q+ z5 ~0 m - counter: 0
. }9 I3 x) t# @" t) _ - }1 A2 S' j( Y& B0 Y, @
- },
2 \1 f) \9 o% T1 x. @, h! l - methods: {2 `3 H E8 @& n: O7 G. t
- incrementHandler: function () {
8 ?) F! ~ D: }2 H, n: y - this.counter += 1
# M9 R4 ]7 E; v3 a! J) [$ { - this.$emit('increment')
% e4 K/ g; P% X6 R& v9 u( k - }8 a5 { d% |- n8 i
- },
, `. {' q7 i- T1 g - })
9 Z$ E8 n/ f) }0 B - new Vue({* S; [+ M6 G, W# C7 o, \
- el: '#counter-event-example',
, D" [0 d6 I6 N* \9 G! y! b0 C - data: {" ~+ E! Z5 u9 q, o+ ~3 }* B
- total: 0
- Y2 }2 w% T8 k* q( f5 f# {8 J, @ - },
. n1 ?: X/ F3 G - methods: {
; Y% N" c/ {; b; a7 `9 Z6 U+ { - incrementTotal: function () {
' J" p% v! `$ z3 d - this.total += 13 K& {% y* u }0 K! {
- }
# Q2 y" m8 \$ E ] - }
# P+ d3 h/ f: ~ X - })7 A% P0 O" A% C
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
; O# K4 F: _7 c. k5 n# x. H - Vue.component('child', {7 Z( }" d: x; G
- // 声明 props
: G7 G; V1 @- |( |( v - props: ['message'], [7 _+ h" |7 i1 E& m- p2 c
- // 同样也可以在 vm 实例中像 "this.message" 这样使用7 o" T& G9 R# Y; l( C
- template: '<span>{{ message }}</span>'
5 b1 r$ t, j. P" y) P3 ] - })
5 S2 D& k, S. @. E2 v, H- a: j! U( Z7 g - // 创建根实例
; V) s: }' a* n& l6 N1 {# s$ Z# q - new Vue({9 H& d* V+ d1 I% e
- el: '#app',
) e/ z4 U# t4 R7 W R! W! c - data:{# e8 k3 x& l/ ?; J4 T- ?8 C6 }
- message:"hello",
% i) Y* i6 c/ g - }
& L3 i' d9 N) s% F! G4 E - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
: F* U4 a8 [5 Q8 X5 `1 @, x' D5 e - incrementHandler: function (v) {
. Y. e* @) r' Z - if(v==1){$ C1 S3 V4 m; S- L4 C& i9 w
- this.counter -= 13 Y0 C% O2 D% ?9 t
- this.$emit('increment',[1])
, B `! O1 @0 a" l9 M+ V: A+ h - }else{' K+ ^5 Y' F3 I4 G
- this.counter += 1# s. u% q+ ]' l! F% `6 F5 ]: L9 w/ R+ t
- this.$emit('increment',[2])2 z* N9 j/ ]1 Q
- }$ F0 N& D0 T# |) H( \- ^/ D2 U9 D2 N
- }
8 E: F! L; \( r, K9 Q - }
复制代码 6 ~ _+ ^5 _4 ?8 n( C
/ p; N7 o) _4 K! c; I* |8 i |