|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
5 s+ n5 X( n" u* j, X- <div id="app">/ R' s$ w9 f7 q4 p
- <runoob></runoob>; R0 H0 c5 E% T6 p
- </div>+ G u; V- s' ~0 W% j8 R
- 1 O: w: Y$ e Q. O. t/ }
- <script>
; D* {0 \& E$ h - // 注册
5 \- j) P) l1 C, [: z. h7 W2 a5 L - Vue.component('runoob', { ~1 V, A9 N: m6 G: r
- template: '<h1>自定义组件!</h1>'
# J* Q" O& z1 R3 C( @% _: h - })
7 y: V! U& S% s0 m' J - // 创建根实例6 N9 J# y5 j; u P P' _
- new Vue({
1 u, Z, f6 ~" X! U - el: '#app': m9 D* c! J% a5 y* u
- })) E' q7 q* y, W9 d( Y
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它:
. W5 k. P0 ?1 r: ?% W+ ~+ K- <div id="app">
: d; l/ t7 C" e' j - <runoob></runoob>5 x7 N& V! \8 P7 k
- </div>
) H4 Q8 l7 z% D - : f7 z4 p+ k1 u1 j7 L+ G* _/ c2 _6 ]$ I
- <script>" u: v; j5 e0 O3 W
- var Child = {
- P5 ]" B" d8 ]3 |$ X6 [8 E - template: '<h1>自定义组件!</h1>'; \% W( g i4 V4 @1 @$ T" Y
- }1 H; T# D n/ d9 q3 f U* ~
-
j" k d! H6 d/ E, | - // 创建根实例6 ?) j2 w; n* ]
- new Vue({
8 {' h. A% B$ ]% \8 G - el: '#app',
$ s6 y1 t# T& y9 n% [& s5 ?. \+ w - components: {5 W' ?0 k3 l7 {. w
- // <runoob> 将只在父模板可用
8 s) ?* m' f5 k6 p o9 E - 'runoob': Child
, x1 C3 P: M: p - }
! O: h" y- L0 _7 f6 f: r - })
3 `. \: j& ~) Y* k# M! q - </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例) P# q& Q% m# j0 Q9 R' J# L
- <div id="app">0 N( Z) A5 V$ O9 d& ^/ g
- <child message="hello!"></child>" S5 S* m% h7 J# K
- </div>
( }" C9 ^% d G+ Z - ' k3 n+ T1 _% Q! K% Y: K' o
- <script>/ v& y/ S& ?4 N& E0 X L, ]
- // 注册$ H" M8 D& q, d% i- N% a; f
- Vue.component('child', {2 R. w% R. `; W1 {7 U
- // 声明 props
8 @7 `3 G" x) |8 Y - props: ['message'],
. q* P( X& S5 G Y2 |* _ - // 同样也可以在 vm 实例中像 "this.message" 这样使用
5 N# m' b1 q* ^9 A; H/ d) A7 h - template: '<span>{{ message }}</span>'
% b% u/ t- }: L G% G [ - })2 Z$ {, n4 \* P" K
- // 创建根实例1 L# r* P6 M/ \" z/ Z
- new Vue({, D, [& }4 x, p- Y6 M- X0 b+ r
- el: '#app': E/ R' g! Z1 `3 o: p
- })
+ i# t! c( [' u: y' v: ~; n# ~( d1 m - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
: @& \' G6 F" G; v8 N C8 C+ Y- <div id="app">- o; Q( b9 R" P. z
- <div>
' F. h7 q S7 [8 O7 _; ^ - <input v-model="parentMsg">! w1 T8 z4 |1 a0 m8 Q! B
- <br>, Q! r x2 l0 x6 w* ^' h* P3 | p
- <child v-bind:message="parentMsg"></child>
* r u' o& H* x+ g - </div>, H( l( ?6 `$ l) }4 E
- </div>
5 n( c: F3 b U% L1 o -
+ X2 m6 m0 N/ m - <script>
; [) a0 l8 `/ m% k! P, _6 x6 D - // 注册, r6 @4 u& d: z7 w
- Vue.component('child', {# @$ H# A) O4 M" u
- // 声明 props: [7 r! l+ c3 U& E- H9 Q
- props: ['message'],
% \6 x0 \3 s& Q$ D - // 同样也可以在 vm 实例中像 "this.message" 这样使用4 v3 c7 \/ ~: Z F' V6 R7 q
- template: '<span>{{ message }}</span>'# F6 L3 T" \4 E) T
- })
, }& \, L, R' c; C# S$ h2 U8 J. m - // 创建根实例* G8 {+ f* ?. @
- new Vue({( {$ @. R8 @8 I9 h( D: z
- el: '#app',8 C& g5 S- B; L1 s9 ?# m2 a9 I$ r% W
- data: {
1 P9 z7 ? ?0 c - parentMsg: '父组件内容'
# }9 A7 V0 A" D - }& V: V6 G b% Q+ c
- })
- ^- _+ z5 C; t0 @+ f4 h, r - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例# ?1 e: _! @) H! @9 t1 X
- <div id="app">
* p( r, n$ h9 }7 e - <ol>/ k G/ X/ E4 |# X, z) q
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>* Q5 J& @* ^+ V L0 B9 }
- </ol>
; g- P! `3 @. e( M& A. Y - </div> e* t1 M, d" a: }2 k+ H
- 9 X1 g, \2 G/ ~3 D% i) W
- <script>$ P7 p$ F& x1 q; L
- Vue.component('todo-item', {
' H; I* l1 R4 x1 X - props: ['todo'],. F; ~! P/ r0 T* H' w: ~! ~
- template: '<li>{{ todo.text }}</li>'
9 v3 [& ]. }# N - })1 D$ z9 l4 h/ [$ i4 W
- new Vue({
8 ?: [& r- {0 d7 `6 a$ J - el: '#app',8 A8 m5 n) u# Z( J- A
- data: {; C! A# f1 n) x. X
- sites: [) M7 o% u. @- R$ ^# ?' U$ h
- { text: 'Runoob' },5 ?3 n" h! |$ _( g, `7 B6 [* [. F
- { text: 'Google' },1 Q+ Q. K: C5 Y
- { text: 'Taobao' }
1 |, L3 n* x+ U - ]
! S, }% S3 r, |8 d- i% e" ?' E - }
1 d9 W" c+ Z; B! R* l$ g& K - })" X7 ~7 B* H. \ u" `
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {4 {- v0 ~; W, q* Q( p5 z5 H
- props: {6 @; I- W$ `# a$ W; |# q, z
- // 基础类型检测 (`null` 意思是任何类型都可以)$ @! j6 T& \: ^2 o. h
- propA: Number,# t3 L+ p7 `; y6 w7 n- H
- // 多种类型
; U! O; W; q* ~$ ?' l - propB: [String, Number],4 p5 n+ a. t7 J |4 q3 S' V$ ?3 P
- // 必传且是字符串+ H1 K5 ~3 ^; W2 d7 F
- propC: {
; }# d: s2 F: B1 w8 o - type: String,
7 ` A+ i' w3 \6 h) Y - required: true9 g3 L8 M! v8 v5 Y
- },8 l5 \2 M9 |9 J0 K1 w# h
- // 数字,有默认值; b9 m% V( l! B( M
- propD: {: }" g/ } X8 e: p! h: r5 p
- type: Number,/ F+ _) k( }% e
- default: 100
; @: G' j R( {* ^# A0 r' w8 A+ V - },
& T6 E1 k/ w. E3 ^ - // 数组/对象的默认值应当由一个工厂函数返回4 R. a! N" ?+ g5 P) g$ k5 k `! q( I
- propE: {( `2 |% R: j1 k8 x0 P
- type: Object,
1 s+ J, O; f& |$ ~ - default: function () {
1 R3 ^1 Y; h' X" q - return { message: 'hello' }
2 W! n8 f: f" ]: m - }5 b! T$ r. o+ u) M9 t) {9 ~) u
- },
0 Y1 r" V9 x7 N! C: e( j* E( y# ~ - // 自定义验证函数
% A# f5 q& [' }$ t2 v2 \ - propF: {
) a+ n; s; V+ C5 g* u - validator: function (value) {
& |% G- [+ P% H5 v$ S - return value > 10# L: e+ F( C5 [, L
- }
( V G6 ]5 P1 M1 P4 [; p - }
: M- M/ @8 ^/ a' f; b5 i3 ~ - }
" y- r! \, \0 A, [2 n! y - })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
; k. l# c! x4 O9 e& G- P
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
* F7 e; u( V: b: h$ ^
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例
9 Q _1 d9 V: j2 R% m' ~+ b- <div id="app">
* W0 T' B+ j9 S4 {5 |: Z. x. J - <div id="counter-event-example">3 F* f2 U5 L* U: x, y' Y
- <p>{{ total }}</p>4 Y6 w8 [, a$ w
- <button-counter v-on:increment="incrementTotal"></button-counter>0 A) l4 @6 B( W' e( p
- <button-counter v-on:increment="incrementTotal"></button-counter>0 t5 Q/ A$ f% Q0 s; K9 u6 A
- </div>
+ U! @: Y7 x4 `2 A - </div>- f1 n+ e, x3 R( g- W1 k
- ! t1 L4 Q4 _5 D. @; r" q
- <script>
: ?! V1 \% w; A9 w+ n - Vue.component('button-counter', {
$ P, Q7 Z) w1 M; w4 r - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
9 V" W \& g% I' r# N# S. ~ - data: function () {
2 i$ y: R9 k {/ Q. }" B. _9 G - return {
% I% m6 t# e* J - counter: 0
+ G- z* B+ Q2 q# G* r: D9 H7 ~" K - }3 L" U9 f& p4 D1 v& @1 R3 t' X
- },/ R3 q2 Z1 _+ l9 K8 h: {& K
- methods: {
9 v. Y3 h6 A3 o9 d/ K5 ` - incrementHandler: function () {' q1 E/ s; N" }# h! T
- this.counter += 1% R7 F+ b5 k' ?/ t6 V
- this.$emit('increment')4 N n! e- n' n0 j3 K
- }1 }* b, [+ P- c$ X; n) g1 \8 y: y
- },
) z: @; ]* [9 Y) G4 f% `0 j - })3 z* ~: U0 K" s F1 K0 T
- new Vue({
/ A5 O2 t% }9 b: P/ a - el: '#counter-event-example',
+ t5 [3 @9 K8 {+ [3 I: X - data: {
+ S! ]1 j6 s" J- G6 `7 c - total: 00 f, e+ a5 T) ^2 K5 J" D
- },
; n) t' n0 P: L m/ S - methods: {8 T( u& U+ Q) k' A( y. X5 y
- incrementTotal: function () {
- R1 C, O- \) r- v, r2 C% g - this.total += 1
0 V" n6 t" P8 L. a8 s% Z - }
2 Q+ _& L* O3 o0 J% M - }! [+ G2 _0 I% S7 J' c2 u8 m1 Y: c
- })
4 @# K$ {6 b/ A6 ?1 o - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册$ a' e% H2 b5 B" L
- Vue.component('child', {! B* \1 s7 N8 r" H# [5 Y
- // 声明 props2 Y1 Z2 V( m, ]/ K. H* w9 \
- props: ['message'],
7 v* I* [/ H+ n$ T3 l - // 同样也可以在 vm 实例中像 "this.message" 这样使用
! p7 }. r" H* D: d% h - template: '<span>{{ message }}</span>'" {" g* U# X6 K' K% x
- })
' b4 g" N* O! ]' J2 |( i6 J6 Z - // 创建根实例+ \/ Y( g/ g9 `# S( T% l. |% [
- new Vue({
. o# H: O2 ^2 U; C! g# S - el: '#app',1 ~. d3 F5 P$ L5 n/ C
- data:{
0 j$ z. O4 y9 a' p/ c - message:"hello",
! I: p" O. C" s - }
6 y& y0 r( {4 ^. p3 U& P6 D, T0 [4 o - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {; s% Q B9 J" [
- incrementHandler: function (v) {8 n4 D* [, `' I3 y) j! U7 H' c
- if(v==1){
' f/ J" H* ^# G - this.counter -= 1
( u! m+ u# I8 n+ q3 F - this.$emit('increment',[1])
0 q6 x8 a& w$ p7 y% W4 M' Y/ D+ b9 A4 a - }else{
) ^6 M) }6 l) K8 S. `6 V+ X7 d - this.counter += 18 g6 `' o6 j9 v6 `
- this.$emit('increment',[2])
* L8 k1 ^6 X! E. J( A, I a - }2 j& z2 U( x, y- h
- }
$ V8 w" [$ |/ ]6 x - }
复制代码
$ b$ v/ G9 h4 g8 [8 U
: G6 V4 E, Y7 z" A1 {/ t, X |