组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
4 w( j( H0 C) ^" Q- <div id="app">
% C1 {0 ^0 f- b# ^- m - <runoob></runoob>
4 }) C# Y) e6 }4 l( s - </div>% y" n. {8 Q8 d0 T1 ^- E. _8 u
- 7 _, j9 V/ Z% _* I& c
- <script>8 I; h+ g* y5 @* w+ j
- // 注册7 c' m: E# I8 V7 F) I4 @
- Vue.component('runoob', {
7 @$ z. Q. X8 d) U - template: '<h1>自定义组件!</h1>'
. ]8 p) W9 L% v! N* _ - })1 M; V( `! O+ n
- // 创建根实例3 q; B- r' o, ~' Y- {3 F
- new Vue({: V0 V) P* F0 A& G" x$ r; t
- el: '#app'
9 V8 w% v. Q/ v% O - })
1 o- ~# i% e$ Q- R5 W) b/ k - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: " Y2 @5 N6 O! s: t
- <div id="app">
O- p* e" ]& E# k+ s - <runoob></runoob>+ k5 J- }: |$ z: Z g6 c
- </div>- e. A0 \2 a3 `0 C, E9 q9 u
-
# x3 _+ C+ |6 W9 U* W - <script>
" G& n7 a# _! }- f$ T - var Child = {* Z' \( e) T H/ g/ H' A
- template: '<h1>自定义组件!</h1>'
: K; V8 \6 y# ]1 j% Z - }
/ y$ j V3 m6 [ - 9 `0 {- Y x1 k+ }
- // 创建根实例
% O" p9 X9 ^5 | - new Vue({+ U) q/ R' W" C: \" Y
- el: '#app',8 K& q8 X+ t& ^
- components: {. n: n* s6 D5 L( l) s
- // <runoob> 将只在父模板可用
9 o! ]4 W7 I% O2 ] - 'runoob': Child
) @3 n" K7 Z J4 w3 p+ p - }
4 w1 O' G1 R, Z& }3 r# J - })+ T9 j8 q4 F/ c4 H9 [4 J4 s. I+ C* a
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例" }9 J5 h+ j' p1 I. C4 r" W
- <div id="app">
7 z. V( v- t4 i$ Y% M* v6 G - <child message="hello!"></child>
1 \7 _( _& M: n# ]9 M. B$ B - </div>" g4 j7 ^. T; q+ S: A
-
2 T) \: y' @5 `1 p- h! ` - <script>% \- W$ H; D' y7 f# O3 x% W
- // 注册
2 D8 T# r, j# R' n - Vue.component('child', {
+ @ X% o1 {+ c4 j; ?1 M: p! W, f - // 声明 props
/ f2 Y: T6 c. }+ K( G - props: ['message'],
8 A- m W8 r8 b* E) A- C - // 同样也可以在 vm 实例中像 "this.message" 这样使用1 m; o9 y- g& f s1 l6 l9 P
- template: '<span>{{ message }}</span>'
% W- o% c0 Z9 [# V6 S2 l$ e( e - })
3 b* z2 u) y* j0 j) e2 p* h' y" R% y - // 创建根实例
3 v2 S A9 {3 k - new Vue({1 ]7 F. l1 g, c% H0 i Z) X# C
- el: '#app'
" O, X& L- L0 Q2 g0 }1 @" f1 A% N - })
" c9 S6 ?) I, `! b - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
& z o% A, u! K+ e- <div id="app">
; U4 O2 h) d9 f: b - <div>9 b! q# e; g( S
- <input v-model="parentMsg">
: v7 n6 f* }" U" j! m - <br>; C9 v. z% H2 a; x+ n# H7 C/ G2 G0 v9 I
- <child v-bind:message="parentMsg"></child>
3 p1 _, Z% r. u( U) j6 P, C, w - </div># }- c1 v9 E# H
- </div>
6 W$ `2 s! {" i0 N; l7 V - * a6 l% [1 \8 [# r) x% F% a
- <script>
6 F9 f4 ` g! ~6 ^ - // 注册
' V/ h' q& X; [: b# C5 } - Vue.component('child', {
$ D! H) X" i" [7 C9 K - // 声明 props2 f; P7 W8 c/ y& u% f* X8 T+ E
- props: ['message'],
5 s$ t/ z! ^/ J4 Y$ Q - // 同样也可以在 vm 实例中像 "this.message" 这样使用: F0 K+ H: [% y0 R. }
- template: '<span>{{ message }}</span>'
# A! q9 w {2 z - })5 F- l. r/ K& C6 U% m
- // 创建根实例
, R' l7 k6 ~" Q& s - new Vue({0 n3 O. S" S- o# f: t; B6 @/ b
- el: '#app',
3 V w+ e- l' E) A2 t8 O' g - data: { {; P. O& y& n; |" B
- parentMsg: '父组件内容'
3 W. I+ E$ g u" k% V& ^2 O - }
2 G. o( Y0 A+ |2 d) t) O! G - })% R/ Q6 m0 X/ J5 E: L: j
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
* d- F( w1 q+ f" c, x- <div id="app">( N+ V% b& s# d" U+ G: s0 _1 a
- <ol>
( N2 d% l2 L: D - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
" @* D8 k7 s0 ]. ^. | - </ol>
* I( M" e8 H# T8 X: r/ r - </div>3 X" M! i# i, L0 f. A
- : t& A+ \( `$ S9 j6 `9 A8 X5 Q
- <script>' l, [$ i+ j8 }+ F8 z* @+ }
- Vue.component('todo-item', {
& j* u0 k6 S7 e6 P0 g - props: ['todo'],
( U4 X* Z" K& y8 ^) i - template: '<li>{{ todo.text }}</li>'8 L& J9 B2 X; O
- }); e' G9 q# @! z6 d
- new Vue({! V& W0 B1 W' W2 d4 k( @
- el: '#app',
( C0 K0 `' n# y% |4 | - data: {! C: z) j# U/ O0 d3 g
- sites: [5 ~( d% K$ X3 e& ~. H& n. b
- { text: 'Runoob' },
- g# h: ^- r' h2 E7 }/ ~ - { text: 'Google' },
' U7 x: A3 ^7 n" { - { text: 'Taobao' }/ i) d5 \5 z2 L, {& J/ Z+ b- n* \; b2 U. j
- ]! B- L, j0 U8 C
- }
3 d5 R- `/ c7 h - })
/ w9 j- f, _0 | G" l+ K- w4 _" [8 u: U - </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {4 L, ~( Q* W; `- a0 i0 f" S* k
- props: {( M( X+ H3 I4 U
- // 基础类型检测 (`null` 意思是任何类型都可以)2 r0 g, V7 D; D
- propA: Number,; h& {$ ]3 z! [; F& y: V
- // 多种类型
4 R- J$ t2 Z% K. V - propB: [String, Number],
/ R, Z" ~+ E. V! W) O0 a" f! I - // 必传且是字符串
6 \ g' W2 w, S% V - propC: {8 s- e( x9 _2 j5 _& E
- type: String,
) @) h. M% d1 |) g6 {+ R2 X9 O) F - required: true
, C0 p) f! ?- B8 `8 l - },
0 v, \! J$ v8 s: a) u; T - // 数字,有默认值
" w; X% w, b0 Y, t& S; i H - propD: {
5 n4 f. O& r4 E' D" X& a K6 q - type: Number,, p, t. P! R9 m# ^
- default: 100
# h7 W6 y6 j- E5 G2 K - },
; x1 D3 Q7 r0 A/ ~- _ - // 数组/对象的默认值应当由一个工厂函数返回
% L, d8 |- O; ]4 _5 e! k2 i- c - propE: {
3 f& U3 A ]! r) V% i4 Y0 L - type: Object,# m2 W) w$ _" V' `
- default: function () {% L2 \& L; Z$ |. g3 V9 V
- return { message: 'hello' }. x( g0 z+ i. t D
- }
i" P+ u; v7 Z9 Q, s1 {' o - },$ a1 {( @. H l
- // 自定义验证函数( V$ E" o7 y& I/ J
- propF: {
7 d6 [' J, V; u- L; | - validator: function (value) {
. {3 P; ]0 s; b% p# l/ ?0 [ - return value > 10, m% u7 [( |, P
- }
! x* v, H3 e3 W ]: q - }: f* v" J9 c9 y& r
- }" k! J+ @( C6 {3 K( H0 C0 S* n
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array+ O [9 U( I Z7 N
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件, B8 W8 s6 Z6 v. C2 A# t
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例2 y: D' H' [4 A9 M" w* U' K" \
- <div id="app">
/ o3 Z4 P2 S6 G1 d! p - <div id="counter-event-example"># Q4 \8 v3 ?4 P) z' x
- <p>{{ total }}</p>/ e0 e! v$ s1 d. A0 i4 Q; m' ?1 p
- <button-counter v-on:increment="incrementTotal"></button-counter>
) s4 U2 K/ R' B0 t3 U - <button-counter v-on:increment="incrementTotal"></button-counter>
3 R% L+ R; T' ?3 f* P - </div>
# z0 y7 {+ G! K - </div>% P4 \" k- r/ V: b
-
4 B4 G6 V; b$ U+ K/ m0 j$ G - <script>
4 N A& a$ v( b0 G8 o9 f/ P0 {" w+ |- W - Vue.component('button-counter', {
2 t& _- A9 |) B, ?0 f' h" i& ` - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
# R \- Q1 V( O - data: function () {
9 U- n& R$ L4 o* {- p2 I5 V - return {
% e Y7 V/ n* L- h+ e4 u# a - counter: 0& s/ E& b2 ]" z% C9 R2 Y
- }
5 }, z' \1 O1 ?! Z; j - },& g, J4 a$ r* K# Q1 k8 A: x6 B5 P
- methods: {) r- q0 I' c1 W6 A: d
- incrementHandler: function () {
L3 O: x/ w b) W2 c) f - this.counter += 1! @, e Z6 e; F+ P
- this.$emit('increment')
, u3 I8 W6 E: a' M2 ~# ~ - }
! \6 X. h3 d, }8 X* f) W8 l - },8 x% J" _; q* v1 F1 r+ p- E
- }), k& H3 y9 @/ a! M8 j R: }
- new Vue({
/ ?2 P4 l8 R- A3 k - el: '#counter-event-example',
: \3 P6 {/ g$ W4 e& u, V: V' n - data: {
& \# c7 Y, Y% k5 E( u# ?# J - total: 0. @. v2 t% {; C, g! v, L m
- },
* W q0 A8 c, f7 v; [3 P - methods: {
4 W0 S$ k8 u: k, l - incrementTotal: function () {$ @9 C; C e) \* G- t3 H: f" @
- this.total += 1
* O- T7 o; @6 G* t& }( K6 Y - }
1 V) }# W% e8 a8 X- J7 v& F - }# q0 _& l5 {- J3 T
- }), h, F: G7 d# `' k' J
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
0 p) a* Q3 |5 L/ X9 y - Vue.component('child', {' S. T1 ~0 S) g5 D6 N2 Y
- // 声明 props$ J7 I+ I' M& c% j
- props: ['message'],
6 ]& V9 g- A7 A2 v5 { - // 同样也可以在 vm 实例中像 "this.message" 这样使用$ T5 J5 \7 |; V- n
- template: '<span>{{ message }}</span>'2 l4 {% `5 V1 o2 |, U: R1 T9 J
- })
: Y% b& Y g0 D - // 创建根实例& }/ c* }5 c! V$ H& {- b+ A% m; u
- new Vue({
( k8 F- E. _" p - el: '#app',
1 A; E/ }% F, b2 { - data:{
i- M' `( _- u9 x( m/ B - message:"hello",# ?3 W1 i; f. `2 `: B
- }
% j$ Q, ^0 r, j, v* b- E: f - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {7 L! t$ g5 B7 {, s1 u
- incrementHandler: function (v) {8 F1 X, }) g1 D _$ T1 Z2 _ C
- if(v==1){
; O& B i5 l! } u4 V - this.counter -= 1
; p' @/ l, r4 K+ B# w# L - this.$emit('increment',[1])8 j8 F& O& F2 |; Z! O9 D$ G
- }else{
+ _( B0 | ^( P/ m% L. o - this.counter += 1
" Y `7 p( k Z" ^8 [ - this.$emit('increment',[2])/ @5 o% i1 U6 \; |
- }5 B; s: Q8 Z5 i7 x9 j K
- }3 X$ ^5 ?4 d6 s) G: s
- }
复制代码
+ `9 i0 |: u& X! ?" d
9 ^: Y2 M$ v4 Q% }5 f9 Z |