|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它: 8 h; J# H( M$ g- g/ Z, x
- <div id="app">* ~' I6 X( r! e5 Y7 f% a
- <runoob></runoob> g) H4 ?# @; N
- </div>- N# q8 [/ J0 P4 R6 A8 U" l$ |( S) I
- + S8 |9 s/ l. k* y1 Q' t
- <script>5 g. A( R: k+ v7 T* w
- // 注册1 p u, y# p# [ {3 G: v) Q. g5 o( B
- Vue.component('runoob', {
1 v% X2 v; J6 O5 l - template: '<h1>自定义组件!</h1>'
! K6 J% y8 G" B$ ]7 \. M9 X - })" _) [, P( c: S7 k7 [) \% Y
- // 创建根实例
' ]% S' y7 i: ]& K/ t - new Vue({, U2 Y, e* j% u7 K m6 f3 N3 E
- el: '#app'
( Y$ u" h, ~/ m. h, ^% | - })
: U+ m2 Q0 V) ^# j, V8 w - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它:
2 h" S5 v* J" Z, Z! Q& q7 s* ^- <div id="app">( \4 l0 p% J4 _" H2 U
- <runoob></runoob>! A$ X/ J4 [7 p/ R
- </div>$ A! J5 ], L" ^ Q- C
- 5 R1 n2 d. K7 h
- <script>
5 |' Y( Z! A4 H4 n3 \) G - var Child = {
+ p, ~, B5 b' K, z; e - template: '<h1>自定义组件!</h1>'+ b7 |$ G" r V2 v# B, r8 x/ O2 Q. {* ?
- }
: d ]3 M# F( N) K c - . [+ e4 S2 O! P0 d' G& \' W
- // 创建根实例
* s) ]( A+ S F, |# \3 U - new Vue({ b/ P6 k8 J+ h4 U* \
- el: '#app',$ u8 m! N( R+ Y( Z
- components: {5 O4 B8 i! d" g" X0 c
- // <runoob> 将只在父模板可用
2 @" l5 P& F* _9 \( c: V0 w - 'runoob': Child) y" _2 F S k6 q# T; D. N* H$ v+ R" k- ^
- }3 ?5 ^9 {/ T3 W. r; l
- })8 K4 l, I0 @. T! W8 f* d- x9 d
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例
' [* A+ S4 x* w2 ] l- <div id="app">3 P! Y# p3 ~9 O
- <child message="hello!"></child>
" N G$ L: _" a: b7 W( G - </div>9 A0 i" P$ J, y2 T$ G
-
/ B9 J3 V4 S2 ?9 q2 } - <script>
! b' N: }8 }; ^ - // 注册! {" O' }! }5 h/ ?0 P; S) r
- Vue.component('child', {
- {& K$ n) w9 ~- _, d - // 声明 props; s2 I* \( j( O8 [ z; V a+ ]
- props: ['message'],8 [8 _' m3 }, {/ w& {& R
- // 同样也可以在 vm 实例中像 "this.message" 这样使用- L$ h6 ]% B' O; n$ t& U$ t1 @ S
- template: '<span>{{ message }}</span>'
' t; ?6 H2 c. a" V3 c' N/ s8 l - })
1 w: A- c# C2 J3 `$ t5 F - // 创建根实例
& Z: O: r' _3 c$ k" T - new Vue({7 a2 G8 K ~% R
- el: '#app'
( g! ?; M0 F6 `' U# I. W! M$ p' m' ~ - })
5 t8 a* L6 n7 H# U - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例( H! v- N/ z1 ]. s0 }" r
- <div id="app">. Y# `7 U, N9 q. ~" N9 q
- <div>2 }+ }% z, k/ Q6 B) i) U5 ^1 n
- <input v-model="parentMsg">5 b1 J2 T! K' \3 v( r2 r
- <br>
) K5 `7 x$ d9 x# B, I F4 o. U q0 _ - <child v-bind:message="parentMsg"></child>
6 F0 P! K& M9 c! M4 I2 z - </div>! _$ l/ a X$ ]2 C) }' f1 {
- </div>
* n* x* X/ q& W% ]5 b -
3 }7 c% f, J7 W, L - <script>- P# h. Q( s c& Z8 n/ T. J L
- // 注册
% i O& T4 l( b& R* W - Vue.component('child', {+ y( D4 Y) ]2 z1 J
- // 声明 props
4 p6 Q8 G6 W! U6 Z - props: ['message'],! J! G; u# W w6 Z$ k2 M3 M1 M/ p
- // 同样也可以在 vm 实例中像 "this.message" 这样使用0 S( A$ z3 e( _1 x
- template: '<span>{{ message }}</span>'9 N- T! ~: \4 y8 X5 ~
- })
' R7 l% F, `: O3 P& J" b* V: D( p - // 创建根实例% Y3 N2 {' ~- y) p
- new Vue({' k; V* L7 t. h3 m
- el: '#app',! Q& j! D3 d9 k' j) y( L
- data: {
' c, _- ^7 v5 f- z f - parentMsg: '父组件内容'
3 ~+ M$ B9 m% t8 P0 p - }
( j8 M/ I' V4 ?* n" _, x! Q' z - })( g% J" P- ?' C7 b2 }9 F
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例9 R/ y( q2 K. d( K% Z5 A
- <div id="app">
7 x6 E3 z( o, B! ~& D6 l$ A8 W" \ - <ol>
' v: H( Q( f6 q# s8 I# i! S0 K/ T" [ - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
1 v, E) r( R9 p - </ol>' a4 x4 u, _0 g% X0 Z
- </div>
" u' o5 B8 O' i - 5 m7 P% o5 I/ |; K) X( C5 R# X
- <script>0 l5 X* d: q S3 d5 i$ P) P' o
- Vue.component('todo-item', {8 k5 D& ^, j: ^3 L9 O: z k
- props: ['todo'],
' m" a1 c3 v9 V' n' F$ b \ E& H - template: '<li>{{ todo.text }}</li>'
; R0 ]' c' a" Q9 ~ - })$ F5 `4 |: n6 [; F
- new Vue({
) K; a; Y% ]' [/ b1 j - el: '#app',
3 l& N9 F1 u. w) X - data: {
6 u/ G! _/ H. P2 z; e - sites: [6 k: D8 t2 R2 K8 j
- { text: 'Runoob' },
' ]' R% X/ X5 `9 p - { text: 'Google' },6 ] `/ f% E" `2 h) G2 \/ X
- { text: 'Taobao' }, M" S0 }5 d) k. Y
- ]
6 w9 m- |$ V, F) Y7 E! B - } z) q1 m: K" W3 y. h2 g
- })4 m _* b1 i( h! D/ X7 O6 U5 O1 P% T
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
# F# `: \5 C! z, y% Y - props: {6 |: K6 `: p0 y9 E" H! H
- // 基础类型检测 (`null` 意思是任何类型都可以)
7 G! G! Q E. b1 u' o2 B - propA: Number,
3 W$ D& ^; B8 E% C) K* D5 {- u- T - // 多种类型$ b2 G6 x; Y! n/ j s; q+ D9 V
- propB: [String, Number]," ~- x/ \3 Q% }: W. h) ^
- // 必传且是字符串
( S9 x3 I+ _6 x, Q) o+ a, I5 U$ X - propC: {; _/ X4 I' g! \
- type: String,1 T Q+ B9 x4 R1 a
- required: true
% T7 x( [' r# v1 T% i* { - },
* A3 U5 b3 Z3 `' D1 l1 \, } - // 数字,有默认值
2 J9 m+ J) @$ v! ]* Y( K - propD: {$ ?8 Z, N! T9 g- S( k! u
- type: Number,- _5 b: P% O6 O: j2 B( x: \
- default: 100
* l7 t. R+ P9 a( Y. M - },' A) k5 U5 `; m# t, ]* X3 c1 `' ]
- // 数组/对象的默认值应当由一个工厂函数返回: B! Q5 z7 g$ X
- propE: {
: c6 U8 |1 s4 w* d' i7 E9 ?" c - type: Object,: b4 _7 d8 i$ |2 k3 W( U% d9 H7 T. e1 x
- default: function () { c! M/ J1 `; I" l/ ~: w/ P" K
- return { message: 'hello' }
0 G/ C4 t" C; W6 | - }
' k# \9 G5 s. Z7 ^ - },
0 `) [: U8 a( b' f3 }; G" g- ~: d - // 自定义验证函数
6 w( h0 r, {/ Q7 W- M( x - propF: {; D7 g, U8 G( F
- validator: function (value) {
; c6 m Y- |0 L/ K - return value > 10# @& Q4 v) I2 Z: E3 r
- }
# P% [8 _2 L/ A3 r7 |: [ - }9 _+ d! U! P. ~3 o- N& a3 y
- } g% {& U, X, v& \0 y4 Z7 V$ `- m
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array& H: S+ d, A1 `" | R. j, n
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
9 v8 H, M! _/ O2 g% b% r X
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例5 C2 L' r! N- k, d
- <div id="app">/ S2 w# e% y" M7 N! q
- <div id="counter-event-example">
& k5 o& @" T, Z: G# x' ~! N7 r9 ~ - <p>{{ total }}</p>
# t6 l5 z4 ]# g0 { - <button-counter v-on:increment="incrementTotal"></button-counter>. f6 Y( W6 K+ B
- <button-counter v-on:increment="incrementTotal"></button-counter>: Z% [5 T" g" j+ ]6 x5 g: W
- </div>- c2 D. d- b" f: d' q0 A1 }
- </div>
W9 g; s! h2 i7 b2 u% p - 7 R! D5 @7 j2 H, y9 k6 N
- <script>
7 u9 e0 I; S% e" `9 M9 H; J - Vue.component('button-counter', {9 W) `: y; r& [' O- s
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
: g( P4 K' h3 p$ q0 B4 C9 W - data: function () {
" j% {$ d# |3 p6 C" ~ - return {
0 s7 V" t: Y5 E& y8 `/ U+ i( Y( e4 a - counter: 0; O" q$ u' K( R0 \! N" L0 o
- }; f& M- n# F7 P9 A! e9 p& J5 [; c
- },
) F* F% c) y# C Z! G& U# [4 v - methods: {
5 I7 {6 d' n8 F - incrementHandler: function () {: P9 r2 h) [& |% ]- }
- this.counter += 13 e9 d" Z {. _3 q
- this.$emit('increment')$ q, f7 F& ^, U( L0 l9 @, s- H) B- x
- }
0 Q9 {0 N$ _ Y6 x' q5 l1 j2 p! W - },
( { B+ |( q. ^& H" o( V0 ` - })
, C! R3 H( h, b6 K3 z( M! o% p# v4 d$ E' U - new Vue({
7 y+ N; s; b2 p/ M - el: '#counter-event-example',1 z: H& z# Y7 l {: J* r" Y3 c8 g
- data: {
" j- I8 C- E: j9 Q: o - total: 0* T- \4 Z* R5 z
- },
8 _) L$ F$ a) F- z- T7 { - methods: {
. H# t! v. `! N# G - incrementTotal: function () {
& G- E! c% o# ]: A8 V - this.total += 10 I( w: B! Q2 I5 Q
- }: @8 h! a, ]/ K- |) ^* E# w: M
- }3 P3 Z5 a# W+ f- i2 H. Z$ \
- })
" y/ q4 ~" [' O - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册+ p. E( k9 [: M2 X X4 J
- Vue.component('child', {- L% _/ A8 T5 s+ F. @
- // 声明 props7 [6 p& @- z8 _ m" l
- props: ['message'],5 x- R% j1 ~" S+ l5 G9 E
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
" s, L7 L: |% S, _ s - template: '<span>{{ message }}</span>'6 ~6 U: @! N) s# Q$ P: C
- })( W8 S1 l" [9 ^8 d
- // 创建根实例
$ |9 F' u; f4 P" ^ - new Vue({
. A C. v9 L) K2 \5 } - el: '#app',# y6 q& S4 r; p" B8 ^
- data:{
% ~- Q' V* j X, S; ^1 U - message:"hello", Y0 A1 K8 X- s: ~ m
- }
3 C5 W9 s/ [+ X6 d1 W - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {" C8 j3 ^9 s. o: S" ?
- incrementHandler: function (v) {
; |% e- m( B$ d0 h; u- \ - if(v==1){
6 B1 ]+ X" x) h7 _' w% i1 l - this.counter -= 1
9 C4 t& [ q9 B5 x - this.$emit('increment',[1])
# a) @4 }0 W/ G4 c) |) P6 b9 J - }else{4 K" F7 A( @ S# P8 _0 n
- this.counter += 18 i# y: `+ i$ N/ B; F' j
- this.$emit('increment',[2]); |6 [$ m1 L+ U4 L
- }
1 s7 P0 }4 n$ M! W# J - }" b0 q/ q9 \$ z
- }
复制代码 + n7 r" P& T/ }, A
j5 x5 P } E" ?: L# Q) h |