组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它: 7 |5 g q# p9 W3 N3 \- C$ b) j
- <div id="app">
+ y) s* g. z1 S3 g+ a - <runoob></runoob>5 Q5 c/ |* z- g: Q2 B& N
- </div>( G9 Q* N& A" _+ a
- / W; h# w/ g5 m7 C# ] H6 [
- <script>
# X) Y5 L0 Y( k- m3 y) m. A/ g+ Y6 @ - // 注册& z ?7 W( ^+ V, Z8 l
- Vue.component('runoob', {
- l8 v: d# w, G - template: '<h1>自定义组件!</h1>'9 |% i7 T1 {8 W1 X; L# b
- }), D9 c! ?3 l) z$ o5 t5 A8 H3 v8 R( _
- // 创建根实例
( A' l* H8 d0 U G1 F - new Vue({
9 x5 d9 P1 B' Y1 P5 L) N; _, \ - el: '#app'
; ~* {& c, D" X4 E1 P0 r1 @ - })
- D# ^" \: g6 x5 u" D% r! _6 J: M - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: ; `& h8 ]0 {: \/ h- W- V
- <div id="app">; X* ?% }' h! \1 v7 w9 P1 e
- <runoob></runoob>8 U: U' n7 O' \
- </div>
9 t I/ Q( B% j6 ?0 w1 }9 \2 {/ Y -
, O! z2 o$ ]2 S& j6 a0 l$ V - <script>
3 o; q, b: r! w$ J6 ?$ u/ p - var Child = {- j5 j7 f1 \: J' }: U
- template: '<h1>自定义组件!</h1>'6 ]. K; Q% @+ ^0 G2 b+ G
- }; x- e: }* g1 y4 ?( U" X" G
-
. f9 l, W# X4 C/ |) T8 S o6 v - // 创建根实例) c( @* i- p$ I ?; y& z9 X' _
- new Vue({
3 |8 `$ R- e& I( f3 H% k M - el: '#app',
0 {+ Z) d; o$ T$ \% i3 O& A* r3 M - components: {
2 Q' S3 C/ W' g6 {2 M2 a - // <runoob> 将只在父模板可用
( c6 Y2 ^! e% H$ z - 'runoob': Child
8 K2 `0 t3 H% [ - }: R. A S4 U% M) ^# h
- })& A4 H! U% L5 Q3 A4 r+ C3 p
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例; I7 P) A! a. G
- <div id="app">
8 V2 o5 |0 G! t$ {: p4 c0 X. O - <child message="hello!"></child>( C8 J0 @ B& E4 a U) q# v
- </div>. r, T; n4 q& ?
-
& r0 n0 R- ]8 T+ m- L# ~ - <script>
( s( T" Z& b2 ? - // 注册
& i, Q! j6 r2 z, q* s - Vue.component('child', {% T+ c" L5 \5 M$ T6 W/ e
- // 声明 props
4 c& }% ~0 L7 T& ]8 i% m - props: ['message'],9 r4 e0 F: R) l& n: h* w
- // 同样也可以在 vm 实例中像 "this.message" 这样使用1 _& a$ O( X9 M+ s3 b, J* g' }) c
- template: '<span>{{ message }}</span>'8 v8 V! J+ O2 ?1 d& ^
- }). l; Z. y6 D4 N& d) |8 x
- // 创建根实例4 n; o$ |' }, J( S4 G8 s' b
- new Vue({
3 h/ A) W& @" ]5 {2 z - el: '#app'3 L1 j# e& c9 P0 p$ k
- })
3 w0 L2 W9 ?. K1 \ - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例( i- N6 p3 o9 \
- <div id="app">
) V: E0 C+ o v3 U* j& z - <div>
: d: S# u4 \$ _8 V9 D0 @ - <input v-model="parentMsg">
: j; g7 O3 i: m" [; f# Y9 U9 d - <br>
) F) f8 q$ Q+ v( E7 g - <child v-bind:message="parentMsg"></child>
) U) J" E" T" B: ?9 I8 Y" t - </div>. H7 m6 f, a6 @7 v
- </div>
! H M. w3 E- r -
; }/ \- o. a5 V7 @7 \$ k; L - <script>
7 E" J* D# Y9 d( Y" s" o( [ - // 注册2 y& n/ e7 \& ^6 h; \5 T* A) P0 L3 o' Z
- Vue.component('child', {) ?+ y, V3 i3 R5 D
- // 声明 props; K1 h. f7 i5 j" l. Q, B/ r0 o
- props: ['message'],
; Z0 J @" k% I; t( k1 }5 k - // 同样也可以在 vm 实例中像 "this.message" 这样使用# W; q& h8 f3 B: a, r
- template: '<span>{{ message }}</span>'! a) ^! E( d7 q8 _, N' V- P/ H
- })9 @7 ^% x. D4 y& L; r7 |
- // 创建根实例
& T9 C8 {9 l8 o- s% i9 y: L5 {3 l - new Vue({: ~1 Z, w' w+ b4 h
- el: '#app',
7 j" F: n; L' R* D/ i: m6 n& q - data: {$ @ }+ F# l3 x' s( q
- parentMsg: '父组件内容'
) W3 R: d' \: U2 |; \6 l - }
! t8 n7 z$ s' d* T5 y - })* ?( S, s# {6 H1 w3 u& n6 }2 Y
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
% w7 a8 E# t8 {. ]* L- <div id="app">8 [7 x ?" Y" E4 ]
- <ol>6 ~/ X z) ]0 S( }3 D" x
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
( n$ F" k, ]6 ^. ? - </ol>
( g& o5 F2 b+ [ i# Z8 [ - </div>
. B1 D4 Y' U6 F/ X; `' O: Y" L -
: R: Y2 x5 c: J+ m5 J1 U - <script>6 V) o# l( L# @; t
- Vue.component('todo-item', {
' |6 x: b6 f' j ~( y/ D - props: ['todo'],7 W5 {: ` E- a% q' E) M: }% y
- template: '<li>{{ todo.text }}</li>'
' y& W* M8 u& [. Q# o) B4 S. ^ - })
/ [! c# q- h2 p5 ^" y1 d - new Vue({
1 q& P+ H# i r# _8 ~- f - el: '#app',* \1 A1 [" s9 d/ G1 J/ P
- data: {9 Q8 B7 f4 h0 s* j% u
- sites: [
6 J+ j* ^$ z( {4 I; {! [' f - { text: 'Runoob' },* x B# a: b9 x$ r$ I( K: H
- { text: 'Google' },
0 j! G0 p* k- W3 P0 [! w/ A' C - { text: 'Taobao' }# F4 o8 @: g( Y0 A6 D! j
- ]
% q. F* [* z$ w" K - }5 x$ Z9 y9 F+ T, |! l$ S! _7 g
- })7 u" f/ i3 d' V3 i
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {9 b7 O, r$ A# @2 I6 Z/ D2 ^; n
- props: {
" h1 T9 g! `3 P1 b3 [( o, q! u Q - // 基础类型检测 (`null` 意思是任何类型都可以)8 M8 c) ~9 U( @: j
- propA: Number,$ q7 J5 m9 C8 r
- // 多种类型
/ ~9 y7 x; x, D* E - propB: [String, Number],
& n4 ]+ W5 \% d6 R* A8 J2 F! N - // 必传且是字符串
9 v/ n/ v S" G* D9 ` - propC: {, D" Q- q9 B3 T" r- q7 w3 D; } X: P
- type: String,# j, _: {/ J/ y- L" _7 _( ?
- required: true( S; G( ]3 X% }9 J- N2 P9 I8 C
- },& O% m8 Y6 O. A& M2 D4 \
- // 数字,有默认值
% v) u2 c% u" c9 ?8 D; ] - propD: {4 }! n3 d# y% l* L
- type: Number,
; g- A/ R/ z' j* @% x - default: 100
0 _% |& @5 i; G8 G# g8 k - },5 y* e9 V" V/ U
- // 数组/对象的默认值应当由一个工厂函数返回# ^& v+ S- D, E P6 p- R6 O/ C3 J
- propE: {$ M( v) A. A8 |
- type: Object,* ]' J4 a q( l/ f
- default: function () {
* o; B1 @7 e; M2 o9 [+ y - return { message: 'hello' }$ Q+ m7 _4 U7 C( ~( ~% [9 s
- }
( m' ^! g t1 u* m - },
1 W9 z, x+ {6 q' G - // 自定义验证函数
+ d& R7 _; `2 ^9 n' ]! a4 v - propF: {
6 K+ v7 [8 F' L) X6 a$ x3 d( {* c - validator: function (value) {9 x) q, _4 Q1 o
- return value > 10
* u1 V s+ p! ^0 B: G" w - }
8 ?* l, Q) J) K8 A4 D - }7 w5 m$ F5 G* P8 L
- }1 Q! _! ]4 [ j% ^: O
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array/ U& r( o* s& l$ N& E
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
0 @2 w. I* C" V) X! [3 n) O
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例
3 Z/ m/ b; F; L) S# |* I$ ^- <div id="app">
) V; o# \+ U7 d' a0 G - <div id="counter-event-example">
: A! x+ f* ], v0 e& u - <p>{{ total }}</p>
- E/ [' W8 w- c" ~ - <button-counter v-on:increment="incrementTotal"></button-counter>! c" f- S+ }% d: c/ {1 w
- <button-counter v-on:increment="incrementTotal"></button-counter>
8 U. x0 ~" l o1 P, p0 B; F - </div>
4 d% x$ R2 P, t3 h% G - </div>
( q# _) z6 l4 c) B/ e1 K -
) g/ Q) H4 o3 M8 V6 `5 q% e - <script>" ~: q" e* z# V0 }% o+ q; {3 n
- Vue.component('button-counter', {
H! |3 o3 w8 P5 \+ l2 v" x) X - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',0 ^% q; U% x5 n% y! J6 Z" B
- data: function () {/ z$ L9 j% G+ p( f: P: _
- return {6 h3 t/ s' w* x0 j7 `$ r
- counter: 0' U/ ~/ _! [2 l
- }
7 q) g$ T" J# M8 O% w' m4 m - },
( K: n; ]+ P6 c# u8 ]3 ^5 I/ n - methods: {) e. D, ?' B0 u- m1 _: X4 p; _
- incrementHandler: function () {
3 d) \7 v8 b% U5 U/ L. g+ M; {9 U - this.counter += 1
( k: q$ z% K8 j - this.$emit('increment')
9 I0 o% ]0 U5 ]: ]% I7 c* K - }3 o% w. M2 v: s
- },
, E7 q2 B0 P( |0 B, F( s% l/ d - })
0 S9 b9 \" o0 d: O, u - new Vue({
* i- ^/ q! Y ` - el: '#counter-event-example',
. z+ t6 p% ?( i* h - data: {: l q/ t5 H! d- b4 J
- total: 0
' [# M& H/ z8 R5 J7 Q0 X - },# q: d) X& t9 K# {4 U7 {
- methods: {
5 R- k+ _9 C1 e2 X% ]1 ^5 I - incrementTotal: function () {
8 h7 e% e. ~) K# S - this.total += 1
; P5 t6 u+ y! V# t - }+ o5 {( a7 O P0 ]4 o! Z' r4 a
- }4 L# ~5 _: W+ P, E
- })
* \# ?3 U4 P; Q( b, k - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册* @1 {* R4 b# |0 g. H7 U% ^, D0 O# R b
- Vue.component('child', {
- g2 T* n$ f& G- \* p - // 声明 props
$ p8 M1 x3 A7 ?: k! M9 _2 G/ T) L - props: ['message'],4 I" J( L" Y6 u. `$ `8 |- m
- // 同样也可以在 vm 实例中像 "this.message" 这样使用' H7 j7 C/ {! x- v% o
- template: '<span>{{ message }}</span>'- `! I& c* a9 U: Y& `
- })
v, x1 b/ y' h0 J - // 创建根实例+ J! u! M( d9 ^: z/ f# \
- new Vue({/ y" @8 y' [; |1 @
- el: '#app',
- v/ G, c5 v) B - data:{
/ K9 W" H! n7 v8 n& \# i# D - message:"hello", o% W# _7 t1 _; Q
- }
, e+ u w& c$ _' Q - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {+ R; {, z# R! @
- incrementHandler: function (v) {
5 I" @* J* |* U& ?# S' _& i9 c - if(v==1){
$ a L7 ^3 L' t. V - this.counter -= 1
# W- J% Z( C% ]0 x - this.$emit('increment',[1])
' R) @/ N0 t* M. J- M - }else{
# f$ @' a- ?% A( l& l# b x - this.counter += 1
1 o/ M0 Q3 T8 A( ]0 s - this.$emit('increment',[2])
% J5 v/ v8 @* Y5 ]! y5 a - }
w5 V; m1 m8 H8 V( m: }" @% G - }
" s. g5 x4 ~9 D" x R - }
复制代码
% l2 y& k2 l3 G0 r; m' I% s2 N' A3 y
|