|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
4 V/ u! {& b9 h: [, z3 ^; E- <div id="app">
+ H1 P2 Z- w2 d: x- q - <runoob></runoob>5 \" g+ t' `: j0 P- p: c( H5 F
- </div>
- _6 X1 [- f- @7 F9 u4 ~! m- [' o - ' m y9 r8 V& v+ x
- <script>
2 B, n/ s8 i5 `. O - // 注册
6 v4 O9 J- ?" b- i" | - Vue.component('runoob', {
2 l# m& p. X A9 I! d - template: '<h1>自定义组件!</h1>'- |6 [. l9 g% V, w
- })
# B r$ N# s& ]1 _: e3 m. H; \% t - // 创建根实例
$ D7 R; W2 z5 T5 R$ B - new Vue({8 E: e8 l; P8 q7 D0 W
- el: '#app'8 B H+ v: A, V8 I2 n
- })
: ]. E6 |% x8 n x - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它:
0 X' B; _; x8 X3 H: i- <div id="app">
3 b/ ]' n' o& [7 l: X - <runoob></runoob>8 d5 g6 D& R7 z$ M" d5 `
- </div>
+ n3 t# V e# y# y -
# h+ O: p2 j% [: y7 H - <script>
6 [3 S, P/ r& T3 q' H# X - var Child = {
! W+ c. U+ Q$ c1 M: k: { - template: '<h1>自定义组件!</h1>'3 g. o+ S* D" D/ K+ z& Y
- }4 h+ v1 L1 Z2 z, d+ S6 D
-
" |( C, q8 R" k3 q" N# r [ - // 创建根实例
) Y* Y: U7 O/ a6 O- Y$ {3 O - new Vue({
2 G) c, s, r' m4 |2 b+ p- Q* B - el: '#app',9 R' K% A# `% d* e" y
- components: {
( L8 q3 e3 Y9 p s. @ - // <runoob> 将只在父模板可用
, r' W& a6 H' l4 H. t* V% o - 'runoob': Child
' I* \' B$ C c - }
/ R- y# X( b }! S1 I5 z - })8 @6 \; f7 _) w# ^1 R
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例8 ?; F+ |# d3 }" K
- <div id="app">- @1 q A ~3 J8 V$ [+ b4 B& J
- <child message="hello!"></child>
~! m+ c4 o' q& K" Z O - </div>& U: y# T {1 \# N" j4 j
- . ^6 ^4 ?! l3 O$ P& t
- <script>
4 w+ A0 ^, K2 M+ Q - // 注册, c* M9 e' K' x( G3 J0 c/ k# \# C2 n
- Vue.component('child', {
7 Z8 v8 \& }" a& C8 \6 n4 d; ` - // 声明 props' m% e* c9 Q2 V1 O; O5 n
- props: ['message'],2 w, G& @. h4 p
- // 同样也可以在 vm 实例中像 "this.message" 这样使用9 _% L2 V3 c9 J# L7 y
- template: '<span>{{ message }}</span>'
% ?9 s, M# X' T3 f" |/ F5 ^ - }) N6 U( F$ {2 i. e4 q% t: p+ ^4 g, \
- // 创建根实例
6 q9 W& D7 r0 q0 n( C, c3 K - new Vue({/ [( O5 S3 u1 a, {* w
- el: '#app'1 n: y3 x5 C: k# B2 r: P
- })
: v. f4 O3 U& V& q' y. y- G - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例7 X6 I! a3 Y2 ~) k
- <div id="app">
6 h9 z/ Z7 ^& O9 G; V9 f - <div>
7 Z% F/ ? @6 x0 @) P T* ? - <input v-model="parentMsg">
6 u- g6 }# W6 t, V; ^ N$ W9 t - <br>$ H4 p+ h# k$ ?; t& z5 G
- <child v-bind:message="parentMsg"></child>
7 C* P2 f3 }7 u2 Q - </div>
: F' G _2 J3 e+ u- ] - </div>
* B8 z/ a: n# s( H5 z -
2 G) s+ L4 p' W& }9 ] - <script>
, a" [# x) z m, P - // 注册4 H' V2 _" I! M* D% L% P3 i
- Vue.component('child', {0 x! r7 W3 B( {4 {& u- C
- // 声明 props# O% q: n! I" Z* D
- props: ['message'],9 e% K$ a1 J5 ~6 i+ T# U
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
2 B: ?( ^, k* W O% ?+ } - template: '<span>{{ message }}</span>'
T# X' [7 \: r% g+ B - })6 K# S( K! }: q' A, @
- // 创建根实例
$ E! G# Y3 y7 Z3 g7 e8 n - new Vue({; x% w1 s- _3 L& @
- el: '#app',1 \. x1 R. }( e5 k. A& r
- data: {
$ _4 m k7 h- i0 F5 { - parentMsg: '父组件内容'
) a/ s" S% O& o9 \! m! n - }6 x# C( V/ y8 d
- })8 a. a1 E4 ^+ t
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例" f1 k3 Z; k; G, z# `$ q N7 [
- <div id="app">
4 ^/ ?: b" w! U - <ol>3 u! t M! V2 Q' h
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>" Q3 K: G& `$ {6 z4 ?1 Z
- </ol>$ W1 t4 M6 y+ F7 J1 ^% d
- </div>
' L7 q5 [) o8 m, Z0 V+ R, G9 i - - ~% W4 H4 n. X3 ~8 u* y
- <script>3 P9 v1 ?) @9 O% [( [& i; w
- Vue.component('todo-item', { g h; E3 ]: ]+ c3 Y' R( ~
- props: ['todo'],& W) P) T9 G# j: o, C3 W
- template: '<li>{{ todo.text }}</li>'! j! V" X5 z9 x: @* I7 |; k
- })6 q: B _7 ~( W
- new Vue({
1 u5 C% m* _! Y6 }+ O @ - el: '#app',1 L, N8 I" g2 @! v
- data: {
( Q, X( C' x- h3 K" ?/ c( K - sites: [; x+ `! ~6 \3 \6 v6 {& g+ Y
- { text: 'Runoob' },
! [& h0 ?8 Q. ^3 }0 `* ?6 t - { text: 'Google' },
" p+ @) _0 T. \7 B# k - { text: 'Taobao' }
+ M* J1 _7 N6 j0 E - ]
' }- z! m. w1 f6 Q5 V" k - }
) w& _& z5 x% `( L, `7 a) |+ ^ - })3 u! A `, w" N/ b2 w" j
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {$ Q$ S+ D& |3 \# P# X
- props: {8 a# s4 \ F, b. C: z) H
- // 基础类型检测 (`null` 意思是任何类型都可以)5 C I7 f: K. n3 l* @* n
- propA: Number,
+ P. P: h; q/ y) d" j% C - // 多种类型
( }" X7 t. f, ~* n' z" } - propB: [String, Number],4 P: _& Q+ ~# ~
- // 必传且是字符串' Q' H" H- q, B- u
- propC: {6 k5 C* w9 ?4 l d' G
- type: String,. i, l! s1 L1 Z
- required: true# F; T" F1 R) i6 W6 S
- },
. N: D& R9 v; R, u% D# W - // 数字,有默认值
) L" ^7 V$ l$ y! H- `: ^ - propD: {
9 c- O8 ^7 y- D/ ^! t" v% u - type: Number,+ y1 N$ D& W" u" ^( @
- default: 100$ q1 a: I b, l% A1 X* p
- },, v* }) d6 u' v* ~/ j
- // 数组/对象的默认值应当由一个工厂函数返回' ~# m! g0 H# b1 B; k
- propE: {
: E' s' @9 k- Y" [6 b$ y8 _ - type: Object,4 r. g" l, I/ N7 f& q2 b$ |, G
- default: function () { P3 C+ W7 U8 \. A! Z
- return { message: 'hello' }
! z4 y6 L8 }, y: y1 Z - }0 {+ k) m9 [" _+ s( M: ?$ ^
- },* T$ j" N! X3 j; G' h5 r2 }4 {% I
- // 自定义验证函数, T& z9 J7 P6 `5 n
- propF: {( t: M8 D2 t, ?* _
- validator: function (value) {
9 G' u8 {! @# K1 c: j$ x - return value > 104 X8 Q. s$ E# V, l. v' w9 O
- }
3 ` _ Q n. }: M' X* l - }
% ?# o4 o6 m' y& s0 H - }
1 e% O w f8 h8 L+ I - })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
3 T* D- ?- r; |1 I& ?# G
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
6 M3 y T4 L- f* Z0 p3 Z4 B' \6 {
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例
! X; d. ?) B/ B6 h4 v: ?- <div id="app">5 v" k R) q% Z( K5 _
- <div id="counter-event-example">6 i2 Y: s! J( b! Z
- <p>{{ total }}</p>
4 U/ ?# a1 w7 b9 q - <button-counter v-on:increment="incrementTotal"></button-counter>
" q+ t# U9 } r8 S( @' ~; L - <button-counter v-on:increment="incrementTotal"></button-counter>
+ f* [9 ]# _% l4 ]' R' E5 A8 o9 z- c - </div>
[, ]$ R4 B; s3 Z - </div>
4 s' p; K# n' ?" z2 ?* I - ' j! ^( T3 R) {+ ~
- <script>
# N! e7 @( M% O5 i - Vue.component('button-counter', {
- P, m- i( F: ]3 Z - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',2 G* w8 u# A+ w1 \' E( l- [ A9 r7 X
- data: function () {) O! t5 Z, j% U
- return {
/ f+ Q+ x) J9 P" H3 ~. w5 o& d - counter: 0$ j1 R; u+ V( g5 W. D7 F* F( }
- }
- T) v1 U J6 W7 B* p- y) c - },) x( w+ s/ v& }# Y4 p3 |1 n
- methods: {
: K9 l1 B4 ^& y* b - incrementHandler: function () {
0 Q( O# T( S8 C O8 o/ q - this.counter += 1
1 a6 J: V; Y% G9 j4 C% p0 C; k - this.$emit('increment')
* g# k! q7 [& p4 W- Y, n - }6 b3 }" T; |# K. ~3 J" {* _
- },
. e! D U- Y" L* W \ - })2 @/ v. u* `8 Q0 Q ]- x, ~
- new Vue({6 t7 p5 B, y! D5 e9 y
- el: '#counter-event-example',& X) a, A) n7 z2 u
- data: {# s W; t& e( \( e5 D( M
- total: 0
( A- f/ y# j5 U3 _9 T4 s! ] - },
e2 ~, n& e6 f7 X' y6 r - methods: {
+ [$ d: ^0 i/ N0 A! B, W# t - incrementTotal: function () {. V5 K6 y$ C6 j& ]) U" S8 q/ C
- this.total += 1
( J" \2 k/ C, v1 H9 B# k0 T - }
4 f# X) w; ?" _4 v. o4 F5 N - }
6 K; {7 E: L9 O+ L - })" [: N2 H& \" q0 Y2 D% i
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
* f7 I/ M8 x1 z. G - Vue.component('child', {
[ R& U" ?& H6 ~0 V3 O - // 声明 props1 H! T$ t% ~# j/ ~: D
- props: ['message'],
* J- N) ^ R% }) g- x6 K! t - // 同样也可以在 vm 实例中像 "this.message" 这样使用; r0 Z1 n; [7 l5 r
- template: '<span>{{ message }}</span>'+ s& G; R- B$ s1 A: V) c
- })! j2 N I. A* w1 h3 Y) ^
- // 创建根实例5 R' i; S& n/ g# s( ~4 s- e
- new Vue({0 |. o" ^" g% h1 q0 L. V
- el: '#app',7 C J) _7 L6 p1 G
- data:{0 U k4 h; C4 o) V* f4 L
- message:"hello",
" z; l- g: `9 b0 u$ O7 d5 ]7 g, z( ] - }+ f. C# n$ R7 L/ ?
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {% n2 G3 v4 V4 z6 [; ^
- incrementHandler: function (v) {
) N7 n6 b4 B. V7 U - if(v==1){
# e; w) ]; S; ?! b+ @ - this.counter -= 1
0 P! C* c0 ]: O1 Z& t( i0 M - this.$emit('increment',[1])
+ M F/ G: c% D' A - }else{
. D+ W9 l. Z& g i/ B/ L7 p - this.counter += 1* E& x2 X3 _1 h9 Y3 V, K
- this.$emit('increment',[2])
0 W/ C0 V1 q. {1 P. ? - }
2 {) i+ a& J7 P+ O - } y4 C5 m# W8 h$ V+ I O( W" }5 R
- }
复制代码
/ E5 b" w" Y' Y' a& u$ _1 a6 R% Y7 M ]+ a8 ~$ ~% \4 R
|