组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
2 D5 G4 i# C8 J$ Z- <div id="app">7 c) @- e+ a2 V8 J
- <runoob></runoob>: E& f) }' k1 X
- </div># o; u( |. x5 L n
- 6 G" L( `+ ]3 d' R5 v
- <script>
. x2 _, R% E7 z9 k1 B+ W" ]0 ?1 { - // 注册
% _- S. b9 G% A7 i; C, \& ~% h - Vue.component('runoob', {
9 M1 Q' o( r$ D6 R& ^; | c - template: '<h1>自定义组件!</h1>'- W, l {$ s' o# _' T5 w3 a
- })% ]- H0 m" s' D
- // 创建根实例
/ i4 }/ A4 p/ B, k( Z4 w2 R - new Vue({; m1 s. J9 {- ~: v, H: D# v
- el: '#app'
& F* f8 g, [, x) J) W& g - })8 T3 C" d3 n0 z9 I
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它:
t6 O" S3 _ h3 s+ y) D- <div id="app">
( c- T. v( |8 L2 @* f7 C5 h8 i - <runoob></runoob>( H- ]* [/ L6 n# f) d' m( U
- </div>
) I1 l1 }9 ^( C/ o( h# z -
- W% x$ G' C. L$ R8 d. k - <script>( R8 ~4 g6 i* b. {
- var Child = {
% e' s( Y9 k) ~" r - template: '<h1>自定义组件!</h1>'* I1 l l, S' ?
- }& g8 w3 |+ I2 [5 t* A
-
4 V# I% j$ j9 a0 Q( q" p/ u" E# \ - // 创建根实例
0 q ~# N$ f1 R7 `- z5 Z7 q$ G - new Vue({6 v% Z" S6 y* O* S! g. Q4 @
- el: '#app',
# ]. d% \( f# z, V3 W - components: {: c* m2 |# K* R, p
- // <runoob> 将只在父模板可用0 a, b3 _3 o3 n' I: F, C! v
- 'runoob': Child
+ I0 ? V3 C8 J8 H* c - }; X8 I+ g1 @4 j* p; U$ P
- })$ ] r! w9 D- `1 B7 E
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例
3 Q p0 u3 ^* G+ r; L- <div id="app">
1 F* h% `" {) G4 L+ c% B - <child message="hello!"></child>, r J" x$ h/ g# R/ z. C4 z
- </div>8 }: Q' b% m* J! r3 F
- 6 P% Y) C3 T, Q3 `+ k) N3 G
- <script>4 ^' k" O m& m% R0 M
- // 注册
! M2 ^8 j! D. p% @ - Vue.component('child', {: I1 K% K8 C7 y) q3 O2 _- s
- // 声明 props, C+ C0 b9 O$ ~- j
- props: ['message'],( K D' Z+ ?/ V
- // 同样也可以在 vm 实例中像 "this.message" 这样使用& I; l0 \5 M1 ^! P: W
- template: '<span>{{ message }}</span>'0 L' c( d) e% s+ g0 ^- F- @5 v& v5 e* u
- })5 S% g/ H" ?! p$ h9 @
- // 创建根实例9 c6 U" l: j. A! o
- new Vue({, K! T2 A! I: v, [! g( k. z) t0 V
- el: '#app'
+ d/ U* x' g4 T' w2 z* `$ L - })
8 `( M2 R' V& {5 d: R: s2 S - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
% F/ h6 Q0 Q% f- [- <div id="app">
( y7 t( B! P* v2 \* J% W; J& ^ - <div>* ?0 m$ Q, ?/ x/ ]0 D
- <input v-model="parentMsg">( y- b# J, J2 ]# ]4 k8 _- ] w
- <br>
* b9 w* ?; c8 g+ E2 W - <child v-bind:message="parentMsg"></child>
$ k) N4 T( Q) {0 {2 p - </div>0 t9 o& {% I" u) N% K
- </div> t/ t: B$ `1 P$ Q
-
( O( }& j4 R8 G! Q6 S9 y p8 | - <script>
! q6 E% _+ E0 g: ^7 W - // 注册
7 ^. B3 O2 {6 e$ ^" O - Vue.component('child', {; P5 ]4 o+ h- o9 [
- // 声明 props/ X0 U; n! |/ @* B' w2 [. w5 p
- props: ['message'],# K2 b$ U [4 N
- // 同样也可以在 vm 实例中像 "this.message" 这样使用1 P4 H: O3 @( \( E. [2 W
- template: '<span>{{ message }}</span>'
0 R4 B% A% Q& e8 u0 `) O - })$ M$ r8 v( k, W b8 h
- // 创建根实例
4 ]' B( s& |8 l* f. @0 t - new Vue({
6 Z7 n1 U P* S - el: '#app',
) R8 [2 @0 B3 e - data: {0 r- l$ R7 S4 p" t" Z5 p
- parentMsg: '父组件内容'/ ]& r; L' `$ R- Q, j. Q2 e1 i
- }
& P7 }* i2 Y+ p" N - })- E8 W7 E9 a; q3 X3 ^8 n7 o6 l
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
# u- [- U1 y; O" E5 j( A- <div id="app">
0 E. I( q) e' S$ V+ } - <ol>0 ?- M( U' y9 g( Q0 \+ m
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>8 G! V: l& q5 {4 a+ y+ l k
- </ol>- o6 F( M$ X7 I5 ]+ ~6 Y
- </div>! j6 t! v% @) ~2 @; K
-
/ V/ A. O8 D# e; ]# ^ - <script>3 u% f- p: j; \/ {" w2 t1 w
- Vue.component('todo-item', {% r7 u9 }" {: U6 u% ~1 m: u
- props: ['todo'],
8 r6 j" O' ?+ {5 A! p - template: '<li>{{ todo.text }}</li>'
# o4 [8 A& U; \3 U9 ]6 A5 O2 Z - })# M$ p y5 \) S/ I$ s% X$ E
- new Vue({; \; p3 T, `1 s4 o0 Y
- el: '#app',/ l( o, O* o, F& g6 f% g3 a! D) C
- data: {
7 g* `3 v7 I; s: |, H7 ^! N, b - sites: [6 n. x6 i1 z& [6 e# M+ r
- { text: 'Runoob' },* B, i! v7 M* l. y. O1 [3 |$ W8 b
- { text: 'Google' },5 g* y2 d* |8 Z9 l" h, H
- { text: 'Taobao' }
, o1 U8 ]- o* o: o# X. | \. r9 ?! J - ]
; m8 o" s' J$ y Y - }1 \3 @. X* S1 m
- })& f" b: ^3 Z) Q
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
7 H* K8 z* Z: h# q - props: {
# {7 W& \& l1 O# g - // 基础类型检测 (`null` 意思是任何类型都可以)( a t$ j: o, R
- propA: Number,
* u/ }) ?! Y1 }2 S* E - // 多种类型
& L) _5 n; h: N1 ]3 h' z5 g - propB: [String, Number],% E7 g! |9 B9 w- @, @3 w
- // 必传且是字符串1 s- L8 ]3 m; Z# e- ~7 Q: S2 _
- propC: { s' i6 C0 f) {
- type: String,0 f3 i" c' f! o2 T2 h
- required: true
: r2 U- J) ^, {" ^- B) G8 ]% h% \! p! A - },% E$ }9 c6 ]0 A- t8 O
- // 数字,有默认值3 j5 t: u) S4 W* F& V6 t* {
- propD: {" @. J$ b: q: W: x4 \" u
- type: Number,
; C6 a2 |# ]" z3 A$ `" K: \: Q - default: 100& d5 O1 f- T) A Q3 N; `
- },. X) a( I# h9 R; W W4 f* l
- // 数组/对象的默认值应当由一个工厂函数返回
2 M/ Y" }; ?2 N3 K& S( x" h- @6 c - propE: {
/ o9 P' k5 w! |; j4 ^# R: A& t, O - type: Object,
1 {9 D1 k2 O0 u4 G& G7 K - default: function () {) P t/ k- \% b' ^1 c( {5 u' S) b7 i
- return { message: 'hello' }6 l' {8 l4 d7 ?' d( ~7 L
- }
' E4 b4 B' X+ K& e6 S* V" L - },
* k! B5 b3 `) C O - // 自定义验证函数
7 u; w4 P' l: m' D, g - propF: {
1 e2 u+ ]" t! q4 j9 Q& A+ w3 r - validator: function (value) {' _+ q2 I; z5 N8 ^
- return value > 10
d, \+ ?0 G$ N2 Z: g# }; y5 m# v - }* N! v: e& [2 G" S, J
- }
9 i2 z. V8 e4 U" K% }4 q& ^ - }! J) X# ]6 l! e& H7 a2 D. ^! |
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
9 R7 \7 f0 @( w1 q! O
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件5 A, ~3 f, W) M5 \
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例- x! K# H9 i, a% M
- <div id="app">) [& J; g: Y Y9 r+ D6 @! d3 F, e
- <div id="counter-event-example">
2 q# U/ \- C, g7 C% { - <p>{{ total }}</p>
8 X% B9 D4 o* j3 q+ F6 R - <button-counter v-on:increment="incrementTotal"></button-counter>
; V v9 s* n1 n1 P8 Z - <button-counter v-on:increment="incrementTotal"></button-counter>, L8 l# [$ O2 f! T( ~% \
- </div>
6 e" _# B5 q! ~4 q$ e$ [% ^. ]+ A - </div>. z& v8 N# f+ m# p' |( g
- : X' U, K' S& O/ m. A# g8 _
- <script>
7 u# {1 D' q3 E' [8 X$ J% M- f; m - Vue.component('button-counter', {
; x1 L* J e) [6 I F; C - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
f" b" O' q- y/ |2 [; e+ U# ]+ I - data: function () {# [! U1 w: x/ M. O, l
- return {
9 J7 a2 e/ y- z6 f - counter: 0) m" r1 t& b9 u* J* m2 t# E
- }
: `+ I6 L+ Y b8 ^# o$ E: u' c# X - },
6 N# p+ ?7 {' g - methods: {
! W3 v2 A; m, a! F! c: |; _8 U' e - incrementHandler: function () {
. e9 {; ~; F9 \0 d - this.counter += 1
) b- `: k/ V3 e3 T* w* ^8 v - this.$emit('increment')
N9 n3 K* n4 @; Z% q( [ - }+ u) D9 F V+ r% G2 Z) P0 B# Y
- },
# p% K) g8 J J4 m5 s& ] - })
1 i8 z* _& f/ L; E3 f - new Vue({
% }. i4 @1 {- y" v5 w2 w! @( Y" V - el: '#counter-event-example',5 n7 r0 I7 i* F5 L m" l
- data: {
. M* Z- a6 x$ ] - total: 0% e4 V {6 {" |' j6 c! u
- },
" N4 N# K+ g1 | - methods: {
# | c3 c5 N; [" M/ g4 h - incrementTotal: function () {
: n! N5 s' s% i* M& g - this.total += 1! B% Y( h2 p9 A; d: P
- }
4 C5 d3 @" {" S) s* f9 y X - }
5 }+ H4 m( T1 R; Q- B0 x# h - }) p0 L7 [" p; J' T# p) w
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
# F m1 p# o, a" O$ D; z3 a - Vue.component('child', {0 u9 Z( g R) R" P- Z. i2 }
- // 声明 props# [- w. a+ R9 L$ B u
- props: ['message'],' P# N* L5 l( V6 O+ T
- // 同样也可以在 vm 实例中像 "this.message" 这样使用0 z) W% h$ Z& T% a, }
- template: '<span>{{ message }}</span>'2 A8 x! l" U' Z; K" f
- }); S& H5 k1 V- ]7 N+ ], K9 J C; ^1 r
- // 创建根实例
8 e0 N6 k/ t( W - new Vue({
) `$ |8 R: T4 c8 }7 D) A - el: '#app',& c8 C Q* Q" ?2 g) g% c1 o% |
- data:{
3 G: u& C: d+ K3 E/ C - message:"hello",
k% @5 y2 t4 P: m: ~ - }
/ {8 D- ]$ `5 a( c4 z - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
* `& m) u4 @, I/ T# J; b9 J1 X# ^3 [ - incrementHandler: function (v) {( ^' J1 ^/ A C* g- J
- if(v==1){
) }# Q. N: e$ [$ d2 z* i - this.counter -= 1
, Q" W4 u f: G/ v( \ - this.$emit('increment',[1])
/ g3 l9 r4 Z+ P0 F- v - }else{
- H7 Q8 P; I" x' i0 o - this.counter += 1
/ k2 [* q ]( o) p$ \* d- y - this.$emit('increment',[2])6 e: t/ I; k. D9 p0 l' m9 u& ]
- }
# j2 A$ ~5 d, U& B7 \, j8 G - }
3 d( V; @7 c, j) ` - }
复制代码
1 \+ G6 R' ^" k" Z5 f7 T- ]9 V$ X B* r# h# y
|