组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
* Y* r1 j. W {- B; J5 R- <div id="app"> A, \8 V+ k' |8 Y2 z6 T
- <runoob></runoob>( R! A1 \& }6 q; z! o3 u9 @& \1 T7 h
- </div>9 s/ y0 W( W0 Y
- . D+ I& W5 b3 F9 _- R
- <script>
! }! G8 j4 r$ H( i: ] - // 注册5 Y: t. b, \& r/ f% E7 j, x0 M! s
- Vue.component('runoob', {
! g/ Q- w: J, a& r+ k G - template: '<h1>自定义组件!</h1>'
y* `: [) r3 k% w - })
: K5 X6 u4 ?5 o$ ~% I) f {0 d - // 创建根实例: l. }+ {0 m- j1 D
- new Vue({
; Q) l- J# X0 x - el: '#app'
4 B* g- r) e$ \ - })5 t o- k6 X1 D7 w5 S! X
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它:
' c l9 y: T2 f5 k- <div id="app">
9 n, E7 k& F" g& ] - <runoob></runoob>
' Q) j/ g: i) |; `& h5 L/ S3 F - </div>
4 b0 [* B% r0 h - $ j& q0 n( q& u- X, G
- <script>
5 D5 B% C+ ^5 u3 L - var Child = {9 ~( E- h% v/ v$ C8 Q$ k1 E+ e# C
- template: '<h1>自定义组件!</h1>'
2 M( }! X( u/ K9 |4 q+ T+ z - }
0 m8 E- ]0 W1 O# `, e- F4 Y -
8 q1 ?# T# p: R& r+ V$ ? - // 创建根实例( f5 ?. S) ~1 H2 n) a6 {# v
- new Vue({! c3 O. t5 Q2 R5 e' `/ p
- el: '#app',
1 a/ S, C" F ]8 U- q5 S6 d - components: {
8 O1 H2 A) o# v; I - // <runoob> 将只在父模板可用
8 T7 Q; O3 X- N$ k - 'runoob': Child
; L% Z& t% ^0 Q - }) g l! B' d+ K# P. h+ _
- })
: `9 Z2 C% p( f5 d0 v& _; x% \8 z - </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例
9 e* I4 k4 x8 }6 p" W4 S- <div id="app">
! _. t1 {8 S1 n0 E1 q3 E - <child message="hello!"></child>8 w+ ]# j0 ]' O- [ n
- </div>
6 v$ j" v$ A+ V5 t - 7 e- T' a& h/ \
- <script>1 ~& e- e9 V8 Q* C
- // 注册
+ w! a% ^0 G! h/ W6 b - Vue.component('child', {# u1 r( v5 s/ U2 Z8 t
- // 声明 props
. W0 j9 O9 U% `, }+ F0 I0 @( [ - props: ['message'],
8 c$ ?/ C! u9 ?1 e n+ k' ~ - // 同样也可以在 vm 实例中像 "this.message" 这样使用9 E/ d+ V1 C2 [7 n; R4 V
- template: '<span>{{ message }}</span>'& g7 W0 D. _3 ]8 O6 z
- })
. ?. o& ~& [" S. O0 O - // 创建根实例
* E- A) A9 q8 N; M0 W( ] - new Vue({: q, s6 x" _8 _0 }
- el: '#app'
* d; }7 z, `5 _7 p - })$ B9 T) v! d. f" ?( c
- </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
4 p( U! m& I+ K `5 c1 Q- <div id="app">2 \' S' V! u# j, j
- <div>
G! t' |) d7 {5 B! B - <input v-model="parentMsg">/ `3 w+ \, t7 P: W+ `; f; M
- <br>. i, R+ v3 j( R( O* J C7 o
- <child v-bind:message="parentMsg"></child>' s, |" ?! Y4 o3 r, ]
- </div>8 v* _7 c- C0 n0 a
- </div>
: i4 B. F; ^) V# w - 8 n! _0 d1 [% v* R" H
- <script>4 W0 W# W* T. H3 k D) u D6 x
- // 注册
/ ^- Y% w) G# E# Q0 b2 ` - Vue.component('child', {
! u' Y4 |: W4 n4 C - // 声明 props
& X* ~% O8 a5 i( i" N+ R - props: ['message'],* E$ ?* l( ~4 Q5 h0 N; W9 ]
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
& K. v* u: g2 S3 \ j - template: '<span>{{ message }}</span>'6 j4 C. ^* O3 s" o( H
- })$ {" z/ |0 b |, }! s
- // 创建根实例
g* z6 P! T6 s) A0 A - new Vue({
. v( n: h- ^) j$ p! c - el: '#app',+ u( X+ {/ L: |* ~' c$ J
- data: {3 t5 i' C8 C( d
- parentMsg: '父组件内容'8 d2 i! S# G6 W; F5 [ k, }
- }
9 J2 X1 ]8 r) K Y2 M - })
' q' q1 T& g: }* k8 v- {+ i, y - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例: B2 F- L+ C* f( B/ u
- <div id="app">" G# v4 i4 ?* F; @& z2 I2 g, B( ]
- <ol>) g) g/ w% ?' ?/ z9 d$ k0 ~
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
6 k0 z, \ B/ V+ A - </ol>: }' [/ o& v# R9 g7 I' z
- </div>$ A9 q- \. W% ]$ F& C& B8 L8 \+ p
-
+ c3 `2 `0 e0 {2 E - <script>
$ Y: I# F0 P* h9 L* {# v" P - Vue.component('todo-item', {
' v, E) Z( x1 H- i! a5 C - props: ['todo'],; d) C/ X. @& B: Z2 U5 `3 u* |
- template: '<li>{{ todo.text }}</li>'
/ B0 C' F. ~, {( f" v - })
( m: f) r9 J8 a4 f% j" `/ ^ - new Vue({
* b; a" [8 W6 L s. H3 s: Z - el: '#app',; w( n. W3 J ]1 T. W# w( p
- data: {$ l2 L, A B# V3 W* I+ D3 @0 ]4 m0 k
- sites: [) S1 g) s/ J; t) N" Y$ j
- { text: 'Runoob' },7 x/ s. @. a, j0 k
- { text: 'Google' },
; k1 a( h5 p0 N1 j - { text: 'Taobao' }& c2 \! O+ d$ c# g# n7 i! C8 p9 S
- ]0 ?' `9 v ? h6 U
- }
2 N! ^7 d! L' @ - })
- ?. B0 o, g! D; \& q" o - </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
2 g" i. c. D9 j9 I4 v, W - props: {
+ W; R2 @# g b/ x - // 基础类型检测 (`null` 意思是任何类型都可以)' R6 |5 b0 r; E" U4 E" C
- propA: Number,
* e/ P* L. o+ f' t, _0 T7 e - // 多种类型* h9 n0 W# W! M* Y) u7 T) O
- propB: [String, Number],
. | ^" i/ G" `: y( \: A - // 必传且是字符串- E( E# F/ o/ M- i3 h
- propC: {. X: \! v3 o6 Q
- type: String,
# M# N2 x; X2 E - required: true
8 A1 U- ^+ z# Z3 V3 p% Q( } - }, p2 p9 A( ^. T3 D# j- ?
- // 数字,有默认值
5 F I8 @2 H. z - propD: {
$ l9 p3 ]1 w# M# A, H - type: Number,
, o' }: i% r f& d* F - default: 1009 [: q; c& g; C& b% _, J
- },
{$ {' P! X5 p c; z5 U/ L - // 数组/对象的默认值应当由一个工厂函数返回
6 _" G G+ `; x$ K% r: f' y - propE: {
/ b1 i+ L) x3 i* k) B) Y g - type: Object,
, O: ~# f6 m7 D* U. | - default: function () {
) t2 `5 f% C/ p/ \, f - return { message: 'hello' }
5 t- p8 j3 M* y: Y$ s - }8 {1 O$ y, d# p8 t& C3 X4 u# P! _
- },1 Y7 W* W5 p/ ]+ f9 f, I$ Q3 p
- // 自定义验证函数
$ C- ]/ D: v x5 s- P* x; B! C9 l5 p# { - propF: {
# o6 c7 d2 ?/ { - validator: function (value) {2 v# Y# N$ ~4 s+ J* n
- return value > 10
# M8 U p' j: r8 D& y - }# C: M' A5 z/ g9 b0 e
- }
. _# y2 ]0 m# J% T& H$ m - }( M( \! c6 r% h: ^, O# B# X$ l$ n
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
7 R1 Z6 q3 ~8 S1 Y+ U8 }6 `" {
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
* A/ B" x4 X2 q$ a: v% g
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例1 f2 m4 x+ z' [5 @$ n3 M
- <div id="app">8 I$ m, d* m% x x
- <div id="counter-event-example">
/ e: U0 }9 G$ H1 E' d9 a - <p>{{ total }}</p>
: Z% i1 o2 a# _) {2 k1 P - <button-counter v-on:increment="incrementTotal"></button-counter>
; U% X" ~7 _" g7 Y r - <button-counter v-on:increment="incrementTotal"></button-counter>
* j$ j6 i1 r6 Q( I" I$ |9 Z! V* A - </div>
8 p% ^$ D: v4 g4 u$ d: ?, ?. ?8 s - </div># a( f7 d0 p+ n0 q: F
- D3 {/ d, x/ L3 {5 i
- <script>
1 n2 B9 {/ y9 I# t, {/ C4 a - Vue.component('button-counter', {
* D( k7 V6 L; n9 j+ e: E - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',- d) o/ Y( a: r. u
- data: function () {& `. o1 y" U4 g( ]1 q
- return {% F1 @/ W" s6 g+ X
- counter: 0
0 n; Y9 M' I" u' L - }! O9 A" r+ m; |- R: }7 ~
- },
+ A/ w8 u/ A+ C" G - methods: {; d) u2 J. g' J- L. ]
- incrementHandler: function () {5 `' C+ i8 U- Q/ f- F5 R! s
- this.counter += 1% c# v7 V8 q2 x
- this.$emit('increment'). a5 N0 U$ y; n$ [
- }
: \8 T2 }. C2 J& a - },
! f5 K) e/ J2 J0 B - })# T+ C1 O. e8 v% E" `1 H
- new Vue({8 U# d; R5 ]+ I7 A* g' E
- el: '#counter-event-example',; u+ o# X, m# F0 E8 x- N
- data: {4 _( @3 Z# M5 j8 o" y. G/ c
- total: 04 w' U9 Y# ?, x) ]: z4 B
- },
7 N6 r+ X% {4 H( T: \7 @& T) ~ - methods: {% ^' u! C, I/ n4 l# ~
- incrementTotal: function () {, ` p! r+ B( J: K8 O7 P
- this.total += 1 X M* j4 S7 l, j6 x$ A- F) M$ s* [
- }
2 M; j/ N' V- p: e - }
8 `7 Y& m6 J3 W+ v5 ]6 j - })
A+ v# h8 ^7 q5 L - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册6 e8 M, C6 e8 ]- s
- Vue.component('child', {. A$ m- |4 D9 J _7 ]
- // 声明 props8 S4 J0 U( D" O \; s+ ^
- props: ['message'],
! p# K/ Q8 h/ l/ u - // 同样也可以在 vm 实例中像 "this.message" 这样使用% w7 ]# Z. f% _" M \
- template: '<span>{{ message }}</span>'
e5 ^9 p6 b `7 e8 X3 W$ X - })
+ E$ n0 [6 k1 v2 j+ O; Y - // 创建根实例8 p! e1 X) L$ ]
- new Vue({
4 A% H5 t1 @0 v5 |3 N - el: '#app',
$ q; ~2 E7 U" c# g4 } - data:{
. Z3 d z& O/ x: {8 m+ n, a( L - message:"hello",
1 a) @# B8 u+ a: a. M6 }2 l - }
) z# Z# t; U; r X% g' C+ O - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
, @+ Y$ k! _$ U4 e2 |( R# G - incrementHandler: function (v) {
) {4 n; ^! y u8 j+ M - if(v==1){/ P6 D$ Z# d, y! w0 I2 ^
- this.counter -= 1
3 |3 \& }# z0 G, a; ~ - this.$emit('increment',[1])! L) x* {8 s f& r" ]! A
- }else{
i3 o6 g( ~ \ R! `. a - this.counter += 1# H+ R0 q) v( w: r3 z, H, A3 C
- this.$emit('increment',[2])
4 d9 v/ ]; m, q6 {" y - }
4 {& [8 ]' |" b0 G - }) q W# u1 H7 e0 X, W
- }
复制代码 C% S) S) G; j2 @' z9 h0 ~
8 [6 l! H: g! b& {/ u
|