|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
2 s) } p3 s5 I! P6 @3 \- <div id="app">
( ~2 Y6 E1 D+ S5 _ - <runoob></runoob>7 E7 v) _$ G7 M& Y3 Z# R! @1 h$ d
- </div>
1 c6 }: P4 s& m* W, c -
$ a2 v ^% h" `7 g j4 f - <script>
" ]5 r: G4 M/ `+ N6 I+ `( x8 x" o - // 注册. M* n: U# T- S5 H- I
- Vue.component('runoob', {+ u) F8 ^+ D8 W$ a1 A! Y3 G& {$ Y- l
- template: '<h1>自定义组件!</h1>'. U" o* c: z8 u( W0 K
- })
/ i& ~$ y: R( y, M5 t' t' d - // 创建根实例
1 q6 }1 z3 ^. \3 k- ?6 i, l; g - new Vue({+ I7 U9 c! v' p: \' }' G2 E
- el: '#app'
6 K8 w; S$ M2 g) R0 ^: n+ | - }); P: X& f: q5 [! P* G
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它:
* |. ^2 I" p4 L" k6 w' Z- <div id="app">
$ r+ k9 E% d: C. [ - <runoob></runoob>+ d( U! B0 `* P2 Z' d; \+ F7 w
- </div>
% ]% T* z) M2 V- P! E -
! b& }8 g* g- n v/ J - <script>" Q; F( n. F1 D
- var Child = {
. P+ k7 `' Q; S( o# |+ X6 h4 w - template: '<h1>自定义组件!</h1>'
) o; V- K4 S& o, v - }" A0 |' i. R* ?$ ]7 u
- & t. ^4 h2 {% o2 |
- // 创建根实例
; }# n" ]- s' ~) J3 l' G - new Vue({
k0 O. @! V5 r( T, @0 X, L& R - el: '#app',0 C- y, {# K2 \: N+ r1 y/ U
- components: {+ q$ k* X# d9 y' A+ k7 l' X2 h
- // <runoob> 将只在父模板可用- D; G* K/ E+ C& k5 Q( Z2 q/ g
- 'runoob': Child* J3 R3 [1 A) G3 g# B
- }
v" W. k& T5 y* O- c - })( J$ ^) ] _! m% ~1 ~4 C; P5 }# M
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例; j/ e. y, h* Q3 g7 |* Q( Z
- <div id="app">
1 Q1 F# P5 ^" D, ?; U7 f - <child message="hello!"></child>
9 N8 `! r3 n1 u - </div>
, W$ a3 u* Z+ \: r3 m6 M! V$ ] - : W9 r8 n- K, I6 k* ^
- <script>4 G2 L2 r. h, p8 G
- // 注册
, ?) r/ t! @. ~' t1 k+ g - Vue.component('child', {
8 H) s3 ~5 }# D$ t: m+ P' v - // 声明 props( t) O9 t, k6 k/ _, ~
- props: ['message'],0 ]. O( E: b4 L/ g* s" p
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
! {& t, }& ~$ x3 }! [; H) p - template: '<span>{{ message }}</span>'
1 z, D( \4 M Z2 d - })& a- `7 X/ I" u. V {! y2 v3 `. D
- // 创建根实例: s$ T; C5 T) b
- new Vue({) n* @+ C/ X" m1 u/ H, e
- el: '#app'% C& B8 B; T. q6 x. A& A
- })
& s9 p2 H7 q: ~- Y) u - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
$ K$ e/ X) |8 |/ W! r# G. [. x/ |7 X- <div id="app">
$ ? J' b* d! l4 N- Y" R - <div>5 j# v/ ?$ ]" x7 [ z. }4 R
- <input v-model="parentMsg">8 D9 {* v; m) Q! q1 f' ~. Q% b7 S+ g
- <br>/ ?" @* o' C/ O8 o/ d! \6 q) ~0 o$ X
- <child v-bind:message="parentMsg"></child>$ J; X, Y j% }
- </div>' `- M, a( ?5 X8 g9 z6 C
- </div>
& y4 v, `! r4 k/ Y, w -
9 ~! N# @2 P6 M2 \, r - <script>
5 Y0 Q3 @) _/ K- i0 N( U) n9 J S - // 注册
+ r: x5 @# ~- D8 Q$ y: w/ j7 B- O - Vue.component('child', {( u- @; c' a) E6 L+ z1 x" f- a
- // 声明 props
2 w+ ?! S- n( b# G - props: ['message'],1 `$ i. C! I5 H0 i+ I" A+ q1 P
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
7 a/ a1 Q) g R - template: '<span>{{ message }}</span>'8 _4 t7 F7 P7 Q
- })) y3 t, b2 u1 ~% `' Z
- // 创建根实例
& K/ S* V* [" K- o/ M! z - new Vue({
+ ?: C3 I+ o1 Y) `& F - el: '#app',
% f6 j1 C3 v8 |7 S: l1 p - data: {. t/ D' k9 Z; T* K$ |
- parentMsg: '父组件内容'2 q1 @1 H& i$ u; X$ o! g( v' x
- }
]* p3 o( Z) h# @+ k8 B# F - })5 }! U2 n5 |& T- U& k' U8 I
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例" ]( t, w$ N$ a6 d% e) ^
- <div id="app">; u: b- J* `' F9 v
- <ol> g9 H% e! a0 n: M; t) E' z# D
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>/ q4 g* {/ }9 W
- </ol>) o( I4 E* C# Z- ]9 w
- </div>
6 I, K9 h9 a9 J9 `" T) q2 ~0 h: w - : W/ S+ M7 H& q0 ^
- <script>3 `6 W5 M) l9 U' [% m( J% q7 t
- Vue.component('todo-item', {
4 t1 Q3 N; x2 x f; g - props: ['todo'],- L8 a" Q! f( s5 P4 ]4 n Y
- template: '<li>{{ todo.text }}</li>': l Z) I! L) [3 R- v3 U6 n
- })
5 _& ~4 r7 k3 Q) V" S - new Vue({: M; _8 W6 o8 j% @: l
- el: '#app',# s2 j0 {& G4 ~$ f
- data: {
9 ~; y3 S4 T2 k- j! S9 n" X/ F( u - sites: [/ o1 J( q! }# S0 I/ @" q% D
- { text: 'Runoob' },
6 @9 ~5 B9 l( c, ~ - { text: 'Google' },( W/ _) b$ G* t4 m
- { text: 'Taobao' }
1 Y$ }$ j, t5 T' f, O - ]
# c7 k5 T( F, l. B7 B - }' L& ^& E7 c0 v! q$ L
- })( J M' Z3 U1 a- p& F
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {; ?, E% W, l B3 Y' H. F( G
- props: {
1 f2 w! t5 V3 {! @ - // 基础类型检测 (`null` 意思是任何类型都可以)" ~' ~$ o. {2 d
- propA: Number,
$ G u w7 z4 }3 i# Y - // 多种类型: [# h$ Y3 p1 K3 _' {( |8 a9 ^
- propB: [String, Number],1 f/ j( U$ c! w7 t) s
- // 必传且是字符串
- |+ ~+ }* h& T5 L" c- j - propC: {
% h7 a" D$ b( `* j- _ - type: String,2 d) v, d7 X! i
- required: true
2 ^: h$ W( Y$ M2 w! |0 \, p2 @1 u - },
1 A- j2 h5 r+ Y: [ - // 数字,有默认值2 i" h x+ E6 T. q
- propD: {; W1 L; P- r2 [; H. @
- type: Number,. g# s9 ?% E" ^) h; [8 @
- default: 100; f2 ~- J: b% S# e A/ Y
- },) G% D7 n6 W8 {$ W; C) n
- // 数组/对象的默认值应当由一个工厂函数返回2 R+ s4 q# p4 U! }1 H! v: o
- propE: {
$ Y9 z- C( z5 F! A5 }% q7 z - type: Object,$ }2 I) `6 E9 Z
- default: function () {
) b2 Y4 U1 D& d% p( G0 y6 K& J2 ] - return { message: 'hello' }% E7 t7 U6 J' k- o3 R+ G* @; O8 r$ B
- }" n4 k% P* f, W$ A& V8 u. V4 U
- },$ X0 p; f+ G! D9 c5 H; L- J" n
- // 自定义验证函数; z7 V, c; \& p8 P+ c! C
- propF: {
0 Y1 S6 j9 S& R8 U6 T' { - validator: function (value) {
: ? V- q7 h8 E6 S- \+ \8 [9 W - return value > 10
: y8 x; y6 @9 }2 i, m; D7 x7 \% l - }
: u- l: N9 K L: U8 G - }+ \: \0 I9 {5 _0 M
- } z4 e* L9 e" h0 P: _
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
9 e. G6 |5 R, B& \9 f% ^5 }# V
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件1 A7 i2 D+ P5 R2 u& ^! @& ]8 v( E6 A
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例: b6 X. O! q: F+ l
- <div id="app">
# G. F! Q! q4 P b- O3 o1 t - <div id="counter-event-example">
3 _" w7 F7 O% T - <p>{{ total }}</p>
# s+ c. m- L% _3 s3 c - <button-counter v-on:increment="incrementTotal"></button-counter>% Z! ?" S& R0 W
- <button-counter v-on:increment="incrementTotal"></button-counter>
- A5 T+ M" I5 \ - </div>
8 l" L) Z# z. K7 M - </div>) E, B v% h9 w$ u% n) z
- / |) H2 J) E) j4 \5 B- j- V' l j
- <script>
- L" j' y- Q9 O1 ?9 ~+ D - Vue.component('button-counter', {
: E! K8 A, f# K+ |' s+ E1 K - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
8 t% g: Q# j, i. e m - data: function () {6 ^- E. S! V8 O" g3 p
- return {2 n7 `( w' e3 h$ T4 g
- counter: 0 f7 ]- g2 G! m/ j0 |6 @% S
- }8 p( ~: Q& T1 y d0 z
- },# |, R) d% p0 ]. ^/ W$ H; S5 F
- methods: { S) h& Y6 n2 N; A
- incrementHandler: function () {
2 }0 @1 y& W' _6 m$ S - this.counter += 1! E4 D# Q; Z! z4 M# A4 E) x# l
- this.$emit('increment')( h8 B3 j6 ?2 M# w* E; O
- }
0 h7 m% r: B/ I+ W - },
+ g# @8 a- V' @. Q) K% `. R - })
) ~) Y7 }' r# {7 {/ Q& B - new Vue({1 Q6 w3 {$ j) l! [% N1 y. c: L; S
- el: '#counter-event-example',
. {. g; i# V. c# E - data: {
' R4 f3 ~& v$ e4 P8 M# |! u. s - total: 0
( _. F/ }) f! P5 F' Z2 \- e - },
. [9 g5 _+ d% f - methods: {
; F6 e4 k* W2 G9 T% n - incrementTotal: function () {) S" R; X4 A& Q- x, e8 W
- this.total += 1+ v* C4 n' h Q! u& a; q
- }7 e- T e/ N: g/ p( F p0 o3 \
- }
6 ^6 p' ?" [1 f0 L1 G7 S% g - })8 o& d) V- S6 y/ k+ G
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册8 p5 R' C& a. R* W6 q2 P$ Z4 N- B
- Vue.component('child', {6 S7 x; x$ ]$ q0 E' A; e& s, F% R
- // 声明 props+ n4 l- s2 r; @8 v. e9 @7 g2 o
- props: ['message'],
( n6 J' ?$ ]/ `9 O1 F' } - // 同样也可以在 vm 实例中像 "this.message" 这样使用
9 J! {& Z- g9 s$ O) d% r - template: '<span>{{ message }}</span>'; `, j: F7 B) {% c& ^8 h0 M2 f
- })
5 P) C# @2 Z; [8 v7 o: r - // 创建根实例
) U$ K/ h2 u s- k: F - new Vue({
0 V& _3 d$ e7 O5 ]9 J. C {+ S - el: '#app',& _7 E: B; [, L, u) D8 X6 e4 `
- data:{/ N& x2 ?8 E' D; O* @
- message:"hello",8 c3 I" k m, o' ~0 t
- }
, G) m/ j2 z2 H' i' h* H! T. ~- Y - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {- d% r; u9 b t+ B# u0 K
- incrementHandler: function (v) {/ J9 s$ o0 w9 h8 O
- if(v==1){7 N& K( x8 ]+ t* ?' |, v2 d
- this.counter -= 1
6 b8 I9 n" @* q2 h+ K1 C - this.$emit('increment',[1])" ~& O7 ^0 ~7 `. U. ?$ Z" ~3 c0 t
- }else{5 ~5 j( x; H/ s! [# t4 l+ N6 j
- this.counter += 1
2 u7 ?2 v1 M+ ]2 S - this.$emit('increment',[2])
( h" w& C( H ?; Y% D* o; n - }
- ?- B/ g. x; }7 ^ N8 F+ w* y7 P - }, G8 j/ i& r. b: i, E
- }
复制代码
6 [1 d/ _. {' Y* M8 {6 z9 p
% k p' ` R# @8 `! @2 L |