组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
7 [8 X' E1 L9 b: @8 m% g- <div id="app">
* v6 a9 z, S; p; e; @ - <runoob></runoob>7 R s3 S8 h1 s8 N! s# w9 \, v T
- </div>! Q/ d' z! E7 L# C% o D
- * \7 ?+ L8 h9 W, |3 z
- <script>$ x: m+ J* }4 {8 o Y1 T5 F3 J
- // 注册) E. { n& j/ L8 S
- Vue.component('runoob', {. |: |, c) y$ P" v |& e! Z$ n
- template: '<h1>自定义组件!</h1>'+ O- P# }' t+ K# G; w. q+ x; L
- })
* t3 n; K; [) E - // 创建根实例+ z6 V8 p/ D5 b9 u! f. c5 k4 T8 @
- new Vue({
' C- U8 @, G R, C! N - el: '#app'
1 k6 F* D: R# N4 I" m" r1 T7 i$ s- ` - })
' `" o5 G0 E% z - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它:
/ i9 k, A; H/ ]( u; T; S1 d- <div id="app">6 c5 V. A- T7 O
- <runoob></runoob>
! N; y* g1 b0 `" ~1 W- r - </div>
+ f) r- u2 z L+ @6 A - 5 D. K% }9 X3 B! ]
- <script>
' D! \$ B. W1 @! w. \4 u - var Child = {: X6 `/ b) W! l: O/ O
- template: '<h1>自定义组件!</h1>'
$ y" S: U( \( ~/ }6 e& F5 K - }1 U7 ]6 I: y; U$ u6 l
-
+ x7 z0 Z3 [' U0 p8 U' ] - // 创建根实例
9 Z! q/ w1 B! M - new Vue({6 E" J8 n) s( s/ T8 `2 c
- el: '#app'," Y8 ~6 ^4 q1 k' z2 i( v. F8 m* A
- components: {
+ l8 X- P3 D" C$ ` - // <runoob> 将只在父模板可用
7 d; T4 [3 a( o/ s) G( T - 'runoob': Child
f3 Y' y: z+ w* N( ^; h - }' \' N- K) |- F! H7 P
- })3 n# I. P b% w, W1 F
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例
( i3 P' @; ^# ]- <div id="app">$ l- M( w: g: f0 ^% \
- <child message="hello!"></child>9 C! m p2 n/ i3 k. M8 X6 x3 J
- </div>0 {5 t. F5 i4 u4 [0 J
-
4 I1 T7 e5 n. }- K' I0 a8 E - <script>$ ]- d1 J3 T5 N$ |( G9 M
- // 注册
' C) H$ F- O& i: D4 I, h% X/ e - Vue.component('child', {' v$ D' \+ v, M( |7 f
- // 声明 props' {9 n- [8 }. i( v
- props: ['message'],. c4 d, G6 \) o+ a
- // 同样也可以在 vm 实例中像 "this.message" 这样使用$ H4 p/ ^" w" _+ S
- template: '<span>{{ message }}</span>'
! i3 s, y1 _ ]2 E# T/ l& F( T - })
$ I- E+ j# H- J% K# ] - // 创建根实例# ?" R4 ^6 ~5 V4 h( m/ T0 H C
- new Vue({- [+ p! u3 E) o6 W
- el: '#app'
9 K6 j, R' o, L0 \) o$ @" N- L - })8 o4 S5 P/ G# X/ y
- </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
* X h: g3 D a( @- X3 e- <div id="app">8 P! }0 c; ?8 W$ \" t
- <div>* l7 D( O! T: |7 o# }
- <input v-model="parentMsg">, }9 t+ Z& j/ M I5 k7 Q) }
- <br>
$ z7 l/ |) {+ [, c6 m. Z - <child v-bind:message="parentMsg"></child>
2 d. ~7 {/ s d P* S - </div>
C/ I" x7 S8 n- r5 `) | - </div>
5 z( P; X; z2 i$ s8 R" l' C -
0 {6 q9 S' z* I7 ]! Y - <script>( [- g+ S& u, D2 {" C) ^. B
- // 注册( z, h% J! ]0 S6 ~8 B+ R- H# Y) S, X
- Vue.component('child', {( q( D# [( \# t8 ~1 V
- // 声明 props
5 X4 i9 g" [7 q7 j( Z; ` - props: ['message'],
* E6 p( R6 j5 D" n - // 同样也可以在 vm 实例中像 "this.message" 这样使用2 L) A" s, E4 c a$ p+ h, q) ~9 g0 |
- template: '<span>{{ message }}</span>' q: W! e% K6 G2 {. m: O- G
- })
- b$ J' r/ i! v# U - // 创建根实例, i$ s# R( Z) C; e* F0 {# a4 P
- new Vue({
+ k, B: w; a! X& _4 C5 l6 H- H - el: '#app',# Y# O2 w2 \8 S7 f' e3 B; s
- data: {
j0 w6 u' e" J X6 u: B$ | - parentMsg: '父组件内容'' M) r# U) j; o( D9 e
- }3 S, F+ r) b2 m
- }); V$ p' a( @) p r7 W* f. a
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
( u8 }9 a/ C) _+ [' d5 M x' O/ W- <div id="app">
. D* H) J) ^- U - <ol>
; u5 \. T7 }, X9 d: L% L7 a7 J - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>: E: {. @' w% n2 U, v0 {
- </ol>& ~2 a2 }+ N# {! ?7 @) Q: ^2 Q. X
- </div>
/ o* P+ r3 X# n, O$ M/ T - 6 U3 g2 f6 Q: E- G( J( T
- <script>
4 X7 v6 Q6 W1 y* x1 Q+ T - Vue.component('todo-item', {6 D* |8 P) X8 j. U
- props: ['todo'],8 \! o3 ~) A4 |% Z/ l- _3 t
- template: '<li>{{ todo.text }}</li>'* O( K$ D/ ~$ U5 T2 R
- })% K! ?, K6 ]6 T5 Z
- new Vue({
6 X1 J$ @% s# Q# F - el: '#app',4 K- v6 V0 b+ E2 k5 \ ]
- data: {, z6 Q6 _* K0 C- O
- sites: [9 t9 \/ m. K- \
- { text: 'Runoob' },- u9 B+ n/ s3 W! A$ ?/ E
- { text: 'Google' },! _1 o3 \7 r/ Z5 z& @: H
- { text: 'Taobao' }
" g1 A7 @5 `/ s% H - ]7 g+ F8 {; y' a2 Z
- }! T/ `- Z) M7 c' f& o
- })& i. ^" t) f; M/ d( H5 F, T( M
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {. W \& G+ C" g) H) o
- props: {
) K! H+ d9 x* d - // 基础类型检测 (`null` 意思是任何类型都可以)5 ] Y) T2 R/ ]9 Y
- propA: Number,
& r. o# D1 c0 k! k - // 多种类型 g/ w* |: s- c7 e; ]
- propB: [String, Number],
1 k# h0 K* p* Y8 N, ?% M - // 必传且是字符串
, V- y: b3 `) E - propC: {/ L( _ U: ~$ t0 ?* Q c( _4 j
- type: String,' {: _. E' ^: u1 Z @ f9 X
- required: true
% ]3 n0 Y/ y! X6 ~8 O8 U" H - },
; ^. [% }! W) \# g - // 数字,有默认值, W$ @1 ^; p+ ~5 x" T, N3 E6 u
- propD: {! V! l" j# _8 t# Y1 ^7 ~
- type: Number,
, }! V) X- i1 y( Z; b: k+ m/ U4 R - default: 100
1 | D% H5 F; n8 N! {3 l. l - },0 u1 B+ |1 h* A* T0 P8 m. F
- // 数组/对象的默认值应当由一个工厂函数返回9 J& j6 x& ^) z
- propE: {
( J6 z' w6 k" x" \, s - type: Object,
- N, u x7 J) F) L4 J* J; [* m' _ - default: function () {' x6 z$ U( ^: ~* W& r$ V
- return { message: 'hello' }7 F; U) B/ G$ z% d5 o2 i
- }% j4 s, f3 `! [' u) ^* M+ s* O! M
- },' V" R7 Q5 v* ^
- // 自定义验证函数
. H$ P; ]- S+ j* Q3 \4 w5 S( U7 d+ W - propF: {
4 b3 y9 \* v- W" u2 h( O' E - validator: function (value) {
* m% o" d* O* n" P) D - return value > 109 \# g* T# m- _& @) S5 }4 T
- } `" L1 z" h8 E+ J6 L8 L
- }
: b$ N6 l7 |. V8 Z7 t - }
u1 B9 |5 T! K - })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array$ E3 u6 l5 U' `/ i
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
2 ]1 m. @% Y6 I0 ]0 D% T7 M
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例
5 g M A- P: v4 L( i ]- <div id="app">
. b( N, N; C d0 D+ Q - <div id="counter-event-example">/ e6 I0 z" i, t# F& W
- <p>{{ total }}</p>$ y n, u1 g7 }' k a5 W& N, m
- <button-counter v-on:increment="incrementTotal"></button-counter>
" P9 q# y. I1 _) K - <button-counter v-on:increment="incrementTotal"></button-counter>
1 @$ [( h" t/ U+ y7 s5 @ - </div>7 `: s: E4 ~9 f6 P5 @' Q. G, ?
- </div>1 K; N( S; T- N0 i0 e; o+ p
-
& t) Y/ A# V4 X$ T" l5 v+ Z - <script>4 y7 y2 Q8 W5 F+ A. I
- Vue.component('button-counter', {
# K8 \( I4 Z* l* R' { - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
/ T2 I$ k0 q8 Q6 ~ - data: function () {+ @' b1 k% h2 S6 @1 k
- return {
$ N1 b \* ?0 q( G - counter: 0
6 u0 Y! P: H' Q8 B0 ?( P* X - }7 Z2 r' B' {# l _
- },
7 X$ d8 \) E% h( x' o - methods: {
5 ]" e/ a, y8 @- o# f - incrementHandler: function () {( Z& L3 n$ m, J$ @2 {: c0 j, o
- this.counter += 14 s# X8 q7 J0 z& t. ]4 ?
- this.$emit('increment')
8 x, u7 V' g5 [ - }( W# F' t3 i3 K, I: e9 p9 Z
- },& g1 k0 {: ~& l, k% V
- })
$ t1 m7 W$ _; a S3 R+ X# J - new Vue({
) B3 \/ L/ i4 v% R" h - el: '#counter-event-example',
, p# D9 f: y+ l$ H2 X& I. B - data: {
0 Q8 ~; s* G$ l3 T - total: 03 d- Y* `/ ^5 o0 {* a5 O, H
- },
8 F* q8 R0 J5 e% q/ Q5 u" S# ^6 ` - methods: {
, N7 [: T% l$ ~& L7 }+ P% R - incrementTotal: function () {$ X. l* [ P; ?
- this.total += 1
' U, d% u1 a$ |- H% F$ p9 X& D - }
% r9 C9 c0 M2 I& i( s0 n - }
1 Z0 Y) k8 r, y8 |5 O$ n - })
% A; ]5 m' I4 N X4 D - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册0 v2 l1 S8 S, s
- Vue.component('child', {, C# r! r0 v" _8 T5 O
- // 声明 props! G( u! {5 K/ o( `6 w& a
- props: ['message'],
' u' N4 V# `7 q- G! v& l! v3 z- Q - // 同样也可以在 vm 实例中像 "this.message" 这样使用/ p; [$ ]8 f" _8 I" E' \6 `
- template: '<span>{{ message }}</span>'
( A' z' n0 a2 _! O& U - })# T8 [( @8 A0 T4 ], l
- // 创建根实例
9 o% m$ G' h+ z7 i6 } - new Vue({
, y- y9 }- Z4 u( l, r - el: '#app',
2 ]! g3 f$ Q# R' b" c - data:{" }2 g0 m+ D6 X; B3 n, b
- message:"hello",- f: J/ X: e% d
- }: l9 @% E* c$ T1 v! W7 o: K
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
( g% O. G) G: S5 F" I - incrementHandler: function (v) {2 U3 t0 A3 ]6 g- X
- if(v==1){
1 |2 E$ v$ F! y9 b - this.counter -= 1* J2 D0 Z8 Z- T- L9 D
- this.$emit('increment',[1])
$ P8 H0 \8 l1 q, y+ [1 x - }else{
/ F6 \& h+ k- ^ Y+ N3 H } - this.counter += 1
" j7 e! J. b5 k* M: F! W - this.$emit('increment',[2])
, m; [7 }3 E( T, b2 b5 c - }
. t8 v' w( v, x+ j6 n - }
7 B7 E, V' W% m9 { - }
复制代码 # |) ]; S: j& R# j/ ^* E! ^% V% n
V3 c. ~. x) C$ a; S2 K/ T
|