|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它: $ w! V f7 b$ {" D/ y( Q+ c
- <div id="app">
0 m, x# L$ g/ e - <runoob></runoob># t" {) c& e: T; F
- </div>
( B8 ~8 }. ?" }/ b! u \ - 4 U9 [3 j5 d L/ p J
- <script>- \' e# C; L5 d
- // 注册
; w2 ^, Z. y* ~/ d5 r8 B& F* p - Vue.component('runoob', {
" r1 y4 _) O8 e0 ?) v8 \9 b - template: '<h1>自定义组件!</h1>'
9 W" D: T) ]$ v - })
: t0 k. {$ ?& H( x* V0 o - // 创建根实例1 \2 N; w' A% K5 x
- new Vue({
( d5 I n: G; M5 o2 z0 e, R! @ - el: '#app'( @& O+ K7 e" J
- })
0 @. f. J- f \2 N - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: + A+ }* a1 {' h( w$ k7 R
- <div id="app">: Q+ V( R( B b1 \6 j3 E6 v
- <runoob></runoob>
$ N: J8 I& o: D0 S! C) D: k - </div>* L. N$ Y+ W; g9 m) @
- # Y6 H u, M& J, b& B) _% o( m
- <script>
3 n1 o8 T* z/ m* m2 H$ S - var Child = {+ |/ C% I6 g/ O1 B$ p4 f) `
- template: '<h1>自定义组件!</h1>'
; M& P: t! J- w) @ - }: s+ D+ v. c( L. i% b% q
-
& D8 `6 ?6 Q7 M* z2 S - // 创建根实例
8 Y/ [ \5 `+ b - new Vue({
/ G. A( v1 F7 h/ f J0 {6 f - el: '#app',
' u- v& C# E6 u/ Y9 _3 G7 v - components: {
5 z5 v. {: t3 R& n' D - // <runoob> 将只在父模板可用; O) B% B( b7 W4 i5 R$ A
- 'runoob': Child
% t, g: D2 _9 F' ?& e0 f- X - }1 E- h2 |( N* ~7 d2 J3 s5 |, A
- })5 p9 H4 W+ x( @% |0 B
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例
+ m `+ f0 ^ T, d9 \! b5 n6 b6 v- <div id="app">
" w! ~' l% b3 Q# l1 ]/ X - <child message="hello!"></child>1 K8 C' V- e: L+ C
- </div>
. E; c: H0 T) c - % v5 c" S& m) }2 ~% |% \+ {8 A
- <script>5 P4 q4 w L. o9 I
- // 注册
+ g9 _* ]! y9 Q/ K' h% f# _" M$ p7 C4 W - Vue.component('child', {3 h% A7 J* O) c; {
- // 声明 props
4 a. Y" N. N5 q$ J6 V( Q/ L* ^ - props: ['message'],
, r2 E1 X) s8 z+ J7 Z9 T - // 同样也可以在 vm 实例中像 "this.message" 这样使用
3 _) u+ V2 J& S% K: Z! C) ] - template: '<span>{{ message }}</span>'
8 G+ `$ F+ o( u) V1 c/ B, ~" G - })# x! B8 y7 j, j8 z, E( T
- // 创建根实例
7 u" ~. k2 e# ?' N2 A - new Vue({
( Q0 k" e$ G1 K - el: '#app': T5 u9 o+ n4 L' f$ _- l- B" W
- })5 e1 O$ y I/ r _
- </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
: x4 W; e' `. Y! z- <div id="app">
. }, a' k/ ~+ J - <div>
% X3 M8 Q& D4 L2 V! V# f+ a$ d - <input v-model="parentMsg">
) E. `5 ?+ W* q8 C" p5 O - <br>
5 J( {2 A+ h, ? b8 a3 |- g - <child v-bind:message="parentMsg"></child>
0 N7 V; f1 ~7 ?6 P$ { - </div>
( [8 `' D* e( P6 z5 @, d& O - </div>1 S% F7 Z5 G: y" \4 N1 h
- 3 B# H2 |3 ]2 V0 c% A0 m
- <script>/ D3 v2 I# C9 N* U- m8 b' d3 Q
- // 注册
* `3 H8 k% E1 m; U( K# o - Vue.component('child', {
) X/ H4 O+ i5 M2 l, U5 A# U: v) n. Z3 l - // 声明 props$ v/ i9 c1 g2 W( `
- props: ['message'],
5 m2 F! ?2 Q$ D, b- Q0 f' u - // 同样也可以在 vm 实例中像 "this.message" 这样使用
$ @/ @3 m9 {" `- \& b1 e9 r - template: '<span>{{ message }}</span>'
. `, n0 b$ Z) u# @7 j' Y P: s - })1 F0 f2 K8 p. }. q9 r( N$ S/ \9 x- ?
- // 创建根实例
?. e7 ]' E* q* @4 i; @/ N" ^" {$ W - new Vue({
. s$ K) b x2 Q( t9 c - el: '#app',
% w4 e: C; X) V) g2 I9 X - data: {9 L( u0 M" X( \! F L. @: R
- parentMsg: '父组件内容'
, l6 m, O. v% N# Z- q0 b. f% Z2 U: J - }
) @: S1 ] `1 f8 h4 ` - })
+ R; q& \" E4 N6 P& s - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
# V8 W# v) a/ D6 q6 S0 m- <div id="app">: L7 u, O6 I) E2 u" v
- <ol>
4 R$ n. H! ~! ?# H4 _8 q4 d - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>+ |" R g# N5 z8 K' z4 p
- </ol>
H! \. S7 s' z/ R# f7 e9 a0 G- Y - </div>
6 Y/ h( Z" S( P3 S6 T: L6 ~: i -
& p2 B! g7 b' f8 }* q - <script>4 K, N- N$ p! m" N7 G! _+ k- }) K
- Vue.component('todo-item', {
/ a1 ~ ]0 z; H7 u( j; ^2 o- b5 T - props: ['todo'],* s8 B4 `9 ?7 ?% x& e0 x) c
- template: '<li>{{ todo.text }}</li>'
9 @# F. t2 Q, w6 s! j, U8 y - })
# i- I! A) l' g - new Vue({
; {6 D8 E2 I' I7 Z# [) ]/ q# t - el: '#app',
& G' s3 R& d3 ]+ ^0 ? - data: {
9 d/ J8 \& U% s: w - sites: [1 Z! m- w- r! N
- { text: 'Runoob' },
1 `/ y. D* _+ n" V: H) o - { text: 'Google' },
2 w+ T0 ]: M' x5 u - { text: 'Taobao' }
2 t2 l( z1 [; D4 E2 p& T: d( U - ]
% X4 c+ s( U. y - }
% d7 y, _! H+ H/ _# u7 v/ V7 ] - })
/ h. G: \! k! c9 s - </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {3 R L+ x E3 x& l. a7 h
- props: {
/ }1 Q6 o4 u- I" _ w+ P! _ - // 基础类型检测 (`null` 意思是任何类型都可以)
3 b6 }! u* g q. W - propA: Number,8 ~; ^5 X8 R6 Y- u1 u
- // 多种类型( s; A: R" ~! v/ Q6 Z; p
- propB: [String, Number],
" m! ?" J: _+ d - // 必传且是字符串0 s. x3 e1 k' R" B
- propC: {
5 Q* V5 K1 K7 Q' S2 R3 i - type: String,
5 M& F, c0 b" t4 }, { - required: true P5 A7 C( ^( v3 q
- },# Y" P$ F; o+ z$ Q( f, C9 ^
- // 数字,有默认值
O! F6 _% `) l. A - propD: {* x' K: F: |! y7 L
- type: Number,# T$ n* _) A- K$ F# T
- default: 1009 d2 N6 n+ |3 I$ t5 \4 c
- },: y, L" Y% | s! H1 {2 }
- // 数组/对象的默认值应当由一个工厂函数返回
/ k. I1 z6 N8 }0 @/ X5 i2 C - propE: {
' M1 X, d& W7 O - type: Object,
/ J1 h; t' X6 m7 t3 u2 @ - default: function () {: l# ]: G5 J8 ?7 I- m7 k5 `+ K' r
- return { message: 'hello' }/ n4 H) y& e; k0 G7 d; u, F+ T1 e+ e
- }( Z7 k; L4 Y6 X9 g9 P/ o9 c/ j& m
- },( z" \' q+ D* g, T) e9 }9 `; C
- // 自定义验证函数$ c0 k+ M( _8 N+ ^
- propF: {8 A5 A( H/ p6 {5 P* t4 _* ?
- validator: function (value) {
6 b* v$ B# e, T: A% `9 L; | - return value > 10
8 Y6 Y+ }/ {3 z; S% I1 L# L - }4 p) G& A0 @1 }; D
- }
! v0 o- m1 z2 M" n9 L - }: l+ D6 j# R" `5 E9 q5 z( v
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array# @: ^+ i7 K; o' j# Z# @" X
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件% Q5 C/ _% O% {* J: u0 d
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例8 o4 S8 ]9 Q: ]. I8 E) x4 A2 p
- <div id="app">
/ d! F1 u& \1 _ - <div id="counter-event-example">6 o, r+ r, G' S: l9 C; A: `8 T
- <p>{{ total }}</p>
8 e! ^( x( o0 f p - <button-counter v-on:increment="incrementTotal"></button-counter>; I, w7 ^% X; x& w& g: J6 x$ W
- <button-counter v-on:increment="incrementTotal"></button-counter>3 K/ ~2 t) l+ B: @
- </div>
6 _7 y# U9 T& m2 B- l3 \4 w - </div>+ k0 u) r9 B* t; j- S" E
-
% b i2 r U: |& I$ g - <script>
4 S" }8 J2 M6 D - Vue.component('button-counter', {
! U& a3 Y- }8 e2 K! L5 X' S7 T N) t' r - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',) o* V; o9 D3 G2 g
- data: function () {( \2 i6 q2 @/ Y8 @* ^- \; H* ~' F
- return {: c9 r: e8 W2 L
- counter: 0
1 c% s1 x9 Z; j& v. n8 x3 C9 ] T - }% q& J( C. n( y& X5 H J c
- },
2 w' j' W! S" F - methods: {
6 r% g: F$ P. T# B - incrementHandler: function () {* I5 G8 I9 g; \; o/ u- H/ r
- this.counter += 1. P' ^' H2 o( l: E; L. J- T
- this.$emit('increment'), p, T& `4 A6 B8 x1 \; V
- }
0 P U1 Q5 ?) S: g - },
& y. z% i: o" M- G* s1 a* @" @ - })
2 j) g- ^5 u- D& ?2 \ - new Vue({
/ L% V: O& E# P# W% z: E4 b - el: '#counter-event-example',1 c9 |4 b9 V" m) r. Q
- data: {; c$ v' o- P o: ]5 \
- total: 0
% r. b& H$ T1 G0 e) D4 [- M9 U5 Q - },
' c2 q% s6 L* { - methods: {
# E# C6 _1 w1 O - incrementTotal: function () {
L9 d I& l+ i# N1 ?, B# K - this.total += 1: J+ ~" z8 f: f6 u, X" H
- }# c( W/ Z0 r( \" o
- }% @+ c B: h* g& b
- })3 D0 X. C) y% [4 ~3 f+ U
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
2 O, h9 q( V7 Q- \; A- z - Vue.component('child', {
5 x: J7 e) d4 c# J( @1 [ - // 声明 props
3 F$ G' N$ a' u9 T. V0 e6 D - props: ['message'],
! S" J+ ^+ C; f) p" `) y/ @4 D8 x/ Y2 f - // 同样也可以在 vm 实例中像 "this.message" 这样使用
, G) ?# Z( G& l0 k" G8 I, ] - template: '<span>{{ message }}</span>'
8 {9 M& p6 r+ H - })5 A1 M* o' K1 h( l6 i
- // 创建根实例) Y! p% O. U' a& p6 |1 ]1 \; a
- new Vue({% _) k8 r3 m0 q. I" ]
- el: '#app',
* j- E2 i2 p1 | - data:{
4 ?/ t6 G1 ]( {+ p - message:"hello",% r* M6 Z; O8 |
- }
& Q! a" _# N1 f" k) f- G/ M - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
# }9 C. i/ A1 [" z - incrementHandler: function (v) {
- X2 X$ ?& z0 N: \- e - if(v==1){
$ F( s& W/ f/ F: |1 M, l - this.counter -= 16 {% i! V* l9 P0 h/ S: e! |4 o& E4 |
- this.$emit('increment',[1])
7 ?1 E3 F9 I: `4 B; ^# ~7 h - }else{
9 E! A* H9 L6 o6 E9 L( Z* e - this.counter += 1
" k9 q) u8 J1 g5 o# \; h - this.$emit('increment',[2])% X/ S! e. V4 `* w N, M, }
- }
5 O! e: N0 u- C% U: y! a - }+ r1 ]* [' F9 w d" S/ R \8 Q
- }
复制代码 ) {8 f% a2 h2 s( b4 b" t
! H* d! ], x% ]- U) [+ h
|