|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
+ s, n- m( D( ~7 H- <div id="app">
7 w+ H. t8 R) z9 T - <runoob></runoob> d$ k$ r( q0 {6 f2 S; L2 B
- </div>; _$ g7 [0 Z2 T( J6 y( X
- 0 N4 {! }5 p! A _
- <script>3 k/ T o0 Q4 O1 z. i0 C/ u
- // 注册
' f9 \% I) ?! F - Vue.component('runoob', {5 f$ }# X4 \0 d3 l" D% B
- template: '<h1>自定义组件!</h1>'
- z2 D* W- O( i) T/ A- h - })
3 }' T: }5 w8 M! q8 U4 ~ - // 创建根实例* f0 R1 y# `% G- ?6 v4 f* G
- new Vue({$ x# B, c6 \& `1 q( N2 O
- el: '#app'
" N1 u( e7 p c1 t8 @ R - })
$ V* O% [- a+ R0 M7 Q7 d, B - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它:
6 ~; Y# R2 R' N/ [7 u9 R6 Y- <div id="app">
* x& j# O5 X7 \. ?. c - <runoob></runoob>+ L; o& ?* o' L
- </div>
. N3 e1 O2 p0 u - % H+ a# W" P. K) L2 \1 Q* O
- <script>' `1 S# o: a; c5 v M# g
- var Child = {2 R; V- d) D, j a! O
- template: '<h1>自定义组件!</h1>'" ]2 b+ c1 S$ m
- }
7 |8 Z, _! K7 \# }+ m7 u1 @( F) m V -
: @: \( j: a/ F, |7 \9 O% n' [( O - // 创建根实例
. u+ L0 [7 @: K - new Vue({
+ q5 f% n: {; [+ W: D0 P2 n% N; J. B( n. y - el: '#app',& x/ c1 T5 {- g3 l4 n Y( R
- components: {
% o. z4 d' ?. {8 X' G+ q - // <runoob> 将只在父模板可用
- F& S& f) d# G3 i* @ - 'runoob': Child
3 D. N! o& ^0 |# H- ? - }+ S3 ^. x+ N2 L0 h" r7 s6 N
- })% j- U* J& s5 f: s" i! Z0 ]
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例8 U; l8 Q7 Y3 n( o
- <div id="app">- _% N' `1 Z `8 `5 p5 A" ~, p
- <child message="hello!"></child>, C6 M& y% Q0 C4 V4 p4 D
- </div>
6 h) I3 t E8 T - & A, T% n8 N, C w& t
- <script># P: f3 e2 ?1 h; l2 f! w$ E
- // 注册
w) V- [4 L7 c1 [7 z# h# B# f0 c - Vue.component('child', {# l, v& V( k/ S E3 f4 b& H
- // 声明 props/ y9 M* ~% m$ C# _1 J3 s
- props: ['message'],
( S: Z' D: q; C. Z - // 同样也可以在 vm 实例中像 "this.message" 这样使用
3 C0 R7 Z: _: e - template: '<span>{{ message }}</span>'
- w" a7 c* G2 Y2 e7 W( \1 [; a3 z. k - })! F7 }$ q6 w2 V5 c: J3 a
- // 创建根实例3 ^+ Y: O% m' m; X/ K3 j
- new Vue({
9 ?8 A8 x. p" h( |/ F: L - el: '#app'
9 E5 }4 O: d/ J& \ - })
4 b: z9 K% S7 a! e W I - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
* b, d! w) Q4 x0 _5 s; t- <div id="app">$ g! ?- K+ O3 P" T* Q, W
- <div>
( `3 V+ J/ L: P, [- {2 Y, d7 g - <input v-model="parentMsg">
! q# s1 e2 l% W' G! k U - <br>
* j3 Y; t7 C( j% e - <child v-bind:message="parentMsg"></child>
- j2 I5 ]9 L+ c; ^3 W! K6 N - </div>
8 s+ V% D- z. ?- d V3 O - </div># w) \; c) U+ q2 D( M: y3 m
- " ^3 Y. y9 t; o0 y
- <script>
7 S3 Z0 d2 {' ^ {. x% u - // 注册# J# f1 u3 g/ ]$ B
- Vue.component('child', {
6 x! [& J2 H6 S' R6 ~ - // 声明 props- q) j0 l5 T! E' P
- props: ['message'],5 d" i$ B2 k/ J/ [+ [6 e( ~
- // 同样也可以在 vm 实例中像 "this.message" 这样使用2 D$ k3 l; ^ o/ K: Q* u
- template: '<span>{{ message }}</span>'
* i4 \% M5 ^4 B# c& N - })
t3 k3 C% k+ a! G! w2 r' F" G# H* w - // 创建根实例& q+ L9 d$ _5 W2 \+ ^9 \# Y; Z
- new Vue({& G( M; F t: |: E) m& ~" O& ?
- el: '#app',
# ]: E; b. c: d4 x; C - data: {; E/ E1 |# o! y: {7 D: v# q$ \. {
- parentMsg: '父组件内容'
6 d) P6 Y. {* P$ G - }7 G$ ?! S6 v* J( A+ O- _; L8 N( d: [
- })% b1 Z+ Y0 {3 o4 v# R
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
+ R1 B0 p8 @( T0 h4 J- <div id="app">1 s& h1 v* m1 h: v/ \1 f1 D3 x
- <ol>' [7 n. r" X; d, G( x
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
7 f6 y3 a a0 n9 \: | - </ol>$ |! t \8 O1 x& d/ @' o; ]
- </div>
2 i2 L1 J; w' T. T' s b0 i -
/ c) U3 E: c% Q# P& ~2 W" m4 w - <script>8 I; }/ g- i0 y, l7 z
- Vue.component('todo-item', {, H5 n& `2 g4 Z- G- M" w. j
- props: ['todo'],# y( ]6 |8 A# ?1 l6 j
- template: '<li>{{ todo.text }}</li>'
1 A5 u0 z, H& l% q: ~9 g7 c - })
* P8 _# o6 w6 \1 U7 S - new Vue({
5 @6 H5 h! S6 T - el: '#app',6 P4 ^+ ]8 ^1 g9 v
- data: {
1 [0 Q' `0 |5 r6 ?, N" e! { - sites: [! M* h0 G# _/ q/ i2 y- ]% c
- { text: 'Runoob' },
& [' g. w2 u$ q* J. l+ @ - { text: 'Google' },9 @/ [& l9 g, s6 y. m: @2 R
- { text: 'Taobao' }" p( b" w! o9 f8 L/ d
- ]
9 W( C* ]& a! T* Q/ h8 C; Z% E1 L - }, W$ f9 A# {+ {+ G
- })
4 c1 F1 L j7 f" Y2 q8 e* J - </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {' `& G7 l9 _' C8 |
- props: {
i/ }! M: a7 w( [; g" |8 X1 W K1 V - // 基础类型检测 (`null` 意思是任何类型都可以)# I% U/ S, D; {& g/ B, K/ m
- propA: Number,
3 n$ T! s! d1 w ` - // 多种类型
4 W! d. N! L1 q, q - propB: [String, Number],
: q! o8 y- H1 _* c6 F - // 必传且是字符串/ q+ E' ~( x9 b: ^; S9 c+ U
- propC: {
# F4 j* T, h4 ^% y/ }0 F6 r1 ] - type: String,
. C N1 X0 N- q - required: true; s& a4 {. s2 W% _& r
- },
4 r5 [" E' G6 K - // 数字,有默认值
6 A: a8 ?0 d- c; E8 Z - propD: {3 s, {# r$ D7 k0 A! D6 a0 i- F
- type: Number,
, ]7 g( m$ T$ S$ L5 c6 X( b - default: 100* F! ]1 `6 I9 `( q5 f$ X
- },# C4 l4 Y" ^1 J" g& u- r7 b
- // 数组/对象的默认值应当由一个工厂函数返回
/ Y" Z5 H. F! @ [- o) _' m1 v - propE: {
. ?! A( E! {. K" ? - type: Object, b- @! M1 W! Y7 x4 g
- default: function () {
9 Q8 i6 v- a c3 q* y - return { message: 'hello' }
- G0 r# ^6 F; D0 r5 d6 `& ] - }- o' {$ M# R, |8 `: e3 j
- },
7 D* b5 D0 r: }0 X/ r - // 自定义验证函数
7 `1 V6 l8 L! P2 [$ T9 { - propF: {
" p/ A6 U3 ]& o; m - validator: function (value) {
$ ~9 y, _# _5 x' D4 j' A3 L - return value > 10, b+ T. m& n% e3 G m/ j
- }3 S; e& i) l9 x0 C+ a
- }* h U) L2 V1 w; A+ ]& I: ^! m
- }; ~' u/ x( q( H0 L/ s# K! p
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
; h& m9 t: s4 h4 b
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
' `0 J l- ?3 ]1 h. \* L/ a; P
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例# p$ U; y b' m( R
- <div id="app">: Z# J! x% M" m( f+ S% s
- <div id="counter-event-example">7 }. c0 c* G0 Z) @2 m0 \. \
- <p>{{ total }}</p>
8 y, s, q4 v n! g+ l - <button-counter v-on:increment="incrementTotal"></button-counter>4 J. b# h9 d1 r( p
- <button-counter v-on:increment="incrementTotal"></button-counter>) H! I' e! I- N8 U0 F% n' P4 _
- </div>
$ ^4 f! ^1 Y( R$ R& q5 D7 \: i - </div>
# W* v3 ]: ~, V2 Z, w -
( a$ @8 N- }$ e! { - <script>4 g, W( d5 B- V$ o
- Vue.component('button-counter', {+ d0 _) \5 }. k/ B) o6 U! L( C
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
: e) u- t, P1 D9 M - data: function () {. Y7 ]& J a: Y L1 U0 A+ b
- return {
0 J, z5 P; `+ t4 A, r7 f8 ? - counter: 0
7 j% A q7 m: p" J& r4 q - }9 \$ M* E+ g2 M2 Z, N
- },9 ]: o7 g" C4 h. |* s$ [
- methods: {
$ h2 ^! s0 E5 M - incrementHandler: function () {+ q0 X( Z- _7 Q9 j% R9 X+ P
- this.counter += 1) ]- v5 ^# c! U7 ?* J3 R/ F( m
- this.$emit('increment')
; Q3 @! h$ w4 C z4 n - }) n L' b) i( f$ q" ]
- },
. I. X5 T; y: |$ R& ~, ~ - })) B% @+ @0 G W9 v/ ^/ V
- new Vue({
6 U0 C% ^! z) O! h6 u: |% X1 @9 z/ A - el: '#counter-event-example',
7 a; S( ~! P+ k2 E0 \7 } - data: {
9 b: P5 W3 e7 x0 w7 d2 k - total: 0
8 b/ f2 S. T7 _: D3 V - },+ s0 ]$ n, @7 A/ a
- methods: {2 Q% E1 }" o1 h5 Q5 `* z% A% z. C
- incrementTotal: function () {
; N6 `6 l! h1 j! E6 ?8 P) K9 x - this.total += 1
( d% M. S! v7 F! U* W3 K - }9 S" Z: M. M5 y5 C4 T! c" a! Y
- }
' l0 z; D9 ]2 u% i4 U" T7 d - })
! S; s+ l* S3 T- c2 F" x, [" U - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册; R/ z- i+ l+ Z0 N+ E% m
- Vue.component('child', {
* Y& t, b; D5 L t, D5 W& W6 k - // 声明 props
8 y* b4 C4 c- Y6 U3 R; l( l* R+ A - props: ['message'],$ ?# v$ _: y; E4 J4 ?& A8 X
- // 同样也可以在 vm 实例中像 "this.message" 这样使用* I8 Y, M* S; R+ q: z
- template: '<span>{{ message }}</span>'
/ N, v1 H: @2 m& H - })
& U! `5 ^6 O7 Q% i8 g. V; l) P6 l' A# u - // 创建根实例/ Y3 n2 _8 J; Z8 y( S* V5 |
- new Vue({& g; `1 N# ?* b, f6 x
- el: '#app',
4 d% x. f- e8 }" h - data:{4 @8 t' t8 ]' A/ W& A# i* S) _
- message:"hello",
* t( H8 L( n) S* M+ e) l - }" E# g6 N7 a; \: p5 e) X9 ?) x' t; N
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
1 i; Z9 O* o3 o- M! t - incrementHandler: function (v) {
E J N4 {9 t8 e: _ ^ - if(v==1){* i& U8 x# ]# o" y1 c
- this.counter -= 1
+ v; x, N* _! } - this.$emit('increment',[1])" r! M) X8 R: ?2 c* @/ E# m0 F$ V
- }else{8 c0 e3 Q/ }/ q( x2 Z. B
- this.counter += 1
_7 p$ R( Q) U/ b! v - this.$emit('increment',[2])
+ e( q/ w# ^$ P - }) a- i/ V0 `& Z+ b
- }& q0 V- x, y$ q
- }
复制代码 % n2 [- ^5 M$ t4 T, b
C0 H/ A" B3 G, k
|