|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它: 5 K% i3 U( I |9 x
- <div id="app">
3 }; z9 M2 @2 |2 [$ y: t3 k - <runoob></runoob>
; P: W- n2 Z7 v0 z" V& X5 u2 r2 X$ e - </div>
7 ?1 n% B$ r; Z* e. ?. r. y -
" n" i" F4 M9 n4 | - <script>
0 ^2 }' i8 B. k( `0 C - // 注册
& q5 T! ^9 K) u" q. c! e* E - Vue.component('runoob', {! l. o) j2 C+ K) ?$ `& h- C1 s+ u
- template: '<h1>自定义组件!</h1>'4 p: P; k: o! _( O7 L- ^" E
- })
+ R4 e. w$ Z! J1 [3 }9 c0 M. r, T - // 创建根实例$ p* E$ Y) [ q8 T0 h$ K k
- new Vue({
# A8 |( v% S( e - el: '#app'
" }' l% W& e# J' R+ F - })
+ c+ M% k+ y7 Q - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它:
* l; u$ q+ [' h* }5 p; x$ p- <div id="app">2 w+ O& b- l7 v% k
- <runoob></runoob>$ a3 h$ l1 C9 M# K/ n: R2 H, f1 }( v
- </div>' F* {5 V6 P5 m7 ~, T
-
( Q5 w$ a! A2 M W6 C - <script>& |' F3 {4 A6 C. r# n% s3 S9 d. t
- var Child = {: _- g* r8 U# R
- template: '<h1>自定义组件!</h1>'7 z/ Z8 M& ~; z8 t, S6 `
- }
1 z# z* }+ N5 [+ S# A8 R# I! Q! { -
& k' s3 |4 h9 d4 H0 q) p - // 创建根实例
9 K* j& t5 h; `* g7 x6 ] - new Vue({9 y. J' S! s, t6 F
- el: '#app',
[; J; Y6 F- n1 r) W, z* N - components: {, A& H4 G. m! P
- // <runoob> 将只在父模板可用
: M. W3 F, d }" h& x0 f4 {) E - 'runoob': Child4 U& o) C& N4 M* Y
- }
; R- s$ z$ B" ^8 E5 q& P - })
7 {: m. q. F N- y& l6 ] - </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例
2 ^( \" c" G0 r- <div id="app">
b! V0 F. d L8 Y' C# L* A - <child message="hello!"></child>
- ]* l! H& j# b3 e3 X - </div>7 O7 s% ?' `7 j2 X
-
: F8 O) B* f4 Q; f - <script>
3 [6 S) h! M0 D' x - // 注册$ }2 w" o- M1 |& ^; B% y
- Vue.component('child', {
( O/ }# V7 `0 D; H" v/ ? - // 声明 props3 x( v6 a" c; e) G+ v4 b
- props: ['message'],1 H4 K' h/ U3 c6 |' d+ I8 |
- // 同样也可以在 vm 实例中像 "this.message" 这样使用, B, O x8 z7 r* B: e) L5 A+ x. G
- template: '<span>{{ message }}</span>'
# Q# f7 `& ^1 p m - }) U. Y c t: O& O
- // 创建根实例
1 G# I7 R# Q/ Z, l - new Vue({
8 t2 Z' l% [ n0 W" `8 X - el: '#app'/ E3 [/ n: [' G5 u6 q# r
- })0 u7 g7 o$ b3 F
- </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例' V: p5 r$ P+ l! ]9 a0 C
- <div id="app">' }% Z t$ ?9 {( o1 i% I
- <div>% \4 N) a( c, f7 ?; Y' G# k
- <input v-model="parentMsg">; o1 \8 C- J: @( c! v6 n
- <br>
, @, T! T) i8 l5 L( A* m - <child v-bind:message="parentMsg"></child>
* K }0 @6 P" ^) ~2 F; r - </div>
9 A3 ^: P3 D2 j( }7 k - </div>
Y& L: h" G3 W+ T -
! O0 ^1 M+ D u+ [! e' I - <script>
0 W! V1 u K- I0 e" h2 @4 M L/ ^ - // 注册
# j/ Q4 V; Y6 o9 b& C - Vue.component('child', {
# {/ p9 d" ]/ e$ f( k - // 声明 props
* Z9 O: E" [& y+ J! h - props: ['message'],
6 `0 L0 V% W4 I1 `/ u - // 同样也可以在 vm 实例中像 "this.message" 这样使用: e9 }9 U1 X& z5 f( G
- template: '<span>{{ message }}</span>'
. Z8 J) q: _& m- {6 J - })4 d7 c/ K# K/ h4 ~, z
- // 创建根实例
2 Y5 z+ s3 g5 }) u# o. }% S1 _ - new Vue({6 ^8 g. B7 I; R K1 M+ N) U
- el: '#app',: Y+ \' ^4 P* ^1 }% {
- data: {9 P$ T% b) ^( D/ B2 b6 V
- parentMsg: '父组件内容'4 {4 c! h% Z/ `& \5 I( C! ~- V
- }
$ G* s5 |# F: l$ p4 R( H - })/ |9 `2 f" }# ~# b
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
* W- U4 U, h1 C$ @0 q) t- <div id="app">
$ `6 q: c9 S* O. z) [6 i. H0 T( } - <ol>0 t2 g0 ^$ f& S; h% U! K
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>7 b5 y a) |! w! S s# t, n% L
- </ol>
+ b2 ]' d a8 T: ~ - </div>% a( ~( i) g0 n2 s
-
! n& B$ ~, H& F6 X6 ~ D4 c - <script>
+ y. h! J) F4 k! D3 X8 v7 d, q( m - Vue.component('todo-item', {
9 m3 [% R6 U, K3 }% y - props: ['todo'],2 {2 }1 f& r# J w
- template: '<li>{{ todo.text }}</li>'
0 @) A Q6 P1 G8 U( w! @% q8 [6 J4 y - })- L- { U* Q9 y
- new Vue({
* v1 X p: w) g - el: '#app',( s' J2 `* U) B% E
- data: {' `1 @8 o& K4 J* e6 `0 M
- sites: [
3 U6 T1 D: G. X' j$ z( m/ c - { text: 'Runoob' },+ o/ w0 x: l7 e/ L1 X
- { text: 'Google' },
' a0 q* \! \; t7 o* C - { text: 'Taobao' }
4 `/ b# ]- G, P3 d. w0 D7 \2 q - ]; ~. F$ ^0 `; \: O& a8 a
- }
! ~3 x/ G9 q3 g2 R/ R ^ - })
1 K: u" I& g/ O - </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {5 T, G% K! t, x* Z% O* o1 }6 @% n
- props: {
: E4 ?& ]( v) C& L/ j; _ - // 基础类型检测 (`null` 意思是任何类型都可以): `$ Q: t+ ?2 C
- propA: Number,
& g$ p6 a* K% E - // 多种类型$ {( U3 |/ l) x2 u& _
- propB: [String, Number],
5 i3 A) D/ W y; t/ Y: @ - // 必传且是字符串
, l) l5 B7 q0 N+ b* Z: G - propC: {
0 P$ t' A/ Q4 {8 n! u- j( U! f - type: String,
5 V* G9 B9 _) g6 e5 |: X- a - required: true X$ T1 V8 b6 L
- },
* R" Q- k; J) W8 k- u; I! c - // 数字,有默认值, r7 u+ l+ r& b
- propD: {
3 r4 j, k+ G1 c p' T: _2 r. v {2 ` - type: Number,, n1 \" e6 g6 {6 t4 @ H' _
- default: 100
& b2 z% P$ t* L" W* R - },
; s7 l/ v8 Q _0 K' J - // 数组/对象的默认值应当由一个工厂函数返回
' J" {1 L. e5 ]; b; w: _ - propE: {
9 U' z, U! x$ R# x& |, Y X - type: Object,+ k6 L+ `8 b9 R/ H z% u# M
- default: function () {
3 N& ]1 H( G! A8 \ - return { message: 'hello' }
; x( Q, ?6 `6 X. K7 T1 I - }
( B2 Z" z4 Z, x, ` - },4 J3 Z- k E' |2 E/ ^% g _8 {+ @
- // 自定义验证函数0 F* [0 m5 p g9 {$ V, [
- propF: {
& J( |" Y" h, A; L' b - validator: function (value) {4 N& r, c2 S# ?% q
- return value > 10
p# f/ Y( H4 q) H. D! s% o - }# I }4 x- f! b5 m0 _/ o5 O( o
- }! m3 _- K& P F; ~6 R7 u
- }. ^$ Q O) K* `
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array a6 c$ t }) E1 C4 \
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件8 |7 \2 k9 l2 S# Q- U8 {
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例! O o% `* C( s, v
- <div id="app"># w- D+ l5 a8 q) S$ J
- <div id="counter-event-example">) a. A0 o& P+ M+ y0 J
- <p>{{ total }}</p>2 N# U* Q x1 k z
- <button-counter v-on:increment="incrementTotal"></button-counter>
: m' ^1 i3 Y5 z5 O4 i - <button-counter v-on:increment="incrementTotal"></button-counter>, U5 M, V# a4 _2 J+ j! a, l" n ^
- </div>
7 I! S' q2 F; Y5 F7 d9 p - </div>
/ A' T6 V9 v& O3 Q( F8 M' h - / L4 _% l) y1 F
- <script>6 t' I& W6 F7 H2 P% ]) c% S- T
- Vue.component('button-counter', {/ U! H' ?9 Q, t
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>',! V- G5 s# p/ t F5 Z1 N I
- data: function () {
7 \/ B8 p, O7 ]% M& x - return {
# m0 T& Q1 {5 \2 ~; v - counter: 0
4 ]* {0 J/ [; `1 G4 V$ o) |& r - }
3 \: X, y4 s& | u3 _/ k5 { - },
* r! o! R$ f( @: k1 s0 e1 t8 b% t - methods: {
/ O5 r3 Y( [, ^" j - incrementHandler: function () {
& k2 b6 |4 K0 G. f0 k - this.counter += 1
' k; d- A' W% ~- a3 T7 \9 U' n - this.$emit('increment')
5 e3 P) x* e5 I7 U - }
" M& h9 x, ~8 J8 x3 `, Y9 ] - },
- M+ K t& ?+ Y- \ - })
6 V. m2 Y) B, N& O6 z# H - new Vue({# \, w' p: x$ k* k( Z; S- ^" j6 }
- el: '#counter-event-example',
9 L% K/ m% } A% |0 R - data: {/ w: u2 ]/ R2 U$ [1 E- d
- total: 0" {$ X( V* B' C/ q A4 N' C- K) w) F
- },
) J) h# O7 \ P5 ]- u - methods: {
0 p/ @ t$ V: Z! x( I8 y$ f - incrementTotal: function () {
+ H0 `7 u" N, s - this.total += 13 O, e6 R% C+ z8 q! h
- }. T6 p9 R/ h" Q4 ~1 `; d7 b7 _
- }, G/ |8 R( `% Y0 g; h) C, E' h
- })0 L- Y! [8 O( \3 n/ ^
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
: q6 N, F" y' W+ y! j; T0 z - Vue.component('child', {
+ d8 f" F7 | X: Q6 b0 | - // 声明 props1 ^) U7 I! S5 a) F( ]' E
- props: ['message'],
* x0 c& ^% d7 \" k% S2 c$ L - // 同样也可以在 vm 实例中像 "this.message" 这样使用
) U9 o# P L5 i' b8 ?3 ] - template: '<span>{{ message }}</span>'9 X i2 w9 V: _. I/ _$ I% c
- })* W& v, H7 z& p [
- // 创建根实例
6 u% T" F+ D! Z) p/ J" N; h: q- [4 _ - new Vue({6 k. U% m' r. {+ x% U$ |4 c
- el: '#app',. u( B. Z- F+ u8 H
- data:{- O% U( X, h7 T: \" T$ S" Z
- message:"hello",
2 `2 q5 U) k( u( J: k, r/ _ - }3 a8 a3 c! j) p$ n
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {) V. H; A& |4 p8 k
- incrementHandler: function (v) {; q1 W4 ~0 W" A3 v; ?" d N: n
- if(v==1){$ n1 X! w# a3 E5 p/ N7 E
- this.counter -= 19 ~5 {% L4 L d% X1 o
- this.$emit('increment',[1])
9 t' |- j; M- i$ q/ [# \ - }else{
" u5 e4 B7 h2 G8 I - this.counter += 1
$ K8 [$ A$ G7 @# f) W/ m$ V, U - this.$emit('increment',[2])( u( d. `; c! ?# A
- }
2 O G) G# c3 W- o8 L$ F - }
1 B" `. C" P2 c. `5 e# R$ r) F - }
复制代码 : b1 i$ c& D) ^) I* Y
9 ]4 h8 W( Q9 c% }2 @0 T( G5 V$ p
|