组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它: . S' o& c5 [$ c0 C& v, j# ]; e/ D- k
- <div id="app">5 g& f1 U# p3 }$ u& l# b1 ]" f8 l
- <runoob></runoob>8 ^( \+ n1 V3 t* X
- </div>8 M" w- N9 ~0 y! s( h
- # ~3 h5 D+ J2 T3 M
- <script> R7 d, _' u- {9 b$ N" ]
- // 注册
5 g- f! Z' e' U- t3 q6 M* _ - Vue.component('runoob', {
. p/ t& _1 F8 f: f" b - template: '<h1>自定义组件!</h1>'
5 j, F+ G1 Z, S3 P# |1 n - })
8 r0 j& i: ~9 c: _ - // 创建根实例
3 Q2 Y: f; [' K+ q$ G R r - new Vue({/ B/ E Z* y5 u# C) }0 ~6 l( F
- el: '#app'
1 o$ g! @0 i/ d5 I6 u - })
: ], b* W4 J; j# P - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它:
" L8 I, `2 Z5 Y. j" V2 L6 F- <div id="app">
* _; r6 I: O; i. T+ f - <runoob></runoob>% c3 f9 |! f3 }$ c- N
- </div>
& G" @2 t1 |1 i1 z, [% F* c' W - W" }0 q) ^# N
- <script>
6 M; }! X; }9 d" @ D - var Child = {
& [* n$ T( {% I$ A) J# r# F5 u* ` - template: '<h1>自定义组件!</h1>'
4 l; S$ ~, v# i$ R" i - }
+ b% i( B3 T3 ?, k - : Z5 |7 v* |1 X3 w% e
- // 创建根实例
/ I# \0 ]* f7 M X* J/ i - new Vue({
! U1 V4 s2 r6 s. X* a0 f( r - el: '#app',4 W+ M3 j; }4 f. X& X
- components: {
; V! o0 e2 N( A$ j2 U - // <runoob> 将只在父模板可用
2 T+ e( [7 }* q- X2 a# k9 W$ Y2 z - 'runoob': Child+ k0 p' Z* T) }$ ?' k
- }
% O- @& }. r" l4 d1 r, j - })
% F; C" T6 Y- N+ b0 e; [ - </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例
# t1 f9 C/ S) u+ k+ J- <div id="app">( u" E8 `3 Q, s" I$ n; }1 u
- <child message="hello!"></child>
% k: ^ O. u) ]0 p8 X0 a - </div>2 [3 d Y. @0 \, A1 ^
-
- _/ q. ?) u; g) c - <script>
4 h- |' S6 s$ A9 ?- h: z( p - // 注册
; x2 w6 V" [ o3 U - Vue.component('child', {
1 E( H, d% E/ l - // 声明 props, U, ?+ J2 V; Q9 p. |9 D1 V T
- props: ['message'],6 G: s+ ]/ W0 R/ |0 ]# ]
- // 同样也可以在 vm 实例中像 "this.message" 这样使用0 n' ]7 @& `; j) }$ v4 ^
- template: '<span>{{ message }}</span>'
6 _/ g" F% r/ h* O0 {* L4 V3 R6 y - })
& K* N8 P4 O% F' s1 d9 q - // 创建根实例! L7 W$ `0 d+ B# I1 G- u$ J" ^
- new Vue({
p' f2 a8 R& O1 m1 n - el: '#app'
, G' h0 ]8 I {; |' w- ? - })4 j4 j9 q K# G, M
- </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例: O7 ~, y9 \: v/ k' q+ V* K
- <div id="app">
6 n& X, d8 g/ | - <div>
4 x$ ~& Y+ X" I2 P8 O - <input v-model="parentMsg">' P: Z! O: v7 d4 l4 h4 n/ g4 w6 O
- <br>5 `3 [2 U0 X& T2 Q# h& g/ a4 B( G
- <child v-bind:message="parentMsg"></child>
: U1 L" ^/ a' R5 e. P% K5 ^ - </div>
$ B& m" w8 O; _' `! u - </div>) p9 Z9 j' @/ u9 `5 n
-
$ \: U/ A4 @! R) M) Z% g5 p& \ - <script>; J Q: n2 E" Y: O
- // 注册) q* h2 `$ \) N9 Z* y$ ^
- Vue.component('child', {0 |- p: o2 M1 p7 I# c0 R1 X/ u
- // 声明 props
( ^6 M# [9 }# h5 i# @ - props: ['message'],! ` W0 F. B& K# R# N
- // 同样也可以在 vm 实例中像 "this.message" 这样使用 n7 A( t4 r7 u9 L. n2 @+ V# r
- template: '<span>{{ message }}</span>'
- q' E7 x9 K- l - })- _- S1 X: f5 @( z; j6 z& i
- // 创建根实例
# A' ^, z' z2 I7 | - new Vue({
; j" r3 z- Y5 }: D - el: '#app',. F6 c5 W: v: Y- W' B, j
- data: {
9 K' y3 S3 \+ j1 b e - parentMsg: '父组件内容'5 g) P2 m6 L9 l/ y* d" P
- }
) \& j% y A% s5 N7 y - })
8 r# X( {: f. @6 D, ? - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
! G4 P5 Z* S: q( {. V2 \" V- <div id="app">% G! P/ |* ^+ Y1 K
- <ol>- p5 g( Q, t3 o m+ R p& t$ g q
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>% Q% _8 s# X# p( z- Y" y
- </ol>8 Q( V E; F) P& Y0 s7 g' {) Z
- </div>
% f& Z) B6 b" \7 i5 D8 o; K/ \3 ^ -
% S% r) ?+ g; U. F" ?7 b7 S& v! C' u - <script>
2 e7 n8 B) O- U - Vue.component('todo-item', {
# y& }2 S; y, X) m4 b - props: ['todo'],
/ a" L1 d& K Z9 k - template: '<li>{{ todo.text }}</li>'- S0 b/ ?, b0 j" P. {
- })
' v+ Y- {6 b$ g# C" h; i - new Vue({& W U% p% V; P# z* n3 |- q
- el: '#app',
3 F9 Z: _, q3 s) Q1 G3 g7 _# r - data: {* b6 v$ X( l5 {! y( y. u
- sites: [
0 }" d+ E4 @" U8 m' H - { text: 'Runoob' },2 U5 ^: T! ]' b; B
- { text: 'Google' },* r, J3 E! E1 C" y
- { text: 'Taobao' }- ?: Q1 ]3 I) v) |1 P
- ]0 o9 a' T2 @1 R: j( c
- }/ {& N2 W! F. y$ q: s" b$ z
- })
+ A( b% n" |# ] - </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', { Q; \ T- v8 ^9 i( M# {7 @- _
- props: {2 _+ I$ {% A* T- J8 U
- // 基础类型检测 (`null` 意思是任何类型都可以)8 B- B; L9 B& m/ \0 c# M
- propA: Number,
; l0 Q- [% ^$ ?) H9 `" M3 s; V - // 多种类型
% x4 B8 Z: p+ w! f2 M - propB: [String, Number],' M& m3 p5 s: P ^
- // 必传且是字符串' g; B) y+ o4 o7 ]5 d4 q+ c$ j
- propC: {
! ~5 o8 V& T7 n& Z, o" O - type: String,+ e4 m0 c$ a# d7 P x% f
- required: true+ `4 D- Q& _4 I0 X. }, {
- },
# C9 H% v9 m% i - // 数字,有默认值+ a$ m7 r- e8 C* a/ ^* V
- propD: {
5 D" V# A% \/ l+ V: ` - type: Number,6 Q' ^' y$ x5 r: E1 v
- default: 1005 H$ c+ D2 l, `- }2 s, ]4 G) V
- },8 \# a, ]5 g& S: K2 }: Q* H( g. A/ k
- // 数组/对象的默认值应当由一个工厂函数返回
% f4 R& {# u2 E8 J) n4 c - propE: {
, H. }# a% S% n* ~6 q" C! s! v - type: Object,
4 A* S* r2 y) s8 a5 H5 I - default: function () {6 V. Q6 b5 |) q9 K
- return { message: 'hello' }
i( i2 D, u3 A - }' d. K% m+ z. I! z4 E
- },
3 v, h! V1 B1 N+ X - // 自定义验证函数
/ A5 @- W* ?% }4 P, \ - propF: {
7 v1 n: x% i: [2 K4 E+ p9 L' E% i - validator: function (value) {
: {3 T- C' v ~' g8 | - return value > 106 c* `2 H4 C0 U2 f" X) P4 O" L
- }( ?9 V# o* V( @ W
- }
1 u7 `7 l; E, Q) X - }
$ \+ J. _& h3 k - })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array$ `; m$ ^/ B8 L; c
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
?+ @' {; F. k* J: N) ^
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例
# `( s' u, O) Z7 F* Y' T- <div id="app">$ K/ y, p3 @9 p. |
- <div id="counter-event-example">
0 K { d3 y h; M2 }$ [ - <p>{{ total }}</p>
. z7 ^: X8 ^, e - <button-counter v-on:increment="incrementTotal"></button-counter>
' x+ }: D3 }0 R% C) m/ X - <button-counter v-on:increment="incrementTotal"></button-counter>0 g/ Q0 D% Y1 M1 H
- </div>0 b# a3 H8 ]/ B6 J. w( f0 x9 W7 G
- </div>* G7 y' w' t `7 P
- : [+ o' o2 H6 _$ X6 S+ h
- <script>' [7 s8 K' {7 ^) k: m
- Vue.component('button-counter', {
; {. ~- Y s9 W' j5 S4 C2 _( z9 ^ - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
6 m x9 o: T8 w6 i$ g - data: function () {' s9 P7 z+ c& ?- y, k2 h+ _' p
- return {
' ]5 ]" S5 P ]3 ^ - counter: 0
/ r c$ D* V" D( v9 x - }
" U' w# b9 C. w# l1 X - },( @2 @. w! B- ]8 D
- methods: {/ m1 c6 s( O G! e
- incrementHandler: function () {
( X s; r( h+ ~4 l - this.counter += 19 p, T% _! `( F# h
- this.$emit('increment')
: O- Z: t" R* M3 W4 {! n- T - }. V1 B2 ^& h$ b I& Q
- },/ ]! R0 c& C3 ^6 C) M# i
- })
& A! Z8 l3 k$ e+ U( |; @4 N) }5 y3 ^- x - new Vue({" C+ w* R1 k* R: t" Z6 Z; b. P
- el: '#counter-event-example',9 s2 z( D6 |( f% ~7 H# i' u
- data: {
9 M4 W% j; H/ y7 m2 V+ ~ - total: 0
; k4 ^7 {- R. [& \% V - },3 ]/ L2 ]8 e3 X7 f
- methods: {
, L( L6 `$ G, \- j% B3 u - incrementTotal: function () {* D: g4 F- p* @9 l; X3 _% o5 w
- this.total += 1/ `# ^; a; \) h$ l9 E2 a
- }
7 ~/ ^8 ~% O- X2 L - }3 C, I% @. a3 Z: J9 ?9 _& l' u; F
- })$ v0 [: F3 b7 D& O" f' O
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
8 S2 T5 j) ~: Z - Vue.component('child', {& Y! J2 C$ w; C* b
- // 声明 props
* J! f/ Q2 I( V5 v1 f/ ^( @ - props: ['message'],
( @, s) r" w. k- I; E1 H# T - // 同样也可以在 vm 实例中像 "this.message" 这样使用
2 @: Z- p$ g2 \ - template: '<span>{{ message }}</span>'9 T( Q, ~) j b- B
- })+ ` m$ | D' z0 a* b
- // 创建根实例
7 L2 j# t4 ~) \: B* b - new Vue({
; i5 Y5 G2 W# [4 ?6 E( b - el: '#app',
( {0 }) F5 U5 N2 a1 T0 f6 L0 a* d - data:{
: L/ D1 p" M& w/ r7 { - message:"hello",6 E* H, g& D, T `8 S
- }5 u+ T$ N- y! h ~. m: o
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {, h* i3 d* \* @! w7 G- n1 H& \
- incrementHandler: function (v) {
- J* I- N6 y: ], h. p4 M* ` - if(v==1){
% b0 g+ o( s5 O% ? - this.counter -= 1
0 \" B" S6 q5 ^' P1 m - this.$emit('increment',[1])2 Q- y5 F+ e4 W# K( i
- }else{
+ j, i0 k0 W1 [. u Z - this.counter += 1
8 o4 B0 b6 j) q; R. { - this.$emit('increment',[2])
2 t$ F) V$ R' `, t - }
( _0 f; [2 M; s' C. E( W0 Z4 r - }* e8 x: f$ x+ o) d* C
- }
复制代码 ; Z( `: O- y6 f7 k
1 [, S/ R6 n' p f3 Z" l* I |