|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
4 L* R7 P* j0 T- <div id="app">( q+ W$ Z' { w! f4 C) r
- <runoob></runoob>; b: S/ [5 \6 q9 B4 ?0 C/ G# z6 t7 p5 }+ \
- </div>
/ ~8 u1 E; l5 }) v% g O - 9 U2 e$ ^/ f9 o# |$ i
- <script>
0 |1 q" d# U5 g, ?3 E1 o3 U - // 注册
1 d" X. R7 J: N+ c - Vue.component('runoob', {
9 ` F) C2 }: }; U3 h% W - template: '<h1>自定义组件!</h1>'
; N' F' T2 F, g/ h% m0 } - })+ J$ A8 p' I7 Z2 J' ~
- // 创建根实例" c- A* |. ^" `7 b: t+ K; r, h( v
- new Vue({1 @9 q5 m3 |* F, [# z9 u' Z
- el: '#app'
' e) [3 _' Z& q1 g0 v6 _ M$ E - })5 a" u( D5 v9 b3 |' N0 e% m
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: " h- m8 g" ~8 V I9 f6 K
- <div id="app">8 B$ t" n F2 U4 X/ H
- <runoob></runoob>
" h ]" v2 K# ^ - </div>7 L; i6 y6 k5 v7 C
- 4 s9 U, v& N3 a$ X6 E$ A
- <script>- ?. r3 \ B. {* @7 R
- var Child = {- {) ^8 I i. _4 M1 f
- template: '<h1>自定义组件!</h1>'
! Y2 ?# M* i8 x! y2 b' @ - }
$ s3 P; \" L) i! ]- M5 k+ l5 Q -
8 f& y0 E; B# c5 L6 a4 u! f: c; c7 m; K% f - // 创建根实例
/ \9 N& E0 ^" B8 _% o; ~9 \6 v - new Vue({# K: K: v H: o: v+ |$ F
- el: '#app',
8 R! E+ K. e# P; f1 K - components: {
' P. p1 e( F0 \ - // <runoob> 将只在父模板可用: R' s( Z* V0 S6 q6 I# g5 W
- 'runoob': Child
/ [+ ~( R( @* I% V) O - }) Z$ G8 z) n% ~+ I B
- })8 ?$ e- l7 T+ i1 q/ t
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例5 Q( t/ z; e2 T% `" o" l+ @
- <div id="app">6 a: I, d2 z5 R% D4 p' n Y
- <child message="hello!"></child>
; ^8 B0 t' {9 `2 h, W3 q1 ` z$ a - </div>
- V9 S3 r6 @7 \2 M. u, @ -
8 ^; Q- T+ V* I9 X' c# |, ^ - <script>
2 W. ~1 L! Z( @) ? - // 注册
. w6 `4 Z8 B: `2 ~/ }7 g - Vue.component('child', {8 K1 k) |4 e' s% o5 m1 O' G7 J
- // 声明 props1 @) T) a, K8 H. q7 s
- props: ['message'],% w/ S) B7 \& I3 B+ l
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
: t. Z$ Q& J7 ^8 m R% C2 @+ G5 i - template: '<span>{{ message }}</span>'
* Q: Z6 p1 L3 Q* k9 v0 V7 Q! `+ w - })
E) r5 _7 y1 A, i& G% G7 H - // 创建根实例! ^# e- t I% y$ ~( Q L7 l# T! `9 R
- new Vue({
$ m ^# ^( u" o0 }: B - el: '#app'
4 c/ W& G" i- ~: g% s$ n% {: H; \ - })
3 w9 L" ?. e$ b& U2 C0 o! E7 V - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例$ W( s; v/ x( ]9 Q$ \: a
- <div id="app">' S. E' j5 f5 n9 V8 M
- <div>
, n. w) H/ N9 a% e2 { - <input v-model="parentMsg">
0 f7 b' C2 @2 S7 i; S& w# q. M - <br>
* m" U: v. a2 h& t! B1 _' n - <child v-bind:message="parentMsg"></child>
- I& d2 p+ x3 k6 P, N2 a+ j, f% S9 l; J - </div>
1 f" u0 L% i0 I" V- S - </div>& x, h% R, k+ ]! g _ P
- 7 U- p1 M% E, Y) j
- <script>
3 S: _+ i4 t' A& c - // 注册
1 E$ ^6 F) S5 \# g" H - Vue.component('child', {
* X3 v o, Z0 M9 K, r - // 声明 props
, [' V3 X' u: m& q - props: ['message'],
/ d9 i1 ~5 q7 H1 T" }! O - // 同样也可以在 vm 实例中像 "this.message" 这样使用
/ A4 C" r5 H( w5 |3 L6 ~& b+ C - template: '<span>{{ message }}</span>'& K& {6 j4 Y4 f. b0 A# W
- })
$ _( a0 C4 Q. Q! T: K - // 创建根实例
- p/ u, L- a3 a" N+ t- g - new Vue({8 u- {; {" G5 l' x0 Z2 z# P
- el: '#app',) Z9 p( S6 O' N+ m$ V x$ K
- data: {6 i5 w$ j% f& P% S" k+ P3 B; o# S. b
- parentMsg: '父组件内容'
6 G3 K* n$ h# w3 o7 ^ D3 z - }' b2 U, L4 { E7 i8 e
- })4 X8 N# c7 Q; V6 L% i
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例8 B a( Z# B0 {# `$ A T
- <div id="app">
& @6 u; f+ K" ^, @ V( ? - <ol>
0 C/ y6 X+ [3 e& f0 f* E, ] j - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>0 H' T& w# X; f0 d8 K
- </ol>) f0 F$ G% a6 C; ]: ~0 @
- </div> m, y& G3 R& p( J/ i/ w
- ) ?( |: J+ Q( N" s
- <script>
3 ?6 b* h! ?6 r! k [5 f - Vue.component('todo-item', {
5 }# n; O# E k; } - props: ['todo'],
" u' U1 j Z: d2 _4 y - template: '<li>{{ todo.text }}</li>'3 s; Y2 j) u; g+ o
- })9 J' x$ X/ T r9 u0 G, Q1 P
- new Vue({3 d O5 N7 m, @) K2 o" f3 Z$ @$ ~3 ~
- el: '#app',9 \% h3 ]0 [) K
- data: {; H1 p) N( b: C& C2 p3 J1 u- t
- sites: [
$ v3 N' j5 g' T" d9 U - { text: 'Runoob' },
8 A6 s) }% y. Q$ T2 }# e - { text: 'Google' },# Q. K& H8 ~* s" ^7 S5 t
- { text: 'Taobao' }6 f$ m, j3 d, ~' E
- ]
2 C! `( d3 x6 Y6 G A - }( I$ }) Y. E% c" k3 L
- }): [1 B3 u: X* e; M- r- N
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {6 ~3 O6 D9 @1 G6 B" Q
- props: {* s+ G& c) F3 A
- // 基础类型检测 (`null` 意思是任何类型都可以)
$ `# I- S4 q8 G9 a! Z) b - propA: Number,
" ^7 R Q. c, [& |4 L. ` B6 v6 L - // 多种类型
8 [6 G" ]* F4 x9 H6 m/ ^ - propB: [String, Number],
/ O6 E+ y1 \9 H8 H/ U& U - // 必传且是字符串6 @; |, I; d5 V" U3 M b
- propC: {7 c* \$ `9 i: h. P8 @: Z
- type: String,( ?7 M/ K5 }% S4 Y1 D$ f
- required: true% X) s0 m+ }- v! t2 L1 ^
- },
1 `% a& D6 U8 `* H, ~/ ~+ f9 v' O - // 数字,有默认值; R1 F8 H# {# z2 J6 T
- propD: {
4 s) d% Z3 W! N$ E- O0 T - type: Number,7 y- H% d- L q$ {; p& f9 J" B
- default: 100. _: ^; I$ l8 N$ k, L5 j- [3 G- }
- },$ [. t" ~; i: U7 U# Z$ d5 r/ E
- // 数组/对象的默认值应当由一个工厂函数返回 ^2 _( U) p" ]& @. L0 N! u3 i
- propE: {
& W1 T3 C1 J# j; x - type: Object,/ Q9 W" a$ Q5 O+ `; i3 q
- default: function () {
5 X" H% P+ H0 `. y. \9 ?3 j$ _ - return { message: 'hello' }) X w* G( J- t8 ?* D9 ?8 T U
- }
" d/ w" C% l7 z: i - },- T: P: t |/ @- ^* A3 x
- // 自定义验证函数0 ^ w6 ]% k& D/ Y1 {
- propF: {/ o3 e6 W$ ^% a1 @! n
- validator: function (value) {
5 q7 f0 o4 u; _4 m: V - return value > 10
% y% Y! v! Z) |' h7 \3 b - }
d5 G- N, @" d. j2 T9 h. h - }% t, R1 o7 c' Y4 K) |; c$ B
- }4 ]& c* O4 x+ J
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
/ y9 a6 e% j* o/ v: z( W1 u
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
+ V& G0 t% T/ u: \2 o( ?% d
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例7 l$ g0 X" n! n0 `% ]
- <div id="app">
, `. }# h( q' T" Y% s0 X9 j0 g - <div id="counter-event-example">
9 |$ X+ [6 o% m - <p>{{ total }}</p>
9 A1 A9 d9 z- D, j! e - <button-counter v-on:increment="incrementTotal"></button-counter>
: k: P9 t) O6 C - <button-counter v-on:increment="incrementTotal"></button-counter>4 v7 b4 o: I) h4 }" Y# d
- </div>
3 T# e9 N" [2 y8 f- t- _- \, K - </div>: F* n% B4 j( f: L
-
9 ?: i7 p3 S5 @9 F, A7 H5 o8 e/ | - <script>
( W! `5 ?+ Q( G - Vue.component('button-counter', {
5 o7 G* v- b0 y8 H4 |% k4 d, R2 p. H - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
% r; o& N) ^1 P - data: function () {
; }/ L% x% i" i: t - return {
, R4 x6 g$ n' D; m, x9 \! R - counter: 07 ?2 c& d% g, P# M9 _
- }1 h& T( m! q# g0 H
- },. e Q1 ?0 K# \9 J" ~" ?) ~
- methods: {
0 g+ N, y4 ~3 {( `3 p - incrementHandler: function () {
$ O2 h7 S) ^* h8 p - this.counter += 1; c1 N% F7 G! v: W# y
- this.$emit('increment')5 ]- D" J. U3 i' n0 O
- }
- T2 ^' D, g) o4 \* u - },
9 n( Y# A* e+ u - })) ^0 i% A* z" ^2 v
- new Vue({
+ z" \' h+ j+ ^' d0 F+ X3 F - el: '#counter-event-example',
! y) n* u1 \6 o+ E+ G - data: {
. y, H/ u" m" O1 d- f; G - total: 0$ R2 q" |$ h1 s" n
- },2 p% {6 t$ J' Y' j
- methods: {
E* s7 y) I9 G/ F$ ?6 H \1 F - incrementTotal: function () {" ?& h2 P2 \/ h+ `% O
- this.total += 1
6 {7 Z- J* F, B, D - }
1 O0 ]4 @1 O) x7 w - }
! a* x; e6 \. c/ ] - })
: l( K ]) H) z. V4 R) e6 m+ r - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册1 Z* U1 Z& z2 b9 V* H8 {
- Vue.component('child', { [5 g: z( G6 n
- // 声明 props% n. ]! P) h9 V& K5 o( X4 P5 }
- props: ['message'],
( u/ H5 _) r0 _3 U - // 同样也可以在 vm 实例中像 "this.message" 这样使用
8 Z* b( v/ W |, W# ?6 t2 H4 \; V - template: '<span>{{ message }}</span>'7 `4 U7 s0 l6 B6 y
- })0 X$ l0 W) ?0 t; T( c& @! K* @
- // 创建根实例% g7 c- D5 \" s# \$ I
- new Vue({- s0 O8 C4 T9 t/ O- L& [0 i
- el: '#app',
* a# q8 J% }( c! n5 F9 ~ - data:{2 v! y' p9 _! X) d
- message:"hello",8 O. a) i' d: o' E3 i5 A$ ]
- }( r0 D: Q( T+ [5 ]2 S
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {5 E m. ^2 q8 i5 B
- incrementHandler: function (v) {
9 I7 m9 h- y- D# U7 h6 Y - if(v==1){: r8 H+ ?- ?/ K0 h4 c- F
- this.counter -= 1
6 S: Q+ Z% ?6 x: H3 }$ U: D3 h - this.$emit('increment',[1])9 P) w5 G X% z& U
- }else{
; E0 s5 _' _, ]; k* L9 R; x - this.counter += 13 Y0 ?6 L: ^9 Y( O: Z
- this.$emit('increment',[2])" t% N. s, l3 m/ I$ S8 e) f
- }* t1 J3 w7 }: q7 a" U& ~. I+ w
- }
5 l4 I" v7 x6 Q; w4 V+ M, ^: A3 K - }
复制代码
, A6 W: a+ g! i0 U$ a3 ]8 M
/ }1 B0 X8 m2 e |