|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它: 0 Z7 H! N" h5 I6 \4 S3 }+ a: H
- <div id="app">0 g5 q( G( m$ [( g
- <runoob></runoob>/ {: c* }. F8 S5 k- K# p- s& K1 C
- </div>. D7 n' ?5 @4 K5 r! l
-
' W" t D/ }* K$ k( F: N9 I6 Q - <script>8 z" ^7 E. c) s) f
- // 注册) `! }6 E' `, F! w! x# v' j4 D6 ^
- Vue.component('runoob', {# \# Q) ~, t6 O
- template: '<h1>自定义组件!</h1>'
* b [* q- f8 [; A- S8 ~ - })
\4 \8 E; ~' y5 c5 e8 a - // 创建根实例7 W: V5 N* m5 z8 A5 B* s; ~1 I5 J6 w
- new Vue({
0 \: r# v2 m' B3 D" m5 v3 l. e* G: Q - el: '#app'
: x3 Y$ M, w6 Q0 h7 D, a - })
1 A! r- }0 J, y8 {8 _ - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它:
2 ?; J) D8 L( N- <div id="app">5 E3 J! }9 O3 w4 A' y( u
- <runoob></runoob>3 A: u9 n, P- Q, [0 x2 o* g
- </div>
: k2 g+ H* ?- O! j3 E' h- n* ` - 0 p8 H7 v) ^7 x% Q
- <script>
9 t6 I1 |6 [& l& D" }5 U - var Child = {
) y+ g( P2 N4 y! u4 @ - template: '<h1>自定义组件!</h1>': u: K3 N) e( @4 X- x3 B' _% R
- }* {& J$ R0 O0 H4 w: |4 I- m. F
- 3 `1 z' R2 _: }4 r6 ~: _# m$ ?
- // 创建根实例: l+ _! A) P- c
- new Vue({
, y) B! G' h$ m+ B s5 Q5 E - el: '#app'," }1 H5 c+ R: m1 u) n) F
- components: {
$ |" l; ]3 K0 X( `, w: M - // <runoob> 将只在父模板可用) e4 }5 U t- L$ ~( U5 v. A; Q
- 'runoob': Child
' B2 K) r+ A0 |( I9 d - }
# k! W/ U: Z l6 ~/ L - })
$ d9 T+ F( A, r' G" N7 U - </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例
/ H5 ]) y1 Z$ b- k! W; a- <div id="app">
8 c* i$ j. H% J, A I. } - <child message="hello!"></child>0 P" g& C1 d7 j9 e+ {
- </div>
d8 f. J }! c5 I& N - , u5 n: t. f: N. f7 N6 R
- <script>( h" B1 i- v0 N' x* g k
- // 注册
w: a# B0 c$ G0 O3 }( { - Vue.component('child', {) B1 \2 l! A2 `
- // 声明 props
& g) I/ z6 m9 t7 S' G! r# ` - props: ['message'],. g% X, E3 }) V4 [1 a! g: m; e
- // 同样也可以在 vm 实例中像 "this.message" 这样使用6 T7 S2 X: E4 T/ n) l3 ]$ ^: s
- template: '<span>{{ message }}</span>'
1 W- S- E! {( c% r6 v# y$ | - })
# X1 W" i0 J0 c6 t - // 创建根实例: u5 V0 R. p7 _* w
- new Vue({
% M0 l. a& J; R" C% t - el: '#app', I/ A9 u2 J' \$ W
- })
7 G+ N$ S9 P+ }* W$ O4 p - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例2 v2 y6 w* M: {0 E' p4 d
- <div id="app">. t M" \" H/ D1 l: l6 D! g* v, ^
- <div>
- m! }0 M, Q/ n; C- I4 j - <input v-model="parentMsg">
+ f5 u" h9 H$ F$ e \ - <br>, O6 j3 q* A& {% P$ U- q. Z
- <child v-bind:message="parentMsg"></child>) k- [) d x6 T3 A$ l% M. t( T
- </div>$ P4 B1 F; Q7 V$ E w$ f
- </div>
1 |( A+ r& ~$ z8 Y5 @ -
$ Z! }. \- d% Q8 v( u# {4 ? - <script>
+ b# N+ {6 I% a& K, p% V - // 注册
5 n$ ^8 v4 w( y. b/ q7 n* L - Vue.component('child', {
1 l' J9 Z7 y$ w& X - // 声明 props
: y) W+ T9 d$ G3 Z& P9 ?, C - props: ['message'],7 @( A2 b( z$ }/ u3 D* U: Y
- // 同样也可以在 vm 实例中像 "this.message" 这样使用6 D5 B8 V3 [5 z
- template: '<span>{{ message }}</span>' ~& q$ C; e) u6 h, Y# L6 E
- })3 c! ^! U) O( N3 a& m, ^
- // 创建根实例* W4 N$ b! w2 u0 V( t1 l
- new Vue({
( g$ p2 v6 e. V9 l - el: '#app',
; Q) O2 F" I, Q; o - data: {
g0 p; P+ p" ], n) a9 b& q - parentMsg: '父组件内容'
7 k. M2 [' {% @; ?1 s - }
* R- M2 E5 Z2 S9 i8 D. a! f - }): b8 {; u/ s1 `. F
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
6 ^7 i! A/ r& g2 _, [1 ?# F- <div id="app"># L. w/ e" a k7 X! o4 K' g! e
- <ol>( C- p* d* ]7 Q. T2 w1 @2 [
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
2 Q0 I' N4 E# ~% k" G - </ol>4 v2 \9 E* S! h3 Y* p' ~8 \
- </div>
/ x( t# o: M/ Y3 b( A% x - 8 c- c/ _5 n& c/ A
- <script>
# ~% T* b, I& R `# M6 o9 { s, W$ y - Vue.component('todo-item', {
- j' s0 T; ~* P( P - props: ['todo'],
4 U, q( d, ^ i/ } - template: '<li>{{ todo.text }}</li>'
* O+ I% q% K: ]* d; P( H8 B: Y - })( v0 G. i+ x- \5 U$ H
- new Vue({4 U2 F4 t9 f3 A3 B& o
- el: '#app',6 F% r- `9 W0 R: x) K
- data: {
% s: g8 j$ x" y3 v' C - sites: [# T3 g6 a9 G$ V, u
- { text: 'Runoob' },* T7 r9 P- i0 y9 I, I
- { text: 'Google' },- Q0 _! X& D9 g. _* F
- { text: 'Taobao' }( o; M7 z& C$ n2 G& G
- ]
- }# G" _; l \& o - }
( t: ~& w9 P I' c _; t - }); |% M; k' t" `: q! Q3 n
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
3 i" k$ g0 u1 m - props: {
+ y& g0 A+ `, J* s - // 基础类型检测 (`null` 意思是任何类型都可以)
7 S1 V) ]& e3 D5 W; V - propA: Number,
3 K n9 A$ Q8 U0 D - // 多种类型' T) g1 B. u7 [+ ]
- propB: [String, Number],
% S2 G5 o4 e9 @; A& F$ |% a k - // 必传且是字符串
& I/ x" d! }% U/ O - propC: {, z) _+ e) |1 O+ s: H7 M
- type: String,
, {: C9 f" {! {2 r - required: true& g8 ~7 |8 w0 A, q
- },' v/ Q- c. k/ @( f! J2 Q
- // 数字,有默认值
1 y* | L0 { q2 _5 Z - propD: {
9 l& b3 Y2 I$ M2 \6 w - type: Number,
- ]+ o8 `3 H! y, c - default: 100( I9 }2 T- Z% o
- },
- I" `1 h. y: E3 G$ d9 A- p( t" U - // 数组/对象的默认值应当由一个工厂函数返回2 r7 F5 e& n! _4 i8 ]! }
- propE: {; T/ Q. k7 t% B; F$ k. {0 j$ g
- type: Object,
2 G4 I2 t; @" `) X9 G+ Q& L& l% Q2 I - default: function () {
2 K" S* ?+ t1 G4 }. g6 R* v( {* w1 I - return { message: 'hello' }( w- E( w* h( c) z1 v) k( t
- }
4 [! H: Y# X4 p9 J z - },
6 U5 I# P4 j* j! H) N1 q - // 自定义验证函数' A2 V$ N9 b( H( p
- propF: {4 D9 y) Y4 ]3 F7 U4 m9 Y
- validator: function (value) {
& A0 A+ L$ o1 D* |( P( r, Q' e0 E - return value > 106 W) p: z9 V7 @2 l% `
- }
4 c' c* _5 j i - }
7 U: g( u0 j9 j3 A! M& H* h - }
9 @1 L& J+ Y3 \; E5 p - })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
; h9 h, A T: P& ~
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件) O, x6 p! g+ X6 e# H
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例
; e$ q. [; i" R# S- <div id="app">$ a" m1 v% Q1 i% E! T
- <div id="counter-event-example">
8 Q% c- U K! s, a% H0 |- ^ - <p>{{ total }}</p>( U& F1 t: S5 L9 ?; V1 r1 [5 O
- <button-counter v-on:increment="incrementTotal"></button-counter> u% F' O! O3 N& Y8 \
- <button-counter v-on:increment="incrementTotal"></button-counter>% T& x4 |' \: l; g; D+ e$ u: R
- </div>
1 `9 m3 D% F8 a& @3 G% W+ I - </div>
: `8 R2 k/ k6 j5 o% N' e* x -
3 |! e J. Q; K* h" s4 Y4 H - <script>
( b, p& o; l" G2 F: j - Vue.component('button-counter', {
# }7 v& I' q) w a: p( ~ - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',7 q( w! u8 M& r u5 w( _6 l8 x
- data: function () {6 p0 e# i: |+ i) V/ m7 ^9 m$ f4 r
- return {! C9 N& ?9 o }8 q3 l" Z
- counter: 04 n0 M! a* L1 ^& V3 W# T$ r/ R" t2 A
- }- n- p# Y+ _- ?. ~3 i, ]4 k. W
- },
" K- m. u! l; ~ - methods: {7 M# X& X3 t5 T, ?0 O% O, d
- incrementHandler: function () {
* c! A* N. U% w - this.counter += 1: I& O" j- X/ L" U" ~2 W0 Q
- this.$emit('increment')
6 @9 c- w( M: j, L1 D - }
! K& s3 I6 ~3 B6 Q - },4 O5 U/ x( ^5 N K; Z; }
- })
9 K% W# f/ m: }: i3 Y" |1 ` - new Vue({$ P- O+ l+ y5 [+ j5 h$ u' V
- el: '#counter-event-example',
# n* k5 z5 W3 u+ F. o' N. X - data: {
( M6 S* W& ]8 Z7 F2 J' Q - total: 0
. x ~ c( P }, @: V - },
# L+ J* x" }7 j. ^/ j* O" q K2 L - methods: {
% ]; b( D* c. K. Q - incrementTotal: function () {
% U. D. j- ]' c0 H0 | - this.total += 1
0 K C: G# g. k8 p. U! \ - }3 T% p2 N; n# ]0 M) k1 k0 N
- }
7 _7 t) b' x ~4 u2 m$ p: @/ ? - })- d- r# H. p3 V9 H$ z
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册" S) @) T0 w0 R7 \) D* _" t
- Vue.component('child', {! s8 Z5 a9 u% v+ y' o# E
- // 声明 props* M) T2 p6 j7 S( m! j, Q
- props: ['message'],
; Y, \# y+ j% S: u - // 同样也可以在 vm 实例中像 "this.message" 这样使用
2 I, [" N5 ?; ^. [1 ]' h5 o. g - template: '<span>{{ message }}</span>'
. e' J. F8 _, y/ T - })
) U1 g' ?* F/ u6 B - // 创建根实例2 H+ i# F8 J$ }$ K" J0 Q5 }4 K
- new Vue({
$ A2 R, w$ V3 l - el: '#app',! m8 U7 R. w9 P9 |# ^$ |+ X
- data:{
' e8 k5 L4 T- r; j$ t - message:"hello",
) f; Z& k! ^& R1 f" g/ y& |" m - }/ |+ D# m% y/ ^" a2 ^
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
- W- v' {' @6 n4 v S - incrementHandler: function (v) {7 Y1 Y0 V* X v5 a' E; [; o T% ~
- if(v==1){
2 ]: \9 h9 D& f$ `6 { - this.counter -= 1( ^ x$ W' x( f- H1 I
- this.$emit('increment',[1]); g0 C0 M' U4 E4 @
- }else{4 d( C, S! Y9 l) q- I
- this.counter += 18 H; R2 K/ X% ]) r. b
- this.$emit('increment',[2])
9 Z2 {% |6 B5 ^- B- `9 U# c - }
1 l) e1 W3 I4 _$ n9 W5 V6 A7 l/ ` - }5 J6 ]& w: o% I- z) [
- }
复制代码 ! p6 `6 `; \) y& X5 P
) z0 g1 w3 z/ W e: Q( V( O
|