组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它: 3 Z; ^4 U0 B n: i( d
- <div id="app">
+ [4 H D4 ?2 z& J) t" T - <runoob></runoob>
/ L# j- }2 ]0 r- N4 C/ ` - </div>( d( M* l# z7 o; z0 K
- 4 _/ F9 }5 C% B6 n* B5 {( N7 l
- <script>
g2 I5 p7 D/ T - // 注册: T8 D, |# Z0 w! h3 f
- Vue.component('runoob', {9 f: K- c& P8 H" ?& V
- template: '<h1>自定义组件!</h1>'9 `% }" e" R2 D: F% l
- })
& `' j f8 V: \, L9 O( T' C - // 创建根实例
/ w9 @ k6 K1 f4 _& Q3 Z - new Vue({
! I4 @. [$ p- v - el: '#app' k; w2 r/ q% S, f. A
- })+ G& e9 r. `" `5 ?; n# b8 _4 f4 r7 v
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: 8 d) z% B, _ D" `3 x) O! g
- <div id="app">* s' X* ]8 s1 V: b( o" b
- <runoob></runoob>
$ o: P+ e( B8 |5 u - </div>
" o6 e+ [# w2 ^6 d" I& Y" n -
! ?3 f7 ^' o1 V" O) z1 c - <script>
7 R2 [* \! a& @5 f$ x - var Child = {$ Q+ f0 S/ k0 K. i- f( k
- template: '<h1>自定义组件!</h1>'
# P9 E$ [+ T1 S - }
8 u+ `; |* t: m! Q8 O -
- K" L7 g E5 O! ? - // 创建根实例
) X$ r6 i \8 u Z4 Z: V - new Vue({
" }2 C" m$ ]8 K/ g9 N" C - el: '#app',
- e7 X2 @6 L: e8 j8 H4 J3 ^ - components: {& d) _" \4 _8 m
- // <runoob> 将只在父模板可用; {/ }6 r0 n/ W/ H& R- H( H( K
- 'runoob': Child9 a% A! M4 z8 y1 o# j
- }
* z) b, ^; D( r8 i - })
/ d, G/ Q& _6 u, F9 w) \ - </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例4 k/ b7 }: P6 N% c% K' J( L
- <div id="app">
& c0 Z- Q; k2 b! j$ `: n - <child message="hello!"></child>
$ f4 d8 H' N" E/ D" Q2 i6 k - </div>$ S; M& t! G, W/ `( z
- 4 Q& t# Y: c( m+ O" X4 I
- <script>
$ W8 a+ S0 G5 n8 o - // 注册
" b- T4 Z. t! S/ n# J2 B1 m - Vue.component('child', {
# Q- o9 |' x+ V4 k - // 声明 props) K. _, L. D" x' k3 V! z; f8 Y: W
- props: ['message'],
1 \" j3 @% Y' l, S7 J, ] F% b - // 同样也可以在 vm 实例中像 "this.message" 这样使用
( z+ |* a4 Q! A* J: e - template: '<span>{{ message }}</span>'! B2 e+ `$ X* |
- })
0 V' }- l/ l8 l3 J! X) m$ q/ F9 T - // 创建根实例* H* ]7 n; ~2 d2 p" w) }( J
- new Vue({
2 \9 i: w X. e" F4 E - el: '#app'
$ U3 S5 ?; I1 K/ y+ b - })
! p: @: i& q# s9 \* H - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
/ r! y2 x% p8 _7 e4 L5 s( [! R- <div id="app">7 L6 T1 A: W% J4 Y1 K; `6 b
- <div>
/ J* T& ^7 w4 ]2 n. {9 y - <input v-model="parentMsg">
g. `. ]( Z. U - <br>
7 a) A% M, b! }2 c3 A; s6 S4 C* T" x/ r - <child v-bind:message="parentMsg"></child>: g) g r! p4 O, G8 c( x
- </div>
6 O3 r) ?! c! |, ?2 @ - </div>
8 @3 y4 o Y2 A- I4 | -
e& K1 n) N6 a$ B' L% Y5 M2 a+ J% b - <script>0 t" {0 J, M! s3 f& ~5 u# J- A
- // 注册9 s- F' c# L4 j* e7 Q+ V2 n& K
- Vue.component('child', {
8 h$ [6 c [9 Z7 j* U, Y - // 声明 props' u6 o' i* y* q: N1 T
- props: ['message'],# ]# _' P+ G5 K/ j+ Q4 f. F2 D
- // 同样也可以在 vm 实例中像 "this.message" 这样使用( X2 [& D A$ y0 U
- template: '<span>{{ message }}</span>', e# z1 q6 K- C: e Y. V
- })2 j2 G8 D- D; h: }7 y6 A, g
- // 创建根实例
+ @0 n4 Z# R6 K/ M* j: b - new Vue({: }9 t! P. w. F) m5 Z L) _2 O
- el: '#app',, t( n4 P* U$ t/ B
- data: {
2 {- i: ~% J$ S' a1 F0 @4 y! d - parentMsg: '父组件内容'' g2 w% {! U& v$ s: b
- }1 S/ F0 x7 x1 w! i W: d/ p
- })
9 I( }) a4 ~6 C" | - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例2 ]- |8 V; ~; a: Y+ z$ B7 K! t$ K
- <div id="app">
& S- V. \. ?8 x, s6 \ - <ol>
5 M( \- ~* t( ?$ k* q - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
$ j$ v, v) r2 z% E( c6 H. L - </ol>* M9 `7 q F; k. ~
- </div>
; d3 z3 L6 _, x - 7 u% w5 x$ d7 ?; ?7 ~" R; g! S5 I
- <script>! K2 W9 z+ s0 B" ^2 G4 ~9 f' L3 q
- Vue.component('todo-item', {$ F9 P5 ]5 v; g/ L: n
- props: ['todo'],2 e) [! e, {8 X h a6 k4 y
- template: '<li>{{ todo.text }}</li>'% v, r ~0 v: w+ f
- })
: t8 z( u( F9 J; ]# p. i - new Vue({: e+ @0 ~1 x& J0 V4 O- ], j! P
- el: '#app',# X) f! i; q6 ~
- data: {: N3 @6 {$ H( r2 l# e
- sites: [& T' M0 f/ @% F- G8 y7 f1 B" k
- { text: 'Runoob' },
$ N W8 v$ t: m, O - { text: 'Google' },
8 F! O- s! r, q s# e7 ?4 R3 L/ m, ^ - { text: 'Taobao' }; F) r# T O; m" l
- ]2 S5 M5 v5 ?2 S7 L5 ^$ \ N
- }1 J1 d% x( F$ d9 u' v
- })
: ]& {$ r% B- n! q# K3 ^( U - </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {6 F/ X* A1 ]; I
- props: {9 ]( r3 T; t" N) _1 y5 a" J
- // 基础类型检测 (`null` 意思是任何类型都可以)
; L+ }; C0 \/ I" d( j - propA: Number,, V# _2 _' ^2 A6 Q) k W
- // 多种类型
* V0 f& P" O' e2 k" j+ F, j% z6 L - propB: [String, Number],
. ?2 [9 O/ [: o0 F* `% u - // 必传且是字符串
+ C9 E# k# I- |9 O7 z - propC: {9 E) e: m; B+ d* l: L; e/ a
- type: String,+ V# [* }5 R, f; ^; J: Z9 n
- required: true* d8 N6 p! t6 c( z2 r9 `
- },: B5 l4 s. w. e
- // 数字,有默认值' F( _5 e6 p/ c
- propD: {* S7 Z( Z$ {; E0 A! N
- type: Number,
% A M- x& j- F& g5 r. J - default: 100
5 J9 c1 G. f3 M% J1 T& }, z0 G - },
6 X* x7 j+ I! m - // 数组/对象的默认值应当由一个工厂函数返回1 `% H* v. M, G' Y7 p
- propE: {8 Z8 a [! w; C C$ K7 m
- type: Object,/ T t0 f0 d0 ~4 I" O* ^
- default: function () {
2 c1 ^/ V2 y1 H+ B% n - return { message: 'hello' }
8 ^5 ^, O$ L. k& D4 ~ - }0 K) t4 ^5 {/ f9 }; Z P( A/ m: {0 B
- },5 E) e7 g+ y. X/ b1 D2 V" u
- // 自定义验证函数9 q9 \0 O. `3 E5 E1 m ^+ I
- propF: {
$ N8 J. Y" S, o% e - validator: function (value) {- o" K G S! d/ v5 o/ N5 |7 @
- return value > 10
" B7 {. u3 c$ O5 \$ Y' \$ ^. b - }: P7 K5 S' F% ?) F/ |) v1 \$ A
- }
% T, F- b& U3 f/ m! s0 V - }& Q3 H$ x2 B9 r/ ^2 O
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array8 ~6 t4 r: s# j9 F( B/ Z
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
w* E! Y X- ]
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例! R: r% W' c; g9 }: h1 E n, u/ O+ V
- <div id="app">
; _( z3 X# t) ` - <div id="counter-event-example">
- ]5 V- S; H0 k - <p>{{ total }}</p>
2 Z# W7 k, d! B) ] \ - <button-counter v-on:increment="incrementTotal"></button-counter>
- B" ]9 q0 J$ H4 P7 Z' Y! d - <button-counter v-on:increment="incrementTotal"></button-counter>! [7 x+ h/ a8 O+ ~& F& ]+ k
- </div>& i" T, d( T Z2 R5 g6 y5 s
- </div>
( {' B1 q) z# \ - % k. I4 i/ U( C/ w8 ] E
- <script>
0 A6 F- {, J2 Z - Vue.component('button-counter', {; e U/ y& d9 X) v' ]$ Z$ C; |
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>',+ Q$ N4 x4 j/ d ~6 u% [
- data: function () {$ R* j" |, ?3 ?& | f
- return {5 x! w& \: H' }0 b( A9 ~& x" Y
- counter: 0" k. g/ e# y$ H6 g
- }) `" B! C) M' L5 H ~/ a$ c
- },/ l2 `3 o8 T. ~( @
- methods: {, r4 p: s, R0 \4 X8 E: ^7 ~0 g' b q
- incrementHandler: function () {
3 a9 P) i, @2 Q - this.counter += 1
2 @" m" v- t& s" i! k7 L - this.$emit('increment')7 s9 k6 m; v' u( N" z- b" x5 i
- }
+ H) U1 ]( z( V; [, f6 N - },4 @" r& y2 b% F5 S
- })1 L. _2 @5 ]+ y) I, g* Q
- new Vue({" l4 O. i) n8 y( f ~8 _2 X
- el: '#counter-event-example',' I9 m2 ]' W2 x: \1 I" y2 k
- data: {6 G5 T1 Y( z6 P" W* J. U
- total: 03 w' X4 y0 h8 ~3 e
- },5 f, Q) A' C+ |4 {3 z% T+ w
- methods: {
5 l, F: O r4 H% o5 {' T( t+ E! U) F4 Q - incrementTotal: function () {
9 a" E: y+ | o4 W! J! g% M, g' Q - this.total += 1
- P' @& j' f. s& U& @8 h) E - }* f3 V! B- ]/ d0 x" [
- }* P+ K/ } i1 N" t% k
- })
3 x1 x1 w: M9 n6 v. e/ q - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
" n( V' x+ K: b5 |% w" j - Vue.component('child', {- c* s, h7 F, ~4 I* ~
- // 声明 props
: a, Q+ R& j7 C! n - props: ['message'],
' s0 x' X. y0 W; L0 v - // 同样也可以在 vm 实例中像 "this.message" 这样使用! Y" N1 s! T/ X- I; H' W
- template: '<span>{{ message }}</span>'
( d0 y" ^# v" w4 b0 n) J! f: b - })! q$ h) ~" O/ M" ]$ e& J
- // 创建根实例
: o5 X$ {, Y- {0 P# ] - new Vue({4 w% n5 R8 c, F
- el: '#app',
1 v! C' `3 G: Y - data:{* r# \# }' T4 I) [+ r( @0 [) K2 H) q
- message:"hello",2 S- }$ @% E0 @5 t1 U q
- }; \. S9 B& }3 ~ N- G
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {* e$ M) ]; w2 H9 x, p* K
- incrementHandler: function (v) {
% I- J7 h; S1 V - if(v==1){
5 U9 `# G2 x$ ]9 m. X# ]. K - this.counter -= 19 z1 H4 X% F' j0 g# r
- this.$emit('increment',[1])
9 s* d8 }: f" J6 j4 I - }else{
* z/ f; p* w) t0 x- q# Z; Y - this.counter += 1# C1 j" I5 Y! j9 Z) y$ [( W
- this.$emit('increment',[2])- G" b$ x' Z7 \/ s( B
- }/ G! a/ V% T, o2 Q2 I% o4 B' q
- }- d7 B: n7 M. v8 \7 I) N
- }
复制代码
0 o3 J/ y; U6 D W( `" N- w/ ^/ J: `
& \3 X; J6 k. v/ d; ^ |