|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
& X) T' Z" w- n' g- <div id="app">
; w! a; _9 ` d9 I - <runoob></runoob>) l8 k v, a% U8 s; X* x8 L( r
- </div>
; z; u) U8 c. z5 B2 H# ]8 O - + z; |2 G7 l+ K) }) s
- <script>" q) |3 b/ V% k( S, L8 I5 d
- // 注册
# P: F1 z3 x0 W - Vue.component('runoob', {0 F) v" d; ^7 b f4 {
- template: '<h1>自定义组件!</h1>'
/ ^& M: h% m; u, q0 x - })
* U6 D/ Q0 U, _# R - // 创建根实例& I4 d6 i1 g: e8 G
- new Vue({+ @/ F, L9 S& y; ]! e& Q
- el: '#app'
( ^" S) O& g; G3 P7 o5 w# k - })
$ [; W" B9 h& z1 } - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: 7 X) @) v& o7 y! h/ V! E4 Q' K
- <div id="app">" n% s) ?- h9 F
- <runoob></runoob>+ c. X! S# W. k) L, G
- </div>
( ~3 q. }% Q5 j7 W$ S6 k - ) G* u) z% l# R- K+ l! s* N" {
- <script>4 I \5 W! `8 o% p7 I$ e# ]
- var Child = {
' M$ D" w5 `- v, H- W - template: '<h1>自定义组件!</h1>'$ J: ~$ x4 o0 c- H' _5 |, _& g8 q
- }2 g @" h2 O. |, j5 W5 F' R J0 R' Q
-
$ z9 |2 a. S' U8 ]2 U2 D - // 创建根实例
9 M$ J0 n5 n5 a% Q" ]& B" v, i - new Vue({
* i, O1 @* r3 n- u/ n, _ - el: '#app',! D" F5 F# A7 w& x" u: f( K
- components: {& m( @# m8 \8 Z2 i
- // <runoob> 将只在父模板可用. ^+ _$ g+ ~8 f8 P8 a
- 'runoob': Child9 y* U7 d& J) f3 j& U' a
- }
1 H- l& b1 o, V0 | - })" _6 }9 b5 p( x
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例5 z) A( y: p2 X/ o* h, h) L
- <div id="app">
; V; Z3 ? H4 R% ?5 y' y - <child message="hello!"></child>
& ~( @+ L; C+ N! `5 } - </div>
1 M& S7 T% L$ k7 w$ A$ W - % }# _- E+ Q& Q
- <script>
5 r7 s1 j- q. C - // 注册/ @+ v, F, }- P& R9 r) K7 H5 W4 P
- Vue.component('child', {0 Y0 P" G: |; J( k9 b2 b: {6 ~" C# W
- // 声明 props/ z9 A# w& o8 X% k5 J' o2 ?
- props: ['message'], B: Q% u0 M: u0 ], v: k
- // 同样也可以在 vm 实例中像 "this.message" 这样使用0 m) C1 Z& b: E: O4 [
- template: '<span>{{ message }}</span>'2 w$ J9 _ ?! T
- })2 i {5 q7 G9 I3 T
- // 创建根实例; F, O- i8 E& b, g; I
- new Vue({$ Q. l2 M3 }! D3 W0 @2 \6 V
- el: '#app'
" }/ ]2 f# h; u. G& N3 V - })
5 _' {. G' Q& E; c+ |" Y& }' ~ - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例1 o( X% s8 r! P9 W2 b9 b8 P5 f
- <div id="app">
" n8 }- v0 h/ [: p5 H9 d - <div>% B3 i2 D% O: p5 P7 h
- <input v-model="parentMsg">
# G3 s" e. g! G0 W1 T - <br>
E1 V! K4 c9 K# K& Y6 | - <child v-bind:message="parentMsg"></child>2 |' W1 @+ M3 M7 J
- </div>+ \8 b( d* F! G* r/ r0 R
- </div>
8 \0 u0 m L1 T2 u7 X' S4 b$ n - 4 J) k/ b3 ]- b
- <script>
) {5 v7 s- q0 D, V- n2 z1 l/ Z - // 注册
# o* U l6 |; I1 @ - Vue.component('child', {
" P9 ?3 Y/ M+ u$ [ e% N% I% D/ Z - // 声明 props
. ?" ~) O( j1 t, X# e q4 L4 f R - props: ['message'],1 _- ^8 f1 M- f% x0 [
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
& i" P/ Y1 T1 ?- p% e - template: '<span>{{ message }}</span>'
8 A7 f' y5 \- Z H - })
. b* m; \# _' E- P - // 创建根实例
9 S4 m( z+ P2 p x- V - new Vue({( B* w5 P" k1 a: F! b4 j! v0 u1 `
- el: '#app',) B# r3 M) r/ N1 Q( S# }
- data: {
4 \- P6 f2 q; h* M' C2 _; M$ P$ I1 S - parentMsg: '父组件内容', `, s7 z( ^" h
- }, ]5 B. r3 Z- m; C: X" P
- })
' I( w0 a2 y" h: q - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
% j/ ]6 T2 r7 y/ T* o. h- <div id="app">
+ ?' _! a6 |, \$ O - <ol>6 E0 J2 S6 D' l8 m
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
) S* |6 c! k8 u w - </ol>
4 P$ S/ C" b- R2 o - </div>
& [- X: ~. T, B - 7 c) l4 q7 d2 ], S C
- <script>
) C3 ~0 m6 h0 S" e - Vue.component('todo-item', {
1 q; }' r9 ~; s6 u: c6 C0 a& U0 A9 e - props: ['todo'],, d- c* @; Y: Y/ S2 W0 E
- template: '<li>{{ todo.text }}</li>'. y, R" }) _4 \4 j1 D# Q4 o
- })
5 U8 j: t1 W/ [; X8 |+ n4 K: w- O - new Vue({2 Z- h+ f0 t7 B$ | Q
- el: '#app',
1 v+ G3 \- \) N* Y/ x U: o - data: {( _( x c6 A) g* g5 e
- sites: [
1 `: k8 T, n. [: r, g& q$ ]6 x/ m - { text: 'Runoob' },
}# [3 o A* P5 Q; g$ }$ D9 j - { text: 'Google' },
5 {! B; y7 g# F$ A( R - { text: 'Taobao' }7 {) J2 T/ n/ r% k& k& J
- ]
2 G3 V: v+ X: {6 } - }% n8 A* P5 ^: t0 E: j) c4 h
- }); Y7 ^, i9 ?, n* [5 K
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
" P$ i) w3 K" ?9 m - props: {
% Z( Q9 v1 C. G8 Q - // 基础类型检测 (`null` 意思是任何类型都可以)5 C) @9 z7 A4 e w
- propA: Number,* Q& q& e7 J7 t( S# f. L. Z
- // 多种类型$ O# P. L5 z# ]7 j1 m- u
- propB: [String, Number],
: z) q' D, ~9 H9 z! l6 p4 s. I - // 必传且是字符串( ]& s5 a" l; S8 ~+ P
- propC: {8 V3 P0 M, B) w% p: y- T# a
- type: String,: C/ N2 r& g) c) Y, u$ ~
- required: true
3 t2 H* G5 p' Z& K& S2 W - },- D& J+ E: m2 y6 F% F
- // 数字,有默认值3 h; ?) x+ [5 y1 d8 [2 {* u
- propD: {3 w! [) e6 I* k6 L
- type: Number,
4 B8 H( O! J4 r1 ^2 W* ?- G2 Y - default: 100& h- B) B! M% H3 b5 n: l6 K6 Z
- },+ ?5 \. m! `1 O, t- l
- // 数组/对象的默认值应当由一个工厂函数返回
6 A2 Q" ~2 I d9 \ - propE: {
- `, g7 m% s/ D8 [. n/ p - type: Object,/ e, y2 K! C$ G: X- `1 y
- default: function () {9 ~ \4 y$ B; X
- return { message: 'hello' }
8 M1 o* j6 b) _' N - }
5 M- C r; d; u- K3 N0 U - },1 M, \2 S" @# ~
- // 自定义验证函数
+ ?7 w% j& C0 d& t! P - propF: {) L8 S0 @. [. ]! n' F
- validator: function (value) {$ w5 {. C6 \" |) \; z
- return value > 10' }9 T# }$ P2 u1 P" I
- }; Q$ L6 Y' k( D
- }- }7 j6 b1 e4 p0 }# H) u
- }
& f2 f( }) t, C, A - })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
# t8 b4 g3 w9 n. H V, B5 i
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
8 p1 Z! ]0 D7 u
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例1 S3 d# d$ g, U F1 l+ n) }; p
- <div id="app"># v0 e' K( ]3 T3 q1 W# M
- <div id="counter-event-example">
$ ^/ `) W$ ~* B8 A9 I- P - <p>{{ total }}</p>
* l( v% s1 ^! H( E - <button-counter v-on:increment="incrementTotal"></button-counter>: t: h: v$ n: Z# P
- <button-counter v-on:increment="incrementTotal"></button-counter># p9 C# N! N$ z0 {, i) }5 p+ C3 L
- </div>. L$ [) Y+ Z8 i7 M# c
- </div>4 L. {/ v# z: C! A
- 8 A& v i$ @& r7 |. Y4 I0 T; `8 u/ ~
- <script>4 \1 s# l: q5 r: x
- Vue.component('button-counter', {
; d5 d; j2 T; {: S2 m; t - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
% J! e( A0 [: o8 Y( J P7 n - data: function () {8 R3 G5 M/ K/ h; Z( T' C
- return {
" `/ E* W! c" W# G4 K; } - counter: 00 c' A+ }3 l; ]7 X1 \
- }( A; _* H$ i( y1 |, s' k( W; x8 U
- },/ a$ J% B; t( @; _* n/ S" @; D
- methods: {; ~6 I1 V1 p1 z, j6 v
- incrementHandler: function () {
' @1 ]$ {0 a- a - this.counter += 1. q t. r& x* L3 [
- this.$emit('increment')
, {7 A% u: f+ n# _; O0 c, g9 g' L0 b - }$ I* l9 n5 L9 d4 r/ { }% i
- },6 x, B, W& o3 u$ S3 I% Q2 k
- })3 M! S( T) n& a# p& Q% X" a0 }1 w0 q
- new Vue({
# |# ]* W- h; g' J' ]8 s5 O' G9 a - el: '#counter-event-example',( j1 f1 M: X2 z* O7 E2 S1 ]
- data: {
" X) C$ p6 Y7 A" e7 g - total: 0
' Z( D5 ~( b! G* H - },, @& x- q' M+ \8 Z
- methods: {1 ~7 X" J: Q8 s5 d7 o# R
- incrementTotal: function () {
+ O4 B3 o5 } S( P; |7 ^+ ~ - this.total += 1; G* K8 Z7 r8 p& y5 ?. p9 \
- }
0 ?, @- C! X5 {- l7 N: Y - }
3 v% s2 {9 ]; B: p" v" C2 ^# D( F8 G; B - })6 S/ g8 B. A3 x9 W& f8 `( y4 e
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册2 K, m Z( H3 b# `# P
- Vue.component('child', {
4 l; }7 b- L @8 ]: W, k* C! w! Z - // 声明 props$ X% Z7 R: a. w! w
- props: ['message'],! |/ V4 R8 N$ O# t% b0 [# N
- // 同样也可以在 vm 实例中像 "this.message" 这样使用/ J! `! |5 G+ h& F7 b
- template: '<span>{{ message }}</span>'
+ V- j1 [3 X8 I, r: v$ g - })4 Y- A. h+ u/ S# y$ _* \
- // 创建根实例 z9 w9 w4 ^2 H; u4 g
- new Vue({6 Q! `' p! r; x O
- el: '#app', L$ f: V* ?/ Z# ]# p
- data:{
! R# x; i) k% J( S: s$ x - message:"hello",6 p. B( c' K7 l" \3 Y+ w0 ~
- }/ z8 a" F. ^' z! N: \) j
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
2 y. N% J9 K# d# q9 G: v- k - incrementHandler: function (v) {7 F# F/ n5 o A# O* Z3 H) j6 l# T
- if(v==1){" Z! ^5 d, m4 I
- this.counter -= 1
9 J2 v+ [3 e! k6 [3 [. w! ^ - this.$emit('increment',[1])
: l# _) I7 O8 D: t5 A3 k - }else{/ H7 }! R5 ]; ? b% P s% [' H# t
- this.counter += 1) _, {) s/ |- e% A7 {" G; x; s, d& ~
- this.$emit('increment',[2]), u4 E2 O" m. _6 q+ k, V
- }
! w: h% Q' u* Z+ U - }
: d# D$ U) r0 o ~& c - }
复制代码 * _2 a3 E$ Y; \, L9 x
9 }' \0 {1 }8 z* |" C+ i
|