|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
Y. } { w! T) v2 w- <div id="app">& f( p6 ~$ J: R* _
- <runoob></runoob>
3 L2 J$ ~4 I5 N - </div>
8 ]" {! f3 ~% I9 n: R" J - 9 p2 [# f% J: K: g' d; v5 v
- <script>9 |% K) s" l+ o/ l" r0 ^+ i8 s
- // 注册* h& f, ^2 r( ]' Y& k' |: J4 N$ _
- Vue.component('runoob', {
( V+ C: k m+ l: Q2 s" k - template: '<h1>自定义组件!</h1>'
" j( f# Q: r$ p5 @7 f) w5 G - })
* {) T/ ]- G, Y - // 创建根实例
' f4 \+ h1 A5 _$ B - new Vue({' N/ ?) G6 ~6 ]
- el: '#app'
# S. o' u0 D Y3 ]; _& V6 a - })' Y2 |7 b7 a0 c u8 X
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: 7 T1 f9 x( g/ n7 o6 y9 G
- <div id="app">
' u3 c& v z4 p5 \6 u; [8 x u - <runoob></runoob>. u8 `4 M, M. I. E# E$ F3 a
- </div>7 N$ H# S/ o# q8 z( n/ g
-
3 f* ^1 y, H' c) a) U - <script>
, T1 n6 F' n* ~2 l# j( n( H7 g - var Child = {7 w. s7 s O! n4 C9 `
- template: '<h1>自定义组件!</h1>'
+ i4 k$ k7 V% P$ \$ D$ r, m - }5 h" l6 s9 i: H% v* A( X
- & O! M: m2 L1 c: ]+ @
- // 创建根实例' t4 X; ]$ d$ D4 w
- new Vue({
; I7 h, X. s/ F9 o4 r7 j2 r! ?6 z - el: '#app',- e f) L! L$ B; G, `7 _
- components: {
# `1 W' M2 x/ {& d2 @ - // <runoob> 将只在父模板可用4 G1 [! N" \ R* u/ G
- 'runoob': Child2 {% F% R" o2 d5 m
- }
4 B) }" |( e6 D1 A* Z - })
: M! u0 T2 E0 S! Y& u1 @7 N% A5 j - </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例
6 X- f6 A4 S" o3 E- @- <div id="app">" M4 {+ [' C3 g
- <child message="hello!"></child>
9 U9 P3 d% ~/ k% P - </div>
5 W; g, j4 |" R: r3 H" g# E" f. O -
5 m4 F+ m# H2 w6 [, U6 o2 F9 \ - <script>: V0 V ^1 K, A0 o
- // 注册/ O+ c4 Q4 j) U6 B
- Vue.component('child', {
1 K, w; m7 [5 \* M& X, d - // 声明 props5 {# x4 v$ Z* |/ Q
- props: ['message'],% j1 e0 B$ a8 b( @, E! B) C2 N
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
- _9 X9 @& T# |3 ~ ~9 | - template: '<span>{{ message }}</span>'
' P9 c; E3 v9 l - })7 Y/ N4 i. e, j1 O: X$ a7 B
- // 创建根实例
m5 A- V5 N/ Y' U0 ` - new Vue({; R: W C) R6 u% `; n
- el: '#app'. g. C9 q' p: @' ?
- })& W P8 \% \. S& E# i+ m
- </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例3 R9 z5 G4 u. ?* U) ^" |% _
- <div id="app">; f* V7 m! [5 b. E, m
- <div>0 ^' D( k: I" D- O: J; L7 H6 Y
- <input v-model="parentMsg">
0 k9 t7 }9 {: H3 F3 t - <br> C$ p+ }" i2 `! \5 x# [9 ?
- <child v-bind:message="parentMsg"></child>
4 G/ I, S5 V$ f3 h; d - </div>0 @* ?% p+ g+ @' X
- </div>" u" T0 R7 F$ ~! z( b+ v2 m
- 8 L& q5 a& J: V) W
- <script>. M3 \) }7 O" C3 B5 T/ g
- // 注册7 W- _. L2 f6 a; z
- Vue.component('child', {
/ M$ W4 o0 \ l/ Q( u' K - // 声明 props
$ `9 ?% B- Z+ ^; w2 }% e - props: ['message'],, a# [6 s9 j, Y* q1 n- {
- // 同样也可以在 vm 实例中像 "this.message" 这样使用1 c/ J' z+ J4 z7 \
- template: '<span>{{ message }}</span>' T6 }- ~* v/ E+ h8 X4 `( M
- })3 x, L1 q; B- e0 k) s% f9 f, k# p' q
- // 创建根实例
9 o9 w4 Y9 K3 y/ m; X! F0 J( S - new Vue({
/ e* _; {6 B! t) p$ N - el: '#app',& o( M; ~ Z' H x' G* x$ `/ g
- data: {5 c9 }3 ]$ c) ?' C! K3 K/ N
- parentMsg: '父组件内容'1 z1 c, g- ^- L9 Q( x
- }6 T1 w! j2 O7 F5 y' y( r( f f
- })
% t# k/ ^+ S) W( i9 E. u5 R - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
: _0 g5 s% s% N) i5 G+ @. [ y; `' P- <div id="app">" a5 b3 R5 V2 H2 A0 C% k
- <ol>
* m, ^' ?; ^/ t9 h7 Y - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
, d1 z: K& Q$ Z& J) g- w - </ol>
! N7 U% K0 p7 @; \* T* H/ S3 p - </div>
; ~5 F& S7 S$ `* F -
* _, \2 P8 U3 d' e% D - <script>
6 s! m) ^- M; [* b - Vue.component('todo-item', {5 u0 h2 `1 i- _: I
- props: ['todo'],
) K( G2 z1 x) {. Z% w' [ - template: '<li>{{ todo.text }}</li>'
* y8 a1 s. o# U! ? - })! H& ?' G9 l& Q4 {: p: S, @, p
- new Vue({+ O1 m$ j& m0 F$ m( X- \+ b
- el: '#app',
' d. j$ h4 h t" H# k8 _5 e - data: {
% r- T9 ]8 [3 @! S' O! O5 p - sites: [
( a# u- d2 W4 e, O8 X- ~) F - { text: 'Runoob' },. F) j) ?* l3 S
- { text: 'Google' },+ v' N2 e! a9 L, S
- { text: 'Taobao' }
& `; p& C( `" C0 @# ?" t - ]
, Y+ k7 S% p" U# X# R8 L - }; r3 u, D$ s* W) p, f6 _9 {
- })
3 x/ R: N7 E4 Z! H8 j6 Q/ T/ c - </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
X5 q' C. ]9 \5 R" t9 H6 E7 [* G. ] - props: {# u' P+ u$ v4 s" a: n2 g
- // 基础类型检测 (`null` 意思是任何类型都可以)5 u+ t Z" x- ~% n7 }0 l: ~- ?
- propA: Number,8 o. j0 L, e% c* E
- // 多种类型3 k3 m! W! d' j, c2 x
- propB: [String, Number],
/ K! i: m) `- u% f$ @5 G - // 必传且是字符串( i I6 w2 k" P8 V9 r
- propC: {
; k9 ]; q$ S' ~ - type: String,& s+ Z3 S* {. N& V( f$ [$ I' h; o
- required: true
' D3 G8 ~) B# {8 ^3 G - },( r/ A8 l+ x. I9 T3 }; o7 Y6 m
- // 数字,有默认值
' \6 r, I: ^& }; ]$ ?- G( j - propD: {
4 V7 x6 c# X4 o) P0 v7 I5 D - type: Number,; s* t+ t$ T3 p ]! @7 f
- default: 100
( V; r8 c, Q" m$ V( Z h: o: o - },
9 Y/ }" P" w: o( K1 a# H - // 数组/对象的默认值应当由一个工厂函数返回
+ R6 Z+ G. _8 C* t) r' Z% T - propE: {
6 u/ X% l T3 q# Q! y4 M7 I - type: Object,( \) h$ K( Y) Q4 {
- default: function () {
1 z5 u" n2 [! t8 l! C3 y* ^$ c - return { message: 'hello' }. _" z4 D W9 {7 W; j5 g
- }
5 r$ o0 u) s% F6 s& P1 ^ - },6 g- A$ |7 Z2 y
- // 自定义验证函数9 P: b" o# J! |$ l
- propF: {& V" f( V O: `3 e4 f- _. |" S
- validator: function (value) {
9 |+ f" h, G$ K6 g8 J8 F! X - return value > 10
& C5 q. E$ t( O* \6 Q7 G$ H4 Z4 ? - }1 A; A; U$ k/ ~; ^, ^
- }
+ ~) t$ [$ p4 @1 m9 J - }3 e0 b+ t" V3 K
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array4 ]2 I2 x1 I# x+ T
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件9 N/ |1 g( F6 P/ w- H# g3 P7 |
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例& j( C$ H& \/ L8 a8 a
- <div id="app">
2 R' V3 V+ s F) b4 p! J - <div id="counter-event-example">
) N1 {* A1 O% @ - <p>{{ total }}</p>& h: E& D, U+ k
- <button-counter v-on:increment="incrementTotal"></button-counter>+ x# A' U2 M1 u, P6 g; u7 a& I
- <button-counter v-on:increment="incrementTotal"></button-counter>+ x8 B. Z8 H0 z5 S. m4 l$ [& P
- </div>
: h" g( T5 ] Q! ~- J+ ^ - </div>
1 E, r! z4 _9 _' A+ u - 1 I1 \1 h$ j* R& Z' X" B
- <script>$ ?. X( D3 r$ E( A+ F, u' x8 t0 S
- Vue.component('button-counter', {7 B' q5 |5 A% h0 E/ G
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
/ C% e. \8 A0 [' f. E. s& V - data: function () {" m. a& N0 J; c7 ^6 E
- return {9 R- t* o# c |8 l% ?! Z4 d8 B- [
- counter: 0$ I# ^1 L9 W& R
- }( m# I2 e- M! @" I% ?
- },
( a3 J: V8 g- H8 H+ _6 R - methods: {' e+ W# F$ v/ a0 {/ u$ v$ O
- incrementHandler: function () {) D# |1 E7 B& ~$ w' O; b: g. ]
- this.counter += 1* `" Z* K# M) I$ L
- this.$emit('increment')
& G$ K) o) K0 b - }
2 Z% P3 l( e, G5 A) X7 C6 D - },, N2 o+ G9 u: ]! N: Y# f
- })% f* l q$ S, S, I$ W, N/ J
- new Vue({
H5 q, X. C. p - el: '#counter-event-example',) K! m4 @% b1 M: w# ^4 e6 j! z* V
- data: {! E% _6 h- J5 m6 R2 f. Y5 l X
- total: 05 D9 B: @: A* e2 S) n
- },( K2 K( C% |- T z+ t( z! g) H3 i- D- O
- methods: {
- i0 ]+ O; L' C4 D/ n - incrementTotal: function () {
9 f4 W+ f' k4 T7 ~ - this.total += 19 T6 V# k3 q) T: d+ z; n
- }
6 Q9 @0 S- u1 R5 E& L - }
% Y$ t+ j: i4 U% V# b( O7 f - }), T6 I2 A3 @+ w0 G9 i9 A
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册9 I; S% [" O3 q! w! a6 ~) Z- x
- Vue.component('child', {. P( ]8 R5 p a: c
- // 声明 props X" `1 @# j6 s' R; @ n( I
- props: ['message'],
1 _3 {# j9 `. R- X0 ^6 @* J5 x) Y3 k - // 同样也可以在 vm 实例中像 "this.message" 这样使用# I5 \8 K# c+ x/ ~
- template: '<span>{{ message }}</span>'
6 M* Q! K q8 @' ^$ V - })
$ _! f0 S0 Q7 X: C$ L& t! f" V1 n! R - // 创建根实例; S% k0 }$ U0 T7 c/ m' ]
- new Vue({
/ k& h' B6 G; K/ ? - el: '#app',0 B$ o j' t% I" Q) R' u1 h
- data:{
- \5 y, Z9 Q R9 d; } - message:"hello",- M7 G( w+ j) S0 u$ {
- }
1 i5 \5 k6 T; K g- q) ~9 H - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {% j4 s5 v b A4 e. `# d
- incrementHandler: function (v) {
1 U8 _( W/ H" C$ A1 } - if(v==1){$ r- ]/ j# N! S2 A' Z. B) M
- this.counter -= 1
& \! Z! {: P7 A+ I/ [( z C8 v - this.$emit('increment',[1])) u' I/ O5 {# r; ]1 Z$ ?9 b/ f3 e
- }else{
0 V c8 G2 G. j# c1 O. o( B8 _' X - this.counter += 1
6 A2 n: f5 x- U/ _/ L - this.$emit('increment',[2])
7 a* M9 F# ?; K+ X4 q! e3 B - }
' a4 H# o }0 h" v - }
: d8 n* b- E u% C - }
复制代码 0 D3 P! i: S8 W- X
0 v' u. L+ B/ O/ b |