组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
( b4 F' L. d' x$ P$ i9 J2 `- <div id="app">
. U# i9 F9 b2 S9 V! ` - <runoob></runoob>0 V9 k* n# e7 ^ c0 v3 m" q
- </div>
* U4 \3 t8 n4 x$ V7 ?# c( | -
8 ?* I1 B W& T3 G - <script>0 Q8 a* o- `9 I$ {" z+ f/ b
- // 注册
, H: k ^: t7 q9 A( n: W - Vue.component('runoob', {& p8 f& c3 t$ {. W: S2 O
- template: '<h1>自定义组件!</h1>'
, M% c$ P! d( h - })9 q5 l- Q* i4 k% l$ {+ M
- // 创建根实例$ j2 L; V- V* i2 O5 D
- new Vue({7 }2 n9 J ~( ^3 X- k g& @8 J/ ?0 f
- el: '#app'
q& X; g& h3 v3 Z& q$ R - })9 l, r1 n. l, q4 a+ f. W/ n' ^
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: 9 z' M! p# @$ E$ {9 W" |% S
- <div id="app">
4 k0 I# D2 i( s- p+ ~; l - <runoob></runoob>
2 v1 ?; |; x; w- ]. [ - </div>6 d& S6 e% a! o. a; z( c- I4 R5 u
-
6 H. K) s) \6 l - <script>
5 E7 s! w$ K$ } - var Child = {6 M \4 ~- A3 f: |. P* ~6 T( u: w9 y
- template: '<h1>自定义组件!</h1>'
5 h& }% B" P* H% k: ]- k - }
4 u" \ X# C+ f* y - 5 H2 {8 I' w% }2 F* O9 h
- // 创建根实例8 F$ K+ j8 A* @1 r
- new Vue({7 M' M* E& F Z/ J7 }6 M" n5 r8 @
- el: '#app',! y' J. k1 J! t' v. W
- components: {
7 j7 Y: u! f" @5 B% q, z- ~ - // <runoob> 将只在父模板可用
- A5 `; L: x; f/ h' N4 L - 'runoob': Child/ G/ I; Y3 ~, b
- }
4 B# M7 S: U& n. ~3 h/ P! @ - })6 I% {$ |2 ]/ E, W; m9 a" h3 n8 T- N- o& f
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例
" H1 O6 E9 y& G" F8 v- <div id="app">
: ~4 d$ F1 {2 C) s - <child message="hello!"></child>
2 a' l% l! i' t& q: J/ ] - </div>
4 ?( y: E: q9 M# l - . ?0 g( l1 ~- ^2 \
- <script>
( m' T) [. D: U+ U( w* \$ \$ B$ p - // 注册
m, x1 ]2 k; t' w! z - Vue.component('child', {2 k5 y ~# a [& }5 I: J) P: y9 J
- // 声明 props5 b9 q9 b- L% K7 \4 x
- props: ['message'],
+ ^( n5 I2 X. [" ] - // 同样也可以在 vm 实例中像 "this.message" 这样使用
" |1 b5 X$ S6 |7 u c - template: '<span>{{ message }}</span>'
0 E& L- y8 U- u7 G2 l- i F - }); B& l, q6 o9 S) A, }
- // 创建根实例9 B' @* I5 x6 k. x, Q' U
- new Vue({$ F6 o# ~6 C7 f" H' E# u! p- b
- el: '#app'( U* T/ f6 C) F+ F* ^" z# f2 `
- }) u6 Z7 z( k- f3 e2 V3 o( g
- </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例5 ~; J2 i1 H" \3 `- l) m
- <div id="app">6 U Z) U: s$ Q
- <div>
( B4 ]* i8 C, A - <input v-model="parentMsg">
: L' j" d8 r* v+ N' N4 j0 H6 ?% Y5 J+ J - <br>% n j5 | i' f! A. s( f% d
- <child v-bind:message="parentMsg"></child>
! s: {7 y8 B Z9 q4 q9 d - </div>
. V; _& S8 M y$ _" X - </div>
+ Q% @6 Y9 p5 b1 B0 T; J8 }9 w -
. J( Q( l; s3 z, b1 b" n4 |$ } - <script>
% Q2 I7 \: n B! S - // 注册
' b5 b9 v0 A" `# ]( m& a - Vue.component('child', {
( \# |+ J4 m- @8 t' n3 T - // 声明 props R8 F0 Z6 b5 B3 Y! p. K" h/ l
- props: ['message'],
3 y- ?2 G. T2 A4 O! T7 m - // 同样也可以在 vm 实例中像 "this.message" 这样使用$ U7 X) f9 @' }8 I
- template: '<span>{{ message }}</span>': W: u5 K9 Z/ N7 l# x
- })
' K9 z2 d9 t7 T+ g - // 创建根实例2 ]: A; w9 A4 F* b2 n
- new Vue({; L, Z' a! x6 K( p" P
- el: '#app',
: a) c3 O" O" u& N, w3 x - data: {. U6 ~5 m& f5 j) s0 g1 M5 ~
- parentMsg: '父组件内容'
: ~5 G8 p/ P1 t5 a! E) ] - }
7 {( `1 }% e' A. F# h1 l - })
7 Q; v" M* |7 F4 p+ S q# r - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例0 z" D& J+ r t' L6 n* D2 G
- <div id="app">
" R% l! c! T, f& _ - <ol>
, Y' ]9 w- ]6 B - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>0 \' H. i6 o+ X3 i0 y% B
- </ol>
* ?" {, g: p2 I4 W7 V2 ` - </div>+ W1 \2 P- p* ^' L. Z' @& |
-
/ y( ?- j0 w" i5 @* v6 @ - <script>& i* L D8 Y. ?6 ` w5 a
- Vue.component('todo-item', {! H5 z$ K8 {1 }) i
- props: ['todo'],
- c2 h) h. ^& K. c - template: '<li>{{ todo.text }}</li>'
3 m8 y$ c3 \1 B- d! Y/ Z; i - })
$ I) E4 W; c( O8 l. C; ^: }" h+ T - new Vue({
# H" L, N. f" @' Q4 V2 A' ^; x - el: '#app',) e. X2 c" W+ [/ j5 u
- data: {0 B1 B( U" F! _ [
- sites: [
1 P V1 }7 d$ x+ X - { text: 'Runoob' },
; x+ t( W; C# ]% c# F3 }* s4 a% m( n - { text: 'Google' },
. A- Y; R b" \* b( B - { text: 'Taobao' }3 |; Q0 ~" v! [& `* }
- ]
( S* q" |6 s% h - }
7 _1 T6 g5 ~! @ - })
) J! R! |* L: X- L! g& p3 i# [( L - </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
+ j( i, z; }% B% B _) X - props: {/ Y0 N4 R+ {5 ?
- // 基础类型检测 (`null` 意思是任何类型都可以)' `4 V5 I4 {' b! r/ m+ R
- propA: Number,
; ]+ ^. f! Q' x) S4 } - // 多种类型
, R- b% q) h" w6 L/ } - propB: [String, Number],9 r0 L. x1 D6 l* G S( [1 z) R$ e; V8 t# b
- // 必传且是字符串/ ?" o4 E: E1 ^+ W; C8 t
- propC: {/ j* U, j1 Q# _* P' k8 l$ O3 K
- type: String,
5 a0 D. p/ p1 Z# X0 X) x3 [* a - required: true
( v) S- t8 E7 C - },8 l2 A: G6 n3 K2 M) O! T
- // 数字,有默认值
) z; ^2 ^+ `7 w7 n3 F5 {8 P4 t0 Z - propD: {
2 ]. o* p4 e% F; ?" C. ~ - type: Number,
: E+ g1 X2 A2 `* Y - default: 100
0 K3 P0 M: w" m; c - },
3 y6 B8 v4 o* @1 Z }3 y* R - // 数组/对象的默认值应当由一个工厂函数返回
2 t7 j$ C8 N P) d - propE: {& K/ W8 M5 q1 w$ u4 l2 A2 ]* |
- type: Object,
, a$ H( F8 g+ X( n2 M2 n2 z e - default: function () {
* `% ~: G5 `7 O$ a' v$ } - return { message: 'hello' }/ X9 w5 p! E8 i
- }
2 @* k- B3 I" V2 V. u - },
9 ]3 I" M) Y( r5 w - // 自定义验证函数
) ^* K9 K. y8 U8 E: D - propF: {
- M% t4 s' M" }, j: D6 W* e - validator: function (value) {
; T. Y$ Z, \( H8 v8 h - return value > 108 Q" Y7 o/ l+ X: q- E& G. `+ r% t
- }* V3 _) k- V# Z
- }
L- `+ G3 T* g) B% d; {5 d F - }- A9 P2 d, E. U4 D
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array: F, u4 S6 N1 s1 a( E" L3 a
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
7 E4 e3 B9 ?& G8 a% l$ K
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例 {4 y3 N1 h$ l3 k
- <div id="app">1 d3 b* a6 `0 T0 B
- <div id="counter-event-example">
# j& l+ I3 x @" ^# q - <p>{{ total }}</p># t9 T& X, N8 p) p: o
- <button-counter v-on:increment="incrementTotal"></button-counter>0 W% h0 n$ X9 E6 S" N# p ^% }0 G
- <button-counter v-on:increment="incrementTotal"></button-counter>+ e N5 ]$ W3 b, r, l0 V7 C
- </div>9 f4 i: H% a( c6 K6 z
- </div>
: f# U% O3 w; B( c: ? -
# f) `* L' o! J$ t9 u0 ~* ]& Z: p - <script>
3 O3 w9 G5 h2 g0 [ - Vue.component('button-counter', {* o7 n6 D% @9 ^2 F, J" c% R
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>',9 O& O' q" q+ u: G) P
- data: function () {; B6 E/ Y+ ]; m" F- Z
- return {
$ s. d& [7 p2 T6 s! z# e - counter: 0
\5 Y$ {7 D1 I) o4 M5 t0 s - }
3 Q2 o" X$ r( I# g0 u - },
- l% U2 ~/ O5 M6 L* H0 u - methods: {- A- Q5 \! h( E- A8 N5 B0 j
- incrementHandler: function () {
7 B! z$ D5 l! c/ f* g5 b% J - this.counter += 1
- f6 z0 _" E k" V - this.$emit('increment')+ Z( f5 Q( ~ Y: c! k) X9 P
- }' U5 {% H* x# c, n
- },3 F! _( i) b" b8 c
- })
/ e; Y( [* V6 C( v; P8 a. o! e - new Vue({; f5 N6 J4 K/ O. e+ g8 m+ Z
- el: '#counter-event-example',
8 F0 S/ F$ }/ z - data: {
" S# _7 t5 w: b& z; o* ^; f% ?# c - total: 0
3 r$ m9 F" M0 c) r- J - },
/ F- g: Y( Q k9 @" s9 m3 ?9 L - methods: {
" |5 s- e7 h% w& `/ g - incrementTotal: function () {
7 q( A# s/ g" h) A0 j! b) e# d - this.total += 18 l2 V6 C" P! @6 ~+ f
- }/ Y! q7 d U9 T$ g
- }
: c9 r. |+ X. s0 _ - })
p* L F/ _8 s+ L7 P - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
/ D/ o( Y$ l/ l h8 x" B - Vue.component('child', {
& I: w5 J+ M! {) k# y - // 声明 props$ q( Y) G2 z9 F$ W/ H1 y, H, O' u
- props: ['message'], c! b3 k1 I8 W$ \% G, s+ T, E
- // 同样也可以在 vm 实例中像 "this.message" 这样使用, [! b; I' ]& b6 H6 a8 k* {. W( h
- template: '<span>{{ message }}</span>'
5 \: i2 Y- K" {! P3 ?# i - })
( `) J* m/ J" `$ o8 ~ - // 创建根实例
1 ], A2 T) P9 G3 y3 n I - new Vue({- i" D$ i7 e. o, k# b1 S' `
- el: '#app',
8 |) O" i% k/ e9 B" B0 K5 h5 _ - data:{7 _, B5 {) p! _9 d+ b3 y; F% r& L8 D
- message:"hello",
' e& C( m: ?6 f/ I5 ]" x8 Z - }
. w: S7 Z! ^8 p8 G( ? A3 ^. P - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
8 w. ~- Y- N/ n - incrementHandler: function (v) {+ n% f* C( t4 r* }2 n
- if(v==1){
, S8 y& Z& {; C, A - this.counter -= 1) Y( B& |/ N1 d, f' D9 u2 h
- this.$emit('increment',[1])
# p6 o' N# [4 e" |0 w# W1 o - }else{. ?+ `! h8 p4 y* V9 f& S
- this.counter += 1 ~ I! L+ _* s: Q
- this.$emit('increment',[2])
/ _2 ?8 F( d; n% b( L( ? - }
8 \+ g# k8 f* L- {" W - }& ]& w$ K. `: y' `' x
- }
复制代码
6 v% x D- x7 d# U
& Y' h7 \9 n8 j/ R/ Q |