|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
) L/ P9 y) b" U8 ]8 K$ x- <div id="app">
! v* z/ _! \3 Q( F1 u - <runoob></runoob>
* e6 W; v# a# e) ~; Q5 ]* n& ? ] - </div>$ h% E1 m0 Z! u0 B; t
- 5 s" v, ?: G3 o2 F! @! H
- <script># Y% J( K( w$ B& p' G" }
- // 注册
# \! g! [. Z# { ~! M% _ - Vue.component('runoob', {2 R- J# s) S% D: q1 y
- template: '<h1>自定义组件!</h1>'( Q, I. n" Y$ r5 U* e1 O: G, U3 I
- }), @# e0 Z( y& s) {
- // 创建根实例: n! W$ @5 h) K: B W. j/ z
- new Vue({ s( R$ ?+ I; w2 o+ I8 |
- el: '#app' `# d% f; g: R( ], c. Q
- }); G8 `" G3 M8 |0 g. `; p( r
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: $ ?' B1 s: i& v# a
- <div id="app">% P9 t t3 e6 D2 T$ r: ~5 c2 j1 |
- <runoob></runoob>( K4 |/ P3 Y# y, P3 E
- </div>
5 A+ o6 c V# J& d) t: ~& z -
, r1 U' J$ y' y- @5 q1 O - <script>
4 {( z$ d3 G$ h) @; I) B7 `5 r/ c - var Child = {
$ a; ` |6 h, |$ e' R0 o/ f - template: '<h1>自定义组件!</h1>'
" u, y3 y+ K, h - }) _" `; X- V8 l# p
- ! |8 ~$ n) d4 S' A# }# |; n/ g
- // 创建根实例2 y) c( W7 `: C# \- L6 u
- new Vue({; J S; i6 s' ?- S, W9 i
- el: '#app',- q' i) ~7 l& J% G2 P/ m& e- G2 i
- components: {0 J5 d. q9 W* A6 b
- // <runoob> 将只在父模板可用
# b6 T/ H1 G$ P5 M - 'runoob': Child
* j+ P) F& E7 R. t# L; ~& Q - }4 m% ~- F7 }* U3 f+ j: I- e
- })
! t2 g+ W# T- f* `, } - </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例# v2 c$ Q7 K) f
- <div id="app">
5 W+ @& U7 f' @4 v" \ - <child message="hello!"></child>( W9 S: Y t( ?7 v+ G
- </div>
/ n% G+ G+ _. M% x q' k5 G# |! U -
% P6 }2 G# c6 |; _ - <script>
) A1 \1 i0 {2 q; Q: Y - // 注册( f( a% `' `) h" `( M0 R0 l; P
- Vue.component('child', {4 I7 O. ^: Y" N" R
- // 声明 props
; q9 R( |; q; ]) E - props: ['message'],
) v n# ]( z, | - // 同样也可以在 vm 实例中像 "this.message" 这样使用
$ |* R0 K9 H) h1 i' \; n% o - template: '<span>{{ message }}</span>'
0 M; C0 n+ m* a, ~: D - })8 |5 [* i- d$ P, {3 A0 Q
- // 创建根实例
* V# ?- b6 b7 {/ L3 c& b' I - new Vue({" d, P! H8 w1 ^- M3 b
- el: '#app'
7 h$ _& B$ k2 P) Z4 z' y" j& s - })
* W2 e) l. {. w# ~ - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例% ~% `4 {4 y* |2 ?6 {4 E
- <div id="app">
2 i" o) L, A+ D0 l5 S, H - <div>( C: T1 ]6 c+ @$ r, Z9 `
- <input v-model="parentMsg">% M2 z4 u" Q2 k1 ]/ i7 F
- <br>
6 {8 C3 b8 F! M/ Q0 k/ R& a$ D - <child v-bind:message="parentMsg"></child>" k8 k% m: D( q& ~1 O( `$ d' R9 N4 E
- </div>5 `5 @0 _$ g# Y& x! x7 x
- </div>2 E7 n9 N3 J) w" V. S6 f; l. Z! b6 f
- ' a7 B# ?) [ T4 T% h
- <script>& e4 m8 Z, K2 q" [, t: q! s
- // 注册
! |. i4 T5 h7 n+ v \& A0 S9 ]! V - Vue.component('child', {+ V. y* U( O& p5 C
- // 声明 props
( h* d7 d# p' y; G e! r- y - props: ['message'],
! K6 f1 [* Y V4 G8 }, P5 X, b - // 同样也可以在 vm 实例中像 "this.message" 这样使用7 u7 l2 ], H4 {# g
- template: '<span>{{ message }}</span>'0 j) g& [1 |9 t& `
- })$ \! h; p% k# c4 x9 _( [
- // 创建根实例+ L6 D8 R" u: g2 V3 c5 G
- new Vue({
2 I0 W! v& V% B5 t - el: '#app',
. b/ B2 F/ Z$ e/ O: E - data: {
: H" E3 `# { ~% @$ \/ Y - parentMsg: '父组件内容'
1 F4 u, K1 p+ ]- n; m5 m - }
% f/ |3 [% C' \0 n; U - })
, C- h$ f' q/ J - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
7 [/ q" w" O. a, u- [( _4 \- <div id="app">
2 L3 B4 o# z+ z | - <ol>
; v5 T5 P. L+ r6 c - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>5 n0 d# D, \6 p5 _1 f. v: ]8 x
- </ol>
% O, x) i- ~' [7 q( W* W - </div>% z3 U& ]5 E# P
-
/ J1 i' s2 P; i l - <script>
) n; N- ^2 T8 e' m' _( {2 g- C - Vue.component('todo-item', {0 b7 u/ d' |7 L6 {! S9 }1 l0 D
- props: ['todo'],
3 j1 ] d W* a. h4 Y8 Y. N& h - template: '<li>{{ todo.text }}</li>'6 c) W8 h. i! l! t4 M% K4 m
- })
2 B* v9 `: Y% ? - new Vue({
2 H( M# \" c h& H* t - el: '#app',+ E$ E' p. C7 E0 E& C# m- w- K
- data: {
* S3 y3 L/ t, x - sites: [1 l ?) y5 X% J1 ?) P
- { text: 'Runoob' },
; ?' b# ^$ N) t. h! ?, P - { text: 'Google' },3 D) W5 _/ F9 y1 c* v6 Z
- { text: 'Taobao' }
+ M. {/ x% z Y7 E3 V - ] `5 Z8 P" ]% C+ }( W2 k
- }
& b# y& f3 K1 B- B$ W- F, [ - })
/ H8 Q) V" A p3 a% W* O2 b9 g6 M - </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
# ~; b- V+ R& y8 s( \; H2 r3 @' \6 b - props: {& `, V, q& F8 C* j2 H s
- // 基础类型检测 (`null` 意思是任何类型都可以)
8 z1 K% ^: \+ h# Q- t - propA: Number,- \. K3 O% p0 c. w. d
- // 多种类型& X: G' W& K/ N/ [* i' t. G
- propB: [String, Number],
3 [0 f8 t3 m; l6 c: \, O - // 必传且是字符串7 K2 X% u( \: R# n
- propC: {/ U& b3 D* n7 D4 x# R4 A
- type: String,
- {: R4 s. Q/ i - required: true
, _' T a8 P, H7 X! ?2 D - },5 a5 e7 z/ B" R( Z
- // 数字,有默认值( s% y9 Z" z* l% B
- propD: {
* P% T: `; b4 o" w) t- P' k - type: Number,- q, B0 H) V& C
- default: 100
9 P) t( @& Y; u6 R; a& C0 D - }," q. Z; E; t! Z, b+ p9 v" N9 k6 C
- // 数组/对象的默认值应当由一个工厂函数返回1 j- h1 a! K3 p
- propE: {0 U0 \/ K0 d9 Q) ~1 O; ]
- type: Object,
$ M0 {+ C2 o6 n& d: _: e - default: function () {8 [) M) Y$ }, }7 Z% S& G6 g# Y( S
- return { message: 'hello' }8 W `4 t4 {6 m
- }
7 Q0 b8 ]/ v8 M7 U }" n1 g# H - },7 M8 G5 M2 J( t. w* R5 {
- // 自定义验证函数/ t4 Z" P9 A# ^# Z, W
- propF: {. y" w* {5 d2 T
- validator: function (value) {
9 E* }( b; j! E7 U - return value > 10
% W# Q" b' |: Y1 }8 L - }
# s J/ ?7 B0 f2 E! Y3 _) t' s - }
$ f' C1 E v! c5 a1 F& A - }; ~7 {4 [; N+ ?0 U! C* P B
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
- J6 U* `+ L& ]9 C5 f" ]( [, B
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
: b/ |6 O6 |4 Y( L
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例
. c5 N' _7 [) J; |& y- <div id="app">( |9 m$ m' Y2 F z" c0 X. s
- <div id="counter-event-example">
/ x& v, F+ L: F* Z/ J! ` - <p>{{ total }}</p>
- f+ E7 ]4 I: H - <button-counter v-on:increment="incrementTotal"></button-counter>
2 }/ O8 O) m0 W$ F( o9 k% {, j - <button-counter v-on:increment="incrementTotal"></button-counter>- K. |2 z3 n# B9 `- _$ H
- </div>1 m- T3 w' z/ o4 J$ A. B
- </div># i8 G- s" F. h+ }6 S( [
- + p& {! ~4 I, U( p) L$ a$ O% S+ x" v
- <script>1 R2 y6 @8 a7 X' k' E# B. L
- Vue.component('button-counter', {
$ W0 Z Q* ]7 J - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
* }/ S- Y( }9 o - data: function () {
8 C5 C4 f% f5 a' o - return {
( m3 G8 J8 p( O2 s; F B6 x# _ - counter: 0+ E" M+ b# X$ n0 R4 t# K
- }- n' B. G0 o0 }. g6 O( f( ]: h
- },
! H2 p: D0 e5 ^6 W5 W - methods: {
, F1 _1 u6 p- u( C$ D4 J - incrementHandler: function () {
* G( U2 ]) S3 ]) D; A - this.counter += 1
) Y, a2 G2 }7 `% S; W1 I - this.$emit('increment')! l/ A7 ~ a+ r( o% r0 I
- }
5 D$ S: P' c; p5 Z( `5 U' C# N - },
- g9 H3 I: U3 o' {+ d8 C - })
- K) y# p* U- I6 F: d - new Vue({
r# ~3 V4 {: Q7 p' J c2 v& i( e - el: '#counter-event-example',( K( c0 v3 x0 G% a5 Q0 K6 v
- data: {2 J8 i& ~3 u( Y* c3 |0 B
- total: 0
- T: l5 N+ |. Y2 I5 W0 r - },1 }6 T+ d# H! K' ?# K$ @* v: h
- methods: {
# k% r( N5 K2 |* J% B1 X0 x - incrementTotal: function () {0 R/ i* Y0 H; P/ j7 ~ \
- this.total += 1
. {, B0 R0 @) S, t& h6 a - }
" b# j! y/ ]$ a4 y% z; o2 x6 `+ \ - }' M f" }, d4 W) m1 M6 [1 a
- })7 r3 d0 X9 b3 \" P- h
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册9 G0 m4 c/ c! t4 D I* ^- w a
- Vue.component('child', {
9 s5 }" c8 S5 w C3 c: Y9 t1 m3 a - // 声明 props
9 n- }6 N/ T" ]5 n8 t3 U9 D - props: ['message'],
4 B$ }* i$ J+ r% Z% {* N - // 同样也可以在 vm 实例中像 "this.message" 这样使用6 n2 ^& F* n3 h5 G
- template: '<span>{{ message }}</span>'9 A( D& C! d9 f: \: I
- })% s6 X0 w, u/ M4 g3 z3 `
- // 创建根实例
7 ?, Z( @0 V3 Y$ p4 m# n+ m - new Vue({
+ z- ~6 b% ^. s* y { D - el: '#app', R5 a' A8 m7 I# ^+ x# K
- data:{
5 W( U1 p& F9 ~# L: N N# s - message:"hello",
* V' k$ _1 c3 c Q9 F* ^ - }% ~7 a Z* ?3 l% X
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {9 d$ E& g2 [9 R) H- \
- incrementHandler: function (v) {
) ?' J% {$ P- X - if(v==1){
2 G% ~9 g6 o, t# c - this.counter -= 1
/ W, k% S# s3 e' ?0 t. l' { - this.$emit('increment',[1])
5 w/ l' V' q0 M0 M( u/ ]5 G - }else{5 ?. _+ b( e4 E& \
- this.counter += 1
& m! v& r9 {! {2 l. U - this.$emit('increment',[2])" T: W7 C1 h5 p/ r+ G* @
- }
6 Z" G, [. n' d$ `) k$ p - }
" P2 t0 A# V( @8 ^" k, y/ M - }
复制代码
7 B" b0 M- X8 G. ]+ D& |4 d
( n. o; `# e! C5 Q |