|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
; P U) L ?% ]3 z4 b" w- <div id="app">' [$ W- c8 f) {5 r4 z h9 N- w% C
- <runoob></runoob>
8 Q. t* M- K- O3 n4 z- O) T+ [ - </div>
; G. e1 y8 y1 c% z5 V -
8 s& G3 x& {8 B* ] - <script>
( e) v1 v9 s6 o+ B3 v. J - // 注册
' [/ O3 _) _- f - Vue.component('runoob', {
- S& O' r# o" \( [6 }2 y$ n - template: '<h1>自定义组件!</h1>'& h; y! a! W0 { t; [1 k* D
- })
. |$ ` b+ F( ]: V7 E9 ~0 i - // 创建根实例
4 |. f: T; T* ?+ k - new Vue({
X! v" z; e' f e# r - el: '#app'
! w5 x% P$ t: r# n. y3 d - })
9 |; C' V* ~% G. Q - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: ! K1 O: m# D% \7 y6 e* s
- <div id="app">
7 ]/ k C7 P5 k' z# v - <runoob></runoob>
1 l0 j, U' W% _: \& d0 K3 p - </div>
9 g: s( P& W+ D& \8 o4 Z' O, @- c" n -
* t3 r7 b/ E4 @; W6 R2 }! _ - <script>
& y v0 I% T! j1 m - var Child = {0 e* `1 z, I- O, w0 n7 X
- template: '<h1>自定义组件!</h1>'
0 ?+ k* k3 J" u$ J6 B) z - }9 T, [& U9 L& S' `: k e
- ( ^* Y1 X5 A6 e$ j1 b3 g
- // 创建根实例7 [& c& m2 x% e' u) M
- new Vue({7 q" w+ O5 A P* [. s* U
- el: '#app',
1 x4 Q/ K i" X/ A3 N - components: {
* z% U6 W# Q; d( m - // <runoob> 将只在父模板可用
0 ` B: t4 y4 y1 h# | - 'runoob': Child
1 H; g, H" b9 m6 E - }
1 F) J7 G0 H9 ~ - }). [1 z$ p; u9 K% {7 V$ {
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例
! j4 M' Z6 \* O ^( R( z- <div id="app">: C" V2 |6 P1 H
- <child message="hello!"></child>
1 Q" p0 Q# V; O6 h7 Z0 ^ - </div>/ Y1 L4 s* o# m U2 k0 j+ c+ R' h
-
; z! b) P j" r2 n1 J - <script>% v6 f D& ]3 ]! n }- M8 A
- // 注册$ A/ W& C3 b" T6 ?
- Vue.component('child', {
% {6 ^/ T4 f/ t - // 声明 props ]: q% ^( S ]
- props: ['message'],
' Z- d( m$ Z; w3 M5 K - // 同样也可以在 vm 实例中像 "this.message" 这样使用
( \! q( T* F1 |$ w- X. y1 d - template: '<span>{{ message }}</span>'1 A3 H2 M" \' F
- })
9 M$ T+ s J7 W) Y3 p4 B) }0 g - // 创建根实例- [# |! P1 d' B5 k/ ^0 C$ g
- new Vue({7 G n* a( z$ ~8 Y6 P
- el: '#app'
, Y! e6 D/ {* b& ~" H/ J$ A - })
. U9 `8 O: {8 e - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
" a9 c! l5 U) F$ S- <div id="app">
5 C0 z; ?# k6 F) D - <div>( Q( h( g0 @2 J5 Y1 L
- <input v-model="parentMsg">( F0 K0 ~7 e+ n3 n
- <br>/ u$ o; K, X- W, S4 H
- <child v-bind:message="parentMsg"></child>
$ J0 f" L7 }4 k% E1 m - </div>: T1 J' p5 O* [; A' ^3 ]
- </div>
r- H8 u- X- Q7 w! z+ ^ - ) {3 v7 `: z( B! z
- <script>8 r- f) D" h0 f5 I4 I1 X
- // 注册( N) F1 Y5 ]6 Z0 ?: X
- Vue.component('child', {
/ [; U* W/ _. _1 O: C$ N( h/ G - // 声明 props& n5 s/ \$ W, l5 I! k
- props: ['message'],
% i+ q; n* s7 o9 J1 Y$ h; g - // 同样也可以在 vm 实例中像 "this.message" 这样使用' _ M. Z7 f2 |+ D( U
- template: '<span>{{ message }}</span>'
7 j4 }/ o5 s6 u! {7 B - })9 \7 j# b9 F6 @1 k. k# [8 H
- // 创建根实例8 Z& r' a/ L: X2 v" ]5 E! `
- new Vue({; e [* R8 K% N
- el: '#app',. M% c* d, m7 F" \( { W# O# m
- data: {
/ s1 T8 D: e- s, B - parentMsg: '父组件内容'
2 J# D. P; y [$ y+ h - }& q7 n; l0 I9 p& w" p
- })
4 L: M! V7 k; v x P - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例8 ~1 Q9 g$ x1 e f( |' r! g1 i
- <div id="app">
1 M3 P; }3 U( T) L; X. Z2 o - <ol>
6 q9 x4 c7 g* W/ C5 a - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>1 F5 B( d% Q' i7 P! _
- </ol>
6 a! c" K u) m- ^, p - </div>
* j0 [% }9 j$ B -
3 K$ @7 t# C" x- H - <script>
- _6 X$ i# l3 ^$ J# o, o: X' P - Vue.component('todo-item', {
8 ~" E/ q& `/ W7 ^) z - props: ['todo'],6 G7 l4 V1 E: [/ }' j( @7 e7 x; g
- template: '<li>{{ todo.text }}</li>': A0 H- C% C! Z
- })5 R) b' \2 D) } F, e% }6 ]( j
- new Vue({ D [9 M( \9 o+ o! I. Z5 Y
- el: '#app',' g: K, \2 p. k5 y- P6 G/ s! l
- data: {; n6 ~( }/ V/ T2 s! V3 O# u
- sites: [
4 X. ?9 s+ R* c& O" ^. W) Z( n' m - { text: 'Runoob' },. N' _" J, ^ y; M
- { text: 'Google' },
) J2 g s, }- }6 h4 v! l* \ - { text: 'Taobao' }
! i0 |+ y& c8 Q9 K1 w: U - ], W; |$ S0 H# z; {+ h! V
- }
; r. V7 H7 e$ r7 o - })
* k x8 G! t1 v4 z/ u - </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
2 \" K& B( @' Z3 O - props: {4 e# ~9 y0 T4 N# K5 }5 |7 s, I/ A
- // 基础类型检测 (`null` 意思是任何类型都可以)
! H5 h$ I7 ^+ k' i2 h - propA: Number,
+ a! A: S( q( j! r1 j& p L2 J - // 多种类型7 |2 s; s' O9 ?$ T. G
- propB: [String, Number],- Q' S: K O& B5 y, h
- // 必传且是字符串
4 t8 f4 Z2 |3 l N - propC: {
1 U; Z% Y& Y% _9 b0 k# o - type: String,: H! l+ P! y/ D
- required: true7 h9 B1 E/ _5 R' ^5 i3 A _
- },
/ u/ ?$ s/ x7 h. k0 N9 E - // 数字,有默认值! b/ k- c$ k4 S$ j9 |0 g& S
- propD: {8 _1 |9 w# y x8 h) F, G s
- type: Number,
! t* I5 }, v0 V# P; O5 `' E6 u - default: 100
9 E( f. t6 u" K% Y! A( p* F) r - },
$ v$ d7 Q& `- Q* D/ z7 z- l( C - // 数组/对象的默认值应当由一个工厂函数返回4 V4 [. W' V3 B5 w7 u
- propE: {
' U) m% m: U8 J: @) A# S S& g$ P - type: Object,
3 n- c( A# D8 h! Z+ `8 D" o+ ] - default: function () { s6 d3 N# U7 t6 t
- return { message: 'hello' }. i7 n5 q+ f: S& l% K, _& e) Q, N
- }& o. v8 K3 y* z' c4 }
- }, q6 O/ @0 V( ^$ Y0 y2 ?4 \2 g( S
- // 自定义验证函数( K* P- A, w9 D9 d: |
- propF: {0 l9 y. c9 ~; {% N9 I9 E
- validator: function (value) {7 I: n* [$ H/ d/ K
- return value > 10
' l$ y+ a2 d; t# d3 o$ o - }9 s/ n d2 k% A
- }+ N& `. _5 k0 J
- }/ v9 r- b; c% C8 j L, n2 G, E
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array# U. D6 o# t, n3 t/ k# E
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
5 |9 O: v3 h' q" a* ~7 E
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例
. Q9 _( `- v5 @- <div id="app">. D. Q) u5 _4 l
- <div id="counter-event-example">% b h" H+ ?) j. K- E
- <p>{{ total }}</p>( J! m" b! w' y i. {8 A
- <button-counter v-on:increment="incrementTotal"></button-counter>
2 i& U7 o8 x/ C4 W9 H* Y* D( g - <button-counter v-on:increment="incrementTotal"></button-counter>0 x% J" h g+ W! r9 N6 O' @7 d
- </div>( x" C q3 i* N. Z3 w; F+ U
- </div>
7 r( |* B! S# W4 e$ G8 s5 S; k -
) z4 n8 a; e, Z - <script>
) h% T/ Y& { ?1 J2 B+ x+ ^# w - Vue.component('button-counter', {+ J0 {4 Y; Y* I' B% {5 q
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>',; @8 E4 K# D. H( B" L. \3 D
- data: function () {. j: e, e: _: P
- return {$ X; R8 B3 N- ]- v5 Q
- counter: 0, \% [9 T6 K4 ?. F; o
- }# g$ c( \( [2 `$ J
- },+ _6 V9 H6 H, {& H0 O4 D% Q0 q* f
- methods: {; w) i0 j/ u$ X* E- W( N6 z5 V
- incrementHandler: function () {
: f2 H) ]3 M* v1 Q$ Z: d - this.counter += 1
- t2 ^1 W. T; p7 z0 u - this.$emit('increment')/ r7 o% [/ k5 x7 a# [; i M
- }8 |" P- E. T P, _+ ~* }
- },
/ H0 R+ D1 x" }8 n* g8 v2 m - })
+ @) L4 M4 W# @' S" S" n3 n - new Vue({0 f- k6 Y) [+ I0 D
- el: '#counter-event-example',+ }6 F2 d4 S, y( g" z
- data: {
0 V9 ?- Z0 i, e9 m - total: 0
t9 O' P+ u: C9 b" C& K+ C - },1 p+ m7 B" T% b8 s0 V
- methods: {& O1 f) B: I* b9 C' E7 f
- incrementTotal: function () {
. o- U" ]! J/ q9 Z3 x& [ - this.total += 1
+ z: _# o' e- F% k1 b" k2 g - }
1 G1 F8 o) `( z - }
/ Y b* J! O8 u" P% G - })& f% y6 ?2 I9 s* K% b
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
* e9 {5 S2 @ l - Vue.component('child', {* y1 k* H) Y& g3 D& f2 c
- // 声明 props- {* z! N/ Z# ]- z
- props: ['message'],. @- @4 e3 w+ f) D; ^" ^1 ]
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
$ U% n! D! J( ?. f/ e; n - template: '<span>{{ message }}</span>' d% _2 L0 l/ [/ o; }2 K
- })
+ P( S! J) L* ^4 a Z* Q! J - // 创建根实例
7 ^, `% o( N& g& m5 \ - new Vue({
& ^1 h, H* L# Y! |' Q) v - el: '#app',/ ~. c7 `/ E! q9 v
- data:{* r* s; g5 @% H. r: j C/ Q
- message:"hello",, }# b! Y; y3 H* y; b- [% p
- }- c3 A- R, f) \, A+ z% f
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {4 Q" C; o. e) L7 \# O4 E& E* r
- incrementHandler: function (v) {3 K" T6 l7 f/ t
- if(v==1){3 w3 Y' a+ Q9 h9 n: s) i4 I
- this.counter -= 10 V' {: Y$ z2 i0 I
- this.$emit('increment',[1])" T* Z1 u9 _3 s2 B1 O3 j
- }else{ c3 q1 J- A/ d1 Q) L$ l
- this.counter += 1
% a/ Q* Q& }, ] - this.$emit('increment',[2])
1 l; W) v/ u2 m9 r - }6 M# [2 B2 E) V0 c, C0 B
- }
$ D- r2 H/ F9 `8 p* d - }
复制代码
1 h% N! O6 N4 \( ^( p X$ T% h, \; [, i1 s
|