|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
, _/ V, y0 G" \* B3 {. W- <div id="app">- V+ L5 w% y2 j! p
- <runoob></runoob>. N1 K% O6 F- E v: f2 z( C; E
- </div>
: L, I" J& `. U -
3 a& a/ D" S0 H0 W - <script>
+ [$ ~( j8 Q4 Q" R, } - // 注册
7 G! V% p; Q3 X! y1 j. ?* a - Vue.component('runoob', {* E* ]7 R# j! q9 y9 e
- template: '<h1>自定义组件!</h1>'* t, L) t3 Y+ o8 ?
- })
3 u$ I' n" ~; |+ U0 v7 z8 i - // 创建根实例
( S' ^* U9 _3 E7 ^ - new Vue({& L \* M+ E) x" s7 a# \
- el: '#app'
: s* J5 m- g7 z1 I6 z8 |4 C - })
( X" H4 T4 b* G+ ^3 S' } - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: 6 u8 _6 K8 A/ y! [# o2 e. T9 Q
- <div id="app">
+ T7 y& z( ?0 S7 | ` - <runoob></runoob>" ^& h g6 U1 g) T ` k) E. `
- </div>
# [& m4 x4 ~; x3 k6 s -
) U" y7 e3 W4 a, @0 Q - <script>+ [4 Z! `" @+ X" W6 |7 A% |
- var Child = {
' G' `7 F# F: L- m8 ~* ] - template: '<h1>自定义组件!</h1>'( H! q$ t( ^3 g5 ?% l# ?# h, [
- }2 Y' ~' y) d$ m8 ^" K
- 9 v) a! O* |6 T' u% d
- // 创建根实例
! k6 ?& H+ C" S d1 Q - new Vue({: a' u8 _) @! a% k0 B7 b
- el: '#app',' W* I/ J" R D) Z- o
- components: {
) k+ D! [2 F6 ?& u - // <runoob> 将只在父模板可用, ]0 ]* [( e0 h3 b/ r
- 'runoob': Child
( C7 a# Z6 u2 [; j- h& {2 \ - }) d2 ~; e' e- ^/ U; y, Z! B
- })# |4 h6 _8 c. l7 s- B
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例6 G4 F6 D8 z% R
- <div id="app">4 b- L+ o; ? n. b# _4 a! ~7 }
- <child message="hello!"></child>
+ {1 H. C3 Q+ _' B1 Q - </div>5 `/ T# @( S' a0 d! C. S( y1 t, N
-
7 w" N* L+ Y3 f! Q" Q1 F0 | @ - <script>* j) ~+ B+ o0 n# E8 h; a9 O
- // 注册* T3 u0 B; q4 b% ]8 \- ~1 f
- Vue.component('child', {
* X; p9 ?+ s3 R$ f" ^! j - // 声明 props4 _3 x- j, E' t7 ?4 q
- props: ['message'],5 N( z u$ f; H7 }& Q
- // 同样也可以在 vm 实例中像 "this.message" 这样使用4 I5 f5 l# ^4 H8 _' i) `1 z
- template: '<span>{{ message }}</span>'
' o7 i0 `& Z W$ a1 ^2 S3 k - })6 h+ ^+ I* }) }$ G# z) n
- // 创建根实例
8 u" K8 q" j0 x# F - new Vue({5 C; l* v+ f9 l& z. `
- el: '#app'& a0 |( _2 N V& U
- }); a" B0 V# W7 B& x6 X
- </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
. y5 O' G4 b6 Z& {) k6 u& q- <div id="app">; i, x( k9 ]1 v" `+ r9 M2 o
- <div>: e) F) G" e- M
- <input v-model="parentMsg">: l( Z1 [) k# y$ v/ _6 R- }( p! g
- <br>
0 A. O6 F+ B5 r: m2 X - <child v-bind:message="parentMsg"></child>
# Q9 \3 F7 `. b1 g# g, a - </div>
* x5 s+ ^* ^# a$ c - </div>
: M/ I' a2 m& a -
! ^" l0 |1 N1 ~! g - <script>) k) ~4 t4 ]9 b
- // 注册
: A% C- Q" f/ ]0 n - Vue.component('child', {4 {3 S- Q; W% a) a& J
- // 声明 props# X7 D; ?0 M# f, C5 l
- props: ['message'],& y8 a; H- G( P* {: t2 `9 P
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
# k5 \* i* E0 E( m - template: '<span>{{ message }}</span>'
8 p1 B( m+ X3 ~ - })+ @* x5 T) A9 J3 v- B
- // 创建根实例& [1 c" {" V, }3 W2 g* p% J) {
- new Vue({0 X# |" [8 q+ M/ Z; H# v
- el: '#app',
. U% U- |. `) Q - data: {. ~9 s- }' ^+ P
- parentMsg: '父组件内容'. U9 t- h) L2 F+ B; V: o: f* P
- }
# a& w' D/ ^! t+ `9 w" y4 N - })1 z5 U9 Z: P- z& e
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
J' N4 J+ @$ r/ G- <div id="app">
0 G) G1 A' h3 y! \1 R) q1 Q0 y" } - <ol>. O% t. P/ F4 q6 r1 E( z0 q8 l r
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
4 s6 }& O9 C, D- W6 F - </ol>' T$ @+ f5 Q2 J
- </div>. L; d4 Q6 ?3 f$ D+ A! h
- 6 t1 j2 O# l7 }& y% }: Z+ i
- <script>4 n1 r' @8 ]% S: M$ |& f, Y
- Vue.component('todo-item', {
7 g1 j7 R8 M3 N# V - props: ['todo'],4 y% A3 r' @; K, I4 V
- template: '<li>{{ todo.text }}</li>'8 m# } e2 j- L$ v
- })6 u0 |3 D( z! e! G$ T
- new Vue({+ h9 g9 u4 a0 ~) I. _! b+ r
- el: '#app'," a) N9 s8 _5 ^/ p5 d# M7 n
- data: {
+ B3 f- H2 l& g, E/ ] - sites: [) i! \: k1 R& }" v, q3 `( V
- { text: 'Runoob' },9 r a+ \. ?! [; L7 C( F( t2 \
- { text: 'Google' },, ^* U) ]) g" e
- { text: 'Taobao' }
" I1 q7 A6 Z# Q" D6 w - ]
7 C- Y: X3 |* h) ?9 b ? - }5 A' g6 I- q$ |( ]
- })$ b, ^; e* h' \: P: G. v- N
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {& o+ A# p& @" K( U
- props: {
9 V1 @/ X, K' ]+ w6 a& V - // 基础类型检测 (`null` 意思是任何类型都可以)
! ]- ]9 n: z0 w! b4 z - propA: Number,9 e% y2 `* E7 A% n' {: f: S
- // 多种类型; i0 s: ^6 K8 q( E- ~) i& c
- propB: [String, Number],- e! Z* Y1 W' ~/ a% Y, Q( U; v* h% y
- // 必传且是字符串1 Q; B: Y7 u/ L! w" O6 z* o# x
- propC: {
, X/ R4 y& c; B" J4 t - type: String,
; L+ d: y* y+ {. e+ g - required: true
8 S5 k0 V/ \ l7 X | - }, V. E9 b# }/ y) W$ T
- // 数字,有默认值
! H4 Z1 N0 z7 e - propD: {0 k. C. m4 [0 l+ J' [7 E$ E
- type: Number,
9 T2 h: P9 m2 l! E - default: 1000 E) _: n# L+ f3 n
- },
6 Y' U2 r3 j+ c/ m2 ^1 X3 } - // 数组/对象的默认值应当由一个工厂函数返回( [) v- t) ?2 C9 F0 Q7 D5 v
- propE: {5 k8 u8 \1 z4 s$ s Z
- type: Object,$ ^4 F% l- t+ j
- default: function () {
* u% p" O$ A1 ]/ I - return { message: 'hello' }# p) S' a) ]& k# n8 C
- }$ \1 Z: Y1 P. O9 o6 J5 b
- },: ~6 |$ y" a4 J7 r+ M, ~' _
- // 自定义验证函数' o5 k) }$ ~ ]# m9 H
- propF: {
; E' E1 y0 J, g, ?; J - validator: function (value) { f' I' e$ n$ q2 p
- return value > 10* L* T$ T& G+ [8 ?
- }& }- n6 X5 ^. @' T- _) Q% ^
- }
2 Z2 i$ O5 e, l6 K" h- ` - }( H$ ^$ Z) p }4 m' {
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array Y* k2 _ e& b) ?
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件* @; q5 r# H: |& [% P
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例3 I3 E) ~% B3 O& a/ F- I& x2 j
- <div id="app">
& z0 j9 w5 |. B5 [ - <div id="counter-event-example">
; X- q' F+ ~: B5 ] - <p>{{ total }}</p>
" ~1 t0 N7 _8 Z x+ | - <button-counter v-on:increment="incrementTotal"></button-counter>$ i0 y* u( c7 W, \" Q" z) \9 y' g
- <button-counter v-on:increment="incrementTotal"></button-counter>% c; B1 \3 q( i( q
- </div>
) @/ U/ n' \1 z( ^6 j; u: K - </div>
1 z* v: t+ p4 x. Y -
3 E; s4 K: s* W" j6 H8 O - <script>
. N1 o/ u- a6 W5 a# G0 ^6 Y) z - Vue.component('button-counter', {
3 R$ j$ Q m2 Y: V) u# ~4 x, Y$ @ - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
% t5 N( q l. F; ~, N% R3 } - data: function () {2 [5 Q2 S3 o K* A
- return {6 I% e: m( B& ]8 h. F3 Q
- counter: 0: B9 a; e9 ^2 M# @% G
- }
/ \$ g; D& {1 d) r4 w& t# X - }, o2 o/ T5 p7 A. @: J0 `
- methods: {7 E1 u: B0 O: G# L5 [ i( b+ {, _
- incrementHandler: function () {/ U1 C7 |2 p4 [2 Z8 J
- this.counter += 1( f. E. Z7 D1 O, W
- this.$emit('increment')
1 c+ y0 t1 T' O: e) I - }0 ]; @. a. B# B0 r6 \3 D
- },7 y. b) K5 r+ q. ~
- })
% E5 l' V0 \* ~; p: R( B2 A - new Vue({
L7 S! @1 \3 t - el: '#counter-event-example',# g3 G7 a( X: N P$ h
- data: {
$ I; W, }+ a9 X5 m* V9 g( K" H, c - total: 0
2 d& l& a' t n - },
5 P" m+ Q% W5 F/ Z9 e, g( [ - methods: {
) u4 S# I. D' A+ T `* a" B6 j( v - incrementTotal: function () {6 l1 I2 H% r( a/ W; k9 N
- this.total += 1, b0 \9 W7 B* y
- }
' W* ]" l9 n! \( ]3 N - }, D4 S X# u8 @, Q9 p/ I' b7 j+ ~7 V# Q
- })
8 D; L9 V4 _6 K) g2 g; f - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册! P& y* V5 S& b2 A! ?# \
- Vue.component('child', {
, |0 e) E2 Q* X7 M - // 声明 props
2 C& l/ i3 u* {) l: P. S1 j- C - props: ['message'],3 ~$ b( X; f, V( M* U
- // 同样也可以在 vm 实例中像 "this.message" 这样使用( T; e+ n3 g) J, M C1 g8 A
- template: '<span>{{ message }}</span>'
" C9 e. i n0 N Q% `5 q - })
, ?$ M4 Z# l) L! N8 g* B5 Q - // 创建根实例5 \ v* ^3 ? G t. r
- new Vue({
: j2 A( n" e- o, ?* _% Z - el: '#app',/ G4 V) X, p' h
- data:{0 ]5 ?5 U# B5 j7 ]
- message:"hello",
* J' R4 B4 ?2 p - }0 B" G r. p. K& E& l: q* C" m
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
' l& g9 I6 m. p - incrementHandler: function (v) {3 f7 U+ l6 R9 c/ a9 N+ @* Z: h$ G
- if(v==1){+ p9 O* b! _- f' p' H# b
- this.counter -= 1
! r' j1 j' W8 ` V' n - this.$emit('increment',[1])
6 ?5 H9 |/ A& _! Y# j% | - }else{+ D* o* m* M- `% t8 g& m
- this.counter += 1# ?% e; t8 b5 x4 q2 @ F
- this.$emit('increment',[2])
E- |! k0 y* z! e( Z3 f- m( J - }
* }1 I8 G: T F$ T9 M( [ - }
/ t: R, @ y6 L' H4 x8 Q7 T) x- L - }
复制代码 5 t6 M1 p/ \6 j% [, B
: x# R! {! m7 ~7 ] |