|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它: $ z+ D- l( l: w0 O) d6 F+ e" G
- <div id="app">
7 @( X& _2 c6 x& \4 O8 ~ - <runoob></runoob>$ T1 c/ m( k% P* [+ C/ T
- </div>, Z4 ?, I9 W! ]& H. ]( A
- ( `) B5 V) M- {6 X3 b
- <script>$ w z- V; k4 C& V& l4 {. q
- // 注册) P% Z2 Z" G1 P3 Y/ `; y9 n
- Vue.component('runoob', {1 S6 I' X2 o6 P" Z4 o' F0 j) H
- template: '<h1>自定义组件!</h1>'
; s/ g5 n ~9 o0 [, R3 _ - })
- V8 @8 E6 w# ~% c - // 创建根实例8 o7 R* t0 Y1 F. B d# R* Q
- new Vue({
/ V, k! q) I7 v. D0 X/ J9 r; m% ~ - el: '#app'
' y+ L8 N* ^. U; ]" r6 ~ - }), y* l9 ^! y( F# T- X
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它:
) z* c5 b1 n! C- <div id="app">9 @: c! } e! K/ K4 C: d
- <runoob></runoob>
6 R" o0 P0 v+ o" E: u5 ]% } - </div>
# c) [: |& R0 q) R d3 l& T - : K8 F5 u" P; m4 Q! M( l
- <script>4 g( d, ]0 Z7 V& e
- var Child = {/ m' ^8 [+ Q+ O& |
- template: '<h1>自定义组件!</h1>'6 g# {( p2 N( l& ~9 Z3 `
- }
$ Z: o) {; i9 K+ @" ^* G& M: U - , ]% d. M: |& R! E9 O9 d" [
- // 创建根实例
h! [* ~; f" v d4 h4 [; W3 ]! T - new Vue({
( c, s1 d' F R - el: '#app',
1 z9 ^ V: H1 L. v2 p8 s - components: {7 a. y- Y# U) v! l0 \! O
- // <runoob> 将只在父模板可用! M% _0 I& ?. W. Y
- 'runoob': Child
5 o. M8 c( }1 ^+ c/ r S! b* N - }
6 b! ^$ y9 I4 G" n6 h - })" ^- g: o' ^. L' j
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例/ g0 C7 u% T$ I) }
- <div id="app">; h [: ~+ y @9 G0 t
- <child message="hello!"></child>
. q! j3 T3 g" q t d' C - </div>
( I% Y m. R7 M3 u" P8 n+ [" P+ V2 u - 8 Y! h/ E1 Q3 ^( Q" Z. o/ K
- <script>: a d; E+ T/ |! M
- // 注册
2 S7 ~2 X! N0 E1 d - Vue.component('child', {" a7 O4 [2 f9 P* y+ m' \* L! v" N
- // 声明 props
! j3 D+ W1 H h8 |2 l/ L - props: ['message'],
$ D* T3 H! V k! K - // 同样也可以在 vm 实例中像 "this.message" 这样使用4 C# ^: `8 B+ T; O8 k
- template: '<span>{{ message }}</span>'
$ [# h. y0 E# ] - })# V9 t+ @. X. T6 ^* t; M
- // 创建根实例; r. r* ]& a: T' B( z( O5 b0 p! O
- new Vue({( u5 f$ T) v# H5 A) | e5 C; {& r
- el: '#app'+ I* u& w/ | H; _3 M* z
- }) o9 N9 ?0 n& y' D# h
- </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
/ O) ]! X% n j$ D- <div id="app">
' r) g k' F6 d. i1 z& q - <div>( [' U, D" c7 u5 E( U+ e
- <input v-model="parentMsg">
# x; I( J& |- @+ R' Z: f3 [ _ - <br>* p* J* Z0 ?! L! N5 E
- <child v-bind:message="parentMsg"></child>
1 C3 R: R+ i+ J3 }5 p; \ - </div>' y U; ]. n) S+ W
- </div>
3 m" s% a! P% E' N1 ?+ H - 4 P& ^" b0 {9 f
- <script>
# F) Z8 V: a; M+ } - // 注册
8 m! B, L, }: B) i- [; Q - Vue.component('child', {3 O! K% I& j: \' }9 n' ~
- // 声明 props8 A4 C1 [4 H1 ^) v- {
- props: ['message'],
( L% n- F+ G/ Z4 T' V7 g - // 同样也可以在 vm 实例中像 "this.message" 这样使用
8 U" U' p! {- P; h9 t - template: '<span>{{ message }}</span>'
1 ^; `! e: q1 g8 p' t3 N5 e$ M/ [ - })
9 z9 @0 x& k2 Q - // 创建根实例
3 M* o- ~% C4 i/ S; w5 O3 m - new Vue({6 c/ v9 D1 U1 L& [4 a# @, K i
- el: '#app'," M. T+ b5 X3 W
- data: {+ U( c+ \- T, @6 }0 z
- parentMsg: '父组件内容'
3 m% p0 d8 p# ?4 u# X8 W - }. F$ u5 j4 E/ r; M( R( t
- })
9 J- ]0 [) \& ~4 k* Y% q2 O; c - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例: U( u. L! W5 q8 t' y5 ]9 L. D
- <div id="app">/ H( k2 j( G1 m& h
- <ol>/ F" ^8 b; J; m" A: {
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>/ ?5 p: S. G3 M. `* d
- </ol># v& K1 p1 }( u1 R
- </div>
: h4 P! b1 w: p -
! d# v. w1 v: |6 J - <script>0 H# M2 b) K- _5 g; x4 Y( y& _
- Vue.component('todo-item', {% C6 F5 r* I/ \9 C4 O, Z
- props: ['todo'], }6 d+ {& i1 _* G
- template: '<li>{{ todo.text }}</li>'
5 k* Z& A4 d# }1 N5 @* T; ~2 w - }); O, \6 B. J# }4 a9 l' h/ q" E
- new Vue({
0 d' g* X1 w5 o: C, z - el: '#app',! S O( g; V2 Y4 }% j6 M) @
- data: {
/ F0 h) l9 b6 d2 h' V' L' ~. W# N - sites: [
* @- O7 w- s& |( f& { - { text: 'Runoob' },2 ^7 I! D( G4 c- ]2 U' `
- { text: 'Google' },
9 _9 E7 n: D. E - { text: 'Taobao' }0 j% y% L4 A' a2 Y( |/ E- o
- ]6 J& N; n3 y. ~) v& N8 Z: I
- }: S K6 \5 x3 X. R9 m
- })9 r7 g- Q V% I& |2 t
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
6 Q9 }5 D3 L" d( S - props: {5 Z6 a N! z& U d0 I% G% z, F
- // 基础类型检测 (`null` 意思是任何类型都可以)5 s; H" J" C9 m9 `7 p- P
- propA: Number,
1 ~# F7 l: a& N1 F - // 多种类型( P# f. L' m" d
- propB: [String, Number],
* r, t( f* m, b5 y - // 必传且是字符串* H6 B+ z4 X( \
- propC: {
8 |4 H8 K( t1 I! O - type: String,
^7 u: M5 G) v2 ^ - required: true5 Z7 d& Z' V+ M1 I+ \
- },5 x4 o1 [! }6 ^1 S' I
- // 数字,有默认值' J7 z- Q6 S: n: v
- propD: {- m! L+ g& a1 F6 R; [
- type: Number,0 ^8 j1 k) n ]$ D
- default: 100 j9 r4 \) R; X. {& d8 u0 \
- },
6 q. |- q5 Q7 V, w5 H& P - // 数组/对象的默认值应当由一个工厂函数返回, L6 Q2 A; u, b" U7 ^* y. q* ]7 b, Z7 B
- propE: {
( F$ Z1 P1 s) Q5 D - type: Object," h2 {1 _; ^5 v E
- default: function () {
- A7 E3 k! ~9 x4 V - return { message: 'hello' }
5 {! B+ M' ]# r* M( u6 q% E4 D5 m - }# Q0 O$ R5 |! [4 N. M& w
- },) ?' K! a/ ~* N. W" l, }
- // 自定义验证函数! h7 d# G5 g" f
- propF: {
1 Z; D+ ~7 `/ E# a - validator: function (value) {& [& u) D/ F9 ]. m, G: T* C5 d7 |" c
- return value > 10# n' e7 J0 n5 o; a1 W
- }
; e0 d1 R# s! w; }* ~; k - }
, N. K5 |5 @3 R( j$ | - }7 X# c/ l9 E7 v2 [- B/ Q
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
7 u: j7 d- o0 g4 w$ \
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
+ o8 K8 X* e! Y" Q3 u$ \$ y* e% I2 `5 z
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例: `+ a- A: Y8 F: g3 E* _# x
- <div id="app">
( ^6 i3 N3 x, [2 B' \ - <div id="counter-event-example">1 r% f# E, Q2 ]- W! k4 O
- <p>{{ total }}</p>
* x7 E8 @7 a+ N9 a0 j - <button-counter v-on:increment="incrementTotal"></button-counter>
# F" K" M3 ~9 E! ?9 G { - <button-counter v-on:increment="incrementTotal"></button-counter>
8 B8 [& g: V% m( A( k - </div>
. U+ p! Z$ l+ B - </div>
2 @/ o8 e5 g; g& V. ~ - , t" [4 x3 W6 `: }3 C1 X
- <script>7 M8 T9 ?. C' q& i
- Vue.component('button-counter', {
9 G3 f- m+ W8 O, f/ a+ P2 ~( e - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',* h+ P8 W9 ]" I" E0 i
- data: function () {& |6 {% D; v3 w$ x
- return {
9 t8 j; g& X8 ?# B1 X9 w! j - counter: 0
) L' N0 g- S p - }
) h, F' A a, K! U5 L+ N( I; v - },
: ^1 C' f+ ~" f - methods: {) W& I0 N5 U) g
- incrementHandler: function () {! T2 e; s' p( B& A
- this.counter += 1
' e& R+ E* b( X) S9 v - this.$emit('increment')* t2 B; R w8 O$ c( _
- }
+ a2 g' {/ M) B) H - },7 o0 u Z5 W9 Z; s
- })
5 L5 Z4 d1 l- ~: R - new Vue({+ a, f& f( y$ w7 S5 V% { r
- el: '#counter-event-example',
/ Z# ?, {. `1 O2 L! q4 T( A - data: {- A# x# V# Z$ Y& j% N
- total: 08 Z) x/ ^* _, @
- },% q/ J8 z1 u4 ~% o
- methods: {7 q3 k) ]- d- Z, o
- incrementTotal: function () {
+ a2 m0 N& ~9 ]8 O( \1 N( A7 D - this.total += 1
9 Z3 d3 \/ G. y - }% w3 T/ |5 m: ~8 Z: c6 V
- }
4 S" a- S; c- _( H6 M+ p7 p' d - })! C$ v3 [7 _# R. T6 E
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
1 K+ c$ u7 n" @* E" L; w* `4 H, U - Vue.component('child', {! @. ^0 `8 R; I
- // 声明 props
" G( P6 m7 a% D$ Q( A# U1 y5 y: k - props: ['message'],
2 O& E& \0 O4 Q - // 同样也可以在 vm 实例中像 "this.message" 这样使用% h& T" D! P |( n
- template: '<span>{{ message }}</span>' Z" v5 s& q9 A$ D+ `/ ]9 W
- }): i) f" U2 S0 V% [0 {+ Z% ?* z
- // 创建根实例1 Z, k+ w" K& T4 K( y8 T$ e
- new Vue({* F+ j: k! W B l
- el: '#app',
) d6 i3 @9 v/ k' I% o7 H - data:{- l3 Q4 n3 [8 N5 m1 |
- message:"hello",
, M! ^4 A- q0 {4 p3 E - }
% ^- j/ Q2 E$ x7 R8 [& K - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {% U5 f$ Y+ g1 p) R8 D h* I/ ~! H
- incrementHandler: function (v) {
9 o @5 |6 A" @ - if(v==1){7 n' t9 p2 V& T% Q0 h5 q; p% T
- this.counter -= 1, I. O% u2 H7 ^6 C" k) G1 v& K z
- this.$emit('increment',[1])
# {8 M) l$ B( Q/ R, k/ d0 c - }else{9 ]9 ?7 _: v1 E% ?& A
- this.counter += 1
5 E; A' l- b: h$ u! }8 | - this.$emit('increment',[2])
1 v" S' w: F I! n - }7 l0 F; }: Z4 e# R8 V0 Z
- }$ L ^7 Y) S9 _& }! Q; n
- }
复制代码
7 x8 \( C8 P4 `7 W1 M8 y
+ n, y ?* j7 l. x" @ |