组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
9 B* w* l' ~, ], M W" W- <div id="app">
% b& \* `5 \" g7 E$ Y/ V - <runoob></runoob>
* O- d6 _" C/ D2 p - </div>; X5 G( p4 J4 z7 g' B+ u
- - [/ w! O& j/ u1 H8 @7 b
- <script>7 [; C9 e9 t! X# d0 g# f; X0 X0 z# A$ m
- // 注册
" z5 A& s, ?; C- ? - Vue.component('runoob', {/ h8 |( `6 D t7 A& Y
- template: '<h1>自定义组件!</h1>'% ]+ b, z4 r8 e0 I" U& ?
- })
8 S A, H* I8 Z6 ]" b" Q - // 创建根实例
9 O2 K9 |, D- ]8 N' u: z( @" J - new Vue({
; k. \4 w& \0 W& i5 k4 \ - el: '#app'
5 Q! E& b* H9 a( d, r6 D - })7 s# ]! j# \$ k( `8 R) x
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: 8 F9 p2 [, L' R. s, w3 j" i0 t' h
- <div id="app">
, `( I& H/ L, H3 w6 A# {& j) k - <runoob></runoob>
3 k% J5 |# [4 m# Q - </div>" y$ M+ m6 ^- F0 d& {. }0 }2 a
- 5 y5 r9 C4 d8 Y; n9 A1 ?+ I4 t
- <script>4 ~' j& m$ \% b
- var Child = {
; q4 s6 q2 a8 J. F - template: '<h1>自定义组件!</h1>'
6 }$ O$ ~9 V% v5 ?7 E d6 [/ b - }) R2 f8 _3 v/ P
- & y. B. m( Q6 f( l" r6 H
- // 创建根实例: Y2 @, l" [( F
- new Vue({
( P1 O' ~4 K5 G: c - el: '#app',: m" Q& y# ~+ k$ ]+ S
- components: {
1 O) |. c! ?6 u# m7 J/ Q" n, @ - // <runoob> 将只在父模板可用' J$ f2 |, X, i& K- S# l: I
- 'runoob': Child
; A3 B3 F0 s, Y$ Y* C# b - }
0 j* J% d" w f; [. k* D - })
4 H% o7 B6 q- Z: s1 L - </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例4 k; Z* C5 _& i I: h
- <div id="app">
# W" D2 \# T! x D7 @ - <child message="hello!"></child>; h: d( y6 y$ _& n5 }
- </div>
: {. F4 R0 ^' a% p! O& r& [& i+ s$ Z. } - 8 n! M) Q" D" M
- <script>- o4 S+ s( |2 H" u. a5 L
- // 注册
5 L5 P- t, X$ z! N - Vue.component('child', {; c6 f/ |/ w5 ^6 B: f
- // 声明 props
: T- b! J3 q* K8 {. g2 e- Y0 @1 X - props: ['message'],9 C% V. H+ i* V# s
- // 同样也可以在 vm 实例中像 "this.message" 这样使用5 |, O, e3 V9 d
- template: '<span>{{ message }}</span>'. |- X8 i: L% p1 L( W
- })
9 B9 Q" z& u9 S# J7 M& C5 y2 ^4 r - // 创建根实例+ W. V$ d3 q: s2 E3 \" t1 |
- new Vue({- g% ^8 c) w x$ ^
- el: '#app'$ i& d$ E) [* t7 s
- })
9 o) g! Q' R+ m8 M; B - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
5 |! L5 S& t% ]) a% @$ k* v6 ~, }- <div id="app">
: Y6 B, y: D) J4 ]3 o' K4 m* v# M - <div>- g/ h0 [& E) c0 Y5 A7 S
- <input v-model="parentMsg">
0 E+ h+ e+ A$ h9 Q. p - <br>% ]. f$ Z3 F& M2 _4 X* b
- <child v-bind:message="parentMsg"></child>
( _( U' k# H4 y4 @! T - </div>
0 s/ g1 {! W7 u7 I - </div>
E* t6 u) B6 x" }2 G2 G -
. J- }3 K S7 i( M) Y; L" j' H1 g" V - <script>2 j3 C; `5 L" l1 I) R) c0 O
- // 注册% Q# ?* X" j4 c$ K$ R3 `
- Vue.component('child', {5 P; U# {, y) h( M" B2 X' J
- // 声明 props( p: J! t5 J3 Z ~# i. p. U0 {
- props: ['message'],
' B5 K! G( V1 \5 L0 y - // 同样也可以在 vm 实例中像 "this.message" 这样使用7 d% G" u4 u& ^' ?, t
- template: '<span>{{ message }}</span>'
9 ?0 O1 b ~) d& w2 H1 c0 Y! w - })
) i9 f( u) l! q8 [( z/ F* E% E- A - // 创建根实例' @6 |/ F; T* a0 U! }: m
- new Vue({2 |1 C. Z- M! L, w
- el: '#app',
8 F* ?, x; u8 a6 Q - data: {6 R! [' |' @0 i7 E( D/ K; S( Y
- parentMsg: '父组件内容'( J* c% i7 J+ \' ^& O$ E. N% \
- }" F$ v } o- r V* ]
- })/ c1 C. W4 V. n$ ]* K7 I3 |5 t; l) ^
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
& S0 a8 _3 K2 w0 |, E7 ]- <div id="app">- ?2 w% h+ {) g$ [0 g
- <ol>& m% X; `- K. x+ Z" H( [* V
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
( g% H2 D4 `6 Q. J+ Q7 U. A8 |4 f7 W - </ol>6 N6 f/ e; [6 I7 _
- </div>* C& I) n4 i0 G. d3 i: F
- X9 } P2 X0 z1 ~8 T0 A
- <script>
6 T0 \: L; x) f& e1 @0 L - Vue.component('todo-item', {1 k4 ^! e" @2 l! ?& `
- props: ['todo'],
6 l8 c; t% {2 I9 N9 c7 j2 l: l - template: '<li>{{ todo.text }}</li>'
- \* c, `& g7 M: _7 s - }) b3 u. B1 L4 Q3 A) U2 L
- new Vue({4 C m9 ?# f" g9 h4 R+ ^
- el: '#app',
, s5 ?3 X7 I/ w0 k/ b; ]! ~0 K - data: {; _- M& k Q+ C. U( k& E+ P
- sites: [5 {2 Y+ c6 R! S7 N. ~. b0 w" q
- { text: 'Runoob' },) R$ e" s! v" Z: p- s0 s
- { text: 'Google' },
) B4 | R( B: G - { text: 'Taobao' }' [# Q4 ~7 Y% d- Y
- ]
2 n# {3 v' A0 | - }
: a0 d( ^* \& H2 a - })2 F9 ~$ h: c6 M F$ ?3 a5 ~5 V9 l1 H
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
8 S# a: T; ~& Z: {, C* Q7 Q - props: {; I) |& R1 m% O" S6 m
- // 基础类型检测 (`null` 意思是任何类型都可以)* U! r1 F+ w0 Q0 z$ |+ c
- propA: Number,
: j4 O- s3 b' V M - // 多种类型
* h! d9 z0 b+ f - propB: [String, Number],# Y9 E1 O6 [, h3 _ l( i) n
- // 必传且是字符串
0 R8 A3 {+ w$ C: T' H% w) ?% X. I - propC: {% q2 r7 y8 j1 V' l ?
- type: String,: N6 t$ [) O1 l' v0 G4 i
- required: true
6 [4 C. W% }7 }( n - },! n2 p8 h+ k6 u# z$ H0 K
- // 数字,有默认值9 R8 P* N$ q2 [, k
- propD: {
2 s) Y- i2 w& O" f8 N - type: Number,$ y4 |( S3 x6 k8 x
- default: 100
0 q% x( u `4 j) L6 }/ Y% I - },
& r/ s/ b- n/ I/ q - // 数组/对象的默认值应当由一个工厂函数返回+ u0 a2 n# l8 N
- propE: {* F1 l$ o4 l: d
- type: Object,+ _7 _# }. D! r) G
- default: function () {
' f' \# N0 A6 W: x; K. f' H - return { message: 'hello' }
) |4 d- j2 q$ Q% O! e \% V3 @ - }
+ P& z" j/ ~! L - },$ T2 n" k% O' f7 _
- // 自定义验证函数- E+ ~! H: I: W5 O* |: i
- propF: {1 y: _ ]7 z3 ?9 N% h
- validator: function (value) {+ I, i/ L; |* h1 @+ R8 I9 ?
- return value > 10
3 M X% b& [/ a3 `4 S1 k8 c. d - }
' C' e1 j* B5 i9 M; H - }
5 t) {+ W# s, i6 `7 o - }
0 S) R8 D# a- }" a! k# p - })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
6 X0 B1 B% a$ j/ e# R# B
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件9 f$ r5 |8 E( g- O H, b
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例* ~. D+ v" K; Y9 v+ {) J
- <div id="app">
" q7 z; ~% r7 U. ^/ s - <div id="counter-event-example">' V& x% `4 c& Q7 O0 l: A
- <p>{{ total }}</p>& d: @& b: C2 {- m. L% E
- <button-counter v-on:increment="incrementTotal"></button-counter>
6 h9 i, K/ O& D- U5 L2 F7 K - <button-counter v-on:increment="incrementTotal"></button-counter>+ E1 F1 p* n- u2 `. s" A
- </div>
* k8 h5 b1 h& q2 ? - </div>
, V2 K% l& q Y- Q, A8 e* m2 N - ) w# V6 e9 T P: l/ }3 m/ R {+ W$ y
- <script>
% b% f# @# M0 u$ U - Vue.component('button-counter', {
8 j& Z1 }& y( Q$ T( B, u" Q - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
2 }8 M- M+ \& Q6 d - data: function () {+ j; S) M: s# T, u$ I- G2 e- B5 Z
- return {
/ ^, _/ Y$ M p/ q- t9 X - counter: 0( l' ~7 h5 T0 R) f
- }
9 ]7 x( |+ Q0 x9 \* E( X* {3 A- v - },2 G/ C0 j2 d9 o2 \: f/ b" C4 R# w
- methods: {
( E7 W- c: h* c" O3 q) H - incrementHandler: function () {
, z |0 G0 s4 L7 j - this.counter += 1/ I; ]3 w" M d$ g% N
- this.$emit('increment')
: g, O. A' e! L; a% M: g6 F I - }! W& T! I$ j) R
- },
# G O9 o- U9 t. ~: P - })$ V, T4 F' f/ _& _1 d$ f3 A3 z
- new Vue({
- J% F( | S; p8 r) O0 V - el: '#counter-event-example',: u7 }; F) ]; ?; ]& g( Y% W
- data: {
/ w: Y) k$ j' d% ^5 ? - total: 0( B5 n; E v# y/ k
- },2 Y: @2 f# H! U% r
- methods: {; y7 l& t% E' G m
- incrementTotal: function () {
* A4 k- `* H E( _. j% i - this.total += 13 n* | `8 z5 g D
- }
E. \1 B' \3 G" h# g" t; R" Y - } ~3 V& D( m. Q7 p
- })% |4 ~ o" w+ M( K7 t
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册) }1 D. {" I) P; L
- Vue.component('child', {
6 |. E% O. d& y+ k: A M1 j - // 声明 props
* E) _0 h9 K5 Q; z3 Z2 H5 Z/ ?. j - props: ['message'],
8 q" _3 n9 }6 l9 G7 w3 W. { - // 同样也可以在 vm 实例中像 "this.message" 这样使用9 B5 a+ O3 U( h" _6 e
- template: '<span>{{ message }}</span>'& t z! G+ [; [" ?6 K3 E. j0 q8 G
- })
' u/ H. U* u, H - // 创建根实例
/ R4 _" W5 A \ - new Vue({
# x2 H0 X" D3 Z+ E! g' C - el: '#app',
! ~. u/ j5 x3 e/ J1 w - data:{
a% ?" e& v5 p5 R1 X& k, a3 ~ - message:"hello",
3 h6 h% P3 x' I4 u" r9 `0 v - }5 o, c% x$ r8 { _! E' h6 J
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
2 f, ?1 [5 k8 u f$ }4 ] - incrementHandler: function (v) {+ s, k% Z- B. R/ ~# y
- if(v==1){
* e: o8 w( P- D: B% Y - this.counter -= 1
9 q8 Y( R j* c) c1 x - this.$emit('increment',[1])
) J9 A: h x9 V8 f; q - }else{
. j, F$ @7 h* E% o" e" x - this.counter += 18 N4 m; ^, D9 F( g
- this.$emit('increment',[2])
5 N2 t, r$ M" s$ V; ^4 Z - } X8 R& ^* ]! J
- }6 o7 ]$ w7 c" [+ `$ L3 `
- }
复制代码 4 K& U. T6 C2 R' g
3 Q# N2 {8 Y1 q) r! u |