|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
5 R* \' ^7 b- ~2 z- <div id="app">
5 n4 l; _& o5 g% j - <runoob></runoob>
- q g1 q& h# t3 T- U9 b& R - </div>; l& ~; o8 X' e, N4 r; C
-
0 W: e8 K' v$ U% V) Y: _ - <script>/ A/ f* W; D( t" v6 j. n
- // 注册
' T9 w' `: T; W* z* L - Vue.component('runoob', {
e+ ]4 _6 c" p T+ t( }* S - template: '<h1>自定义组件!</h1>'8 n; o% D6 {# X# u& D
- })
6 J( S6 K- _4 t7 a - // 创建根实例
1 W0 M0 w4 p9 p - new Vue({
+ k$ f$ ?: R& `; E - el: '#app'
. `( g( v3 w4 U5 ^9 J - })4 [% i3 k( T: U8 u* a
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它:
6 Q' C0 S. t( [& n* g: U1 c- <div id="app">9 F# t$ _3 n \% p9 w$ ?
- <runoob></runoob>. A) w; E3 _: S- y! V
- </div>. r! }7 w* ]: B3 F5 w3 ~0 {
-
3 j5 ?, H+ J: H( G - <script>
7 v. e* K# X- {) | - var Child = {
" b+ } u/ Y3 T a& I; r - template: '<h1>自定义组件!</h1>'
9 I/ ` }4 }5 i/ v3 Q3 U; o1 e7 Y+ h - }6 u" ^8 _. R" W1 H& y) ?
- , @' {. G8 v! I$ J7 s9 t, v* n
- // 创建根实例$ k/ v2 W& q9 p" k& b. E0 z
- new Vue({' W2 G2 M1 R e) n+ F4 A2 K
- el: '#app'," a2 p, ~% M! b' [8 O
- components: {
/ T0 p" u" o5 S) f, s& U. _ - // <runoob> 将只在父模板可用, Z" y5 ]' b6 Q3 h4 W* k5 X e$ e
- 'runoob': Child
5 T" [0 G+ X0 m6 T - }
, E- X, o( E* g: a5 R0 {- w - })& v* U9 s. m2 T: \. P3 b+ z* W
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例' X6 `# a/ o. S" v8 f8 Z
- <div id="app">
5 \: U! J# s1 p+ w$ F: r - <child message="hello!"></child>
! o4 l& ^* V# s1 ]' U - </div>
' c/ }- u5 \3 C! p! l7 |$ n - : F2 a- t/ m1 b/ P
- <script>
, n- z+ m$ n8 x4 M& _: X2 B/ y - // 注册
j, Y; _9 p2 o8 p - Vue.component('child', {( ^, ]/ k1 N# @4 O. b) p9 }
- // 声明 props0 J5 \/ h! u6 X
- props: ['message'],
9 G- d8 q3 S- n, G) b/ K - // 同样也可以在 vm 实例中像 "this.message" 这样使用* V6 i1 K% J2 f
- template: '<span>{{ message }}</span>'
9 Z( R" s) g2 V8 \8 ?3 V; J( c - })7 r u( Z. s5 s6 ?
- // 创建根实例
' C1 k6 w5 L& ^- z6 G. e+ ^+ a - new Vue({! t2 Y8 |# L: r) v1 v
- el: '#app'
" V& Q s# f' t3 @! r! X0 e+ M. U - })
5 c6 M1 `* V8 H4 u, j Q" U - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例( m2 ]* Q$ L k+ @% |! D/ A
- <div id="app">
8 E" A& V8 U- i - <div>( B4 J( r. ~0 R7 E) R& H
- <input v-model="parentMsg">! ]$ g1 X A: ?: }" H8 Y2 ?5 k
- <br>
/ d0 n, B4 ]* p& ? - <child v-bind:message="parentMsg"></child>
7 w2 s& a9 d" ` v$ k6 D3 x" ~ - </div>
( Z+ t3 Y0 w( x- R" q2 R7 D - </div>
- L0 j( G5 E9 C, h) k - , B% I9 H' D* v/ o: M' J# t
- <script>
1 x# z7 J$ B3 N, H5 K - // 注册
6 C# n D$ z! }, @+ Z" f% O - Vue.component('child', {
8 l$ `& N4 B+ O - // 声明 props
' j; i: b( `( J3 [! J0 g - props: ['message'],
3 h+ d- l6 `) C& l$ Q h5 X ] - // 同样也可以在 vm 实例中像 "this.message" 这样使用
! O: Y8 v: M1 P - template: '<span>{{ message }}</span>'
" h" `8 ?# B) L - }). A+ p7 G" q z# n
- // 创建根实例) m7 {; R, K- l: _
- new Vue({7 e1 q% }5 N7 g0 F; a; a
- el: '#app',
' x/ O) b- `5 |) m1 v1 q: v) C - data: {
2 {% ~, m" q4 ]6 u - parentMsg: '父组件内容'8 x/ A1 p- `* T+ i$ t
- }
3 i7 D. q6 o, V& V: r g - })
+ K- v1 x1 b5 B# Y1 d Z - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例& `* F: r* F5 r, k1 T/ R
- <div id="app">9 Y2 f+ E6 c: [
- <ol>$ s- Z" M: d6 g/ U
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
5 N5 o' t$ z7 C9 f4 s - </ol>
3 W/ Q# r$ g/ X. z8 {+ ^' _ - </div>! r6 g6 ?5 R/ z) ]! P, j' X
-
0 {1 j4 _/ G" n+ b! E+ i - <script># }2 G: [" A4 m( X; M( J; a) }
- Vue.component('todo-item', {
) i, D$ T( I/ l4 b: v - props: ['todo'],0 d" K7 y! N1 I) `' y
- template: '<li>{{ todo.text }}</li>'! R9 T6 @( K5 a! u
- })
, t- ?- Q5 E8 N0 I0 b8 Q - new Vue({' w) L8 w8 K+ j3 I( ?/ @2 z
- el: '#app',; U) t3 ^" Q& I1 o# P
- data: {
+ @2 u& h7 B5 J0 N& D% S - sites: [
4 c. k, |/ ]0 G( A- W - { text: 'Runoob' },3 u" x7 Q. v* N
- { text: 'Google' },
8 O- F+ {7 m( I+ P/ g U. ] - { text: 'Taobao' }+ v. H4 @" g6 U8 f
- ]
. p% b5 Q4 @( r- V9 ^% U! [4 _ - }9 i+ e8 r7 E0 T; l4 x+ h" `0 ?
- })+ _ l0 u! s( i. N, V/ W) F! G
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {7 t* ], u) x6 Y4 A2 `& `
- props: {4 V. v4 q- t! w. W# y) L2 r5 I
- // 基础类型检测 (`null` 意思是任何类型都可以)2 V5 ^. C' |/ d4 X
- propA: Number,, }9 f5 e1 r* q8 \7 m+ r. G9 X4 F" Y
- // 多种类型( x) a4 }! S% l g
- propB: [String, Number],
3 v% O8 A% ?$ d1 [ - // 必传且是字符串
$ M( n- D9 ^& C6 E! |+ q, R5 r - propC: {
9 M6 r$ x" j+ P3 g$ ? - type: String,& }2 A0 i9 C. G( r/ x0 a3 h
- required: true; t& d& e' [+ V* a% |
- },
' c" U" P E, w: I( h - // 数字,有默认值
/ ~1 o$ }( [5 s- w) k& m - propD: {
% E5 y* B0 q s4 p# O0 ?. Q& u/ \5 l - type: Number,- Z$ z, u8 [! q) Z
- default: 100
/ z& s. A( h" s6 e, v* B% ~. F - },: P- v0 J6 |; d* ^( J
- // 数组/对象的默认值应当由一个工厂函数返回
0 A. p+ o2 c$ a6 ? - propE: {
9 l% h' f+ F& k9 l - type: Object,
1 e, a) K I3 ~% \; x3 e - default: function () {
, V) v4 }7 S' y3 f- H: q7 M5 z - return { message: 'hello' }
9 e, P+ F3 b; i9 s" \$ x - }
! X! W q3 \3 N5 p7 a) e0 } - },
& w4 U/ k0 O' f& L, S$ O& f- T; M - // 自定义验证函数0 P3 V5 z6 d5 E
- propF: {9 d& O E. z G0 \
- validator: function (value) {. N( n; b& \6 P
- return value > 101 g( X! H9 H! K0 I6 Y9 u# p9 \
- }
7 p% M, i! Z R/ K' q, n0 @4 H - }
$ m A3 ^9 ]+ B+ J6 h - }
& x. F9 Q# l8 J1 S s1 F& z - })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array! ^! ]- M6 U+ |$ [; ~
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件. ^2 I* z7 v# ~' L. P/ G7 { D ~
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例
* q S, n8 M) ~8 ]8 n! g- <div id="app">; O( N4 y/ ~7 ^' _$ [( T
- <div id="counter-event-example">$ ? \& r. v4 E% _
- <p>{{ total }}</p>
* |% m w1 r t9 G( c# X, \% S - <button-counter v-on:increment="incrementTotal"></button-counter>$ o+ O) `9 |% M+ e7 r# f
- <button-counter v-on:increment="incrementTotal"></button-counter>% M' J$ n$ C8 s* G+ h; D
- </div>
- M# s! X! q b" P - </div>) J, N3 Z, F4 s: }8 \5 ]
- ( m* Z" X6 f$ r/ `
- <script>" ?0 y' m% }* t. o; K
- Vue.component('button-counter', {
3 L$ h% C9 w: A4 a3 C - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
) ?7 M* t2 ]7 {, J3 y- |* P k# d+ q - data: function () {
; @5 k' `/ x% }- N- q R. I - return {
3 a; F& ]" m! K8 {- L g' x - counter: 0% ]7 G- [1 x& o
- }
6 u: P( t4 ?6 J: B0 {. S - },
& x7 Z7 y& ~6 {: y. P% q - methods: {
0 c* |% ~; h3 X - incrementHandler: function () {
- b, F$ X8 q, `6 N' p- E9 i; i - this.counter += 1
; P) U5 F% N* I2 N - this.$emit('increment')! i4 c. D% J/ K7 _$ b
- }
. T: S& n, R4 z' y - },
, Z/ v* h$ ]6 b, I3 L) v1 I3 W; { - }) J W+ i! R) m% B$ p, s
- new Vue({( H* i% d3 C. z/ a' Z$ Y
- el: '#counter-event-example',, Y+ d0 t4 T% G8 W @% P& c1 |
- data: {
3 \1 ]1 |, ?) q! M7 H - total: 0
0 |" X: S( ^9 B& }7 w9 j - },. g2 @; _+ y9 `& H9 S, M O
- methods: {
6 i8 e5 g; r, x - incrementTotal: function () {/ H, {5 e$ u2 B; F
- this.total += 1
6 ^1 ^3 x7 p# x- F X - } v$ L% @% P- A; U' L9 ]
- }
8 ]/ G* o% y% q4 x8 { - })/ @: H0 U1 w2 q* d' f
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册% K' _6 |9 Q" N4 p3 U K/ y/ j
- Vue.component('child', {& C2 g' R9 L3 H1 u$ ~$ B
- // 声明 props
; m" D; ~! ~: T- Z - props: ['message'],
) Z( i& y$ M& L! N2 ] - // 同样也可以在 vm 实例中像 "this.message" 这样使用6 A- X1 Y8 I# N5 Z' X4 s$ n
- template: '<span>{{ message }}</span>'
! [' L0 q1 B. b* C; g* z2 G+ A2 d - })
( D5 S& `2 @8 X/ L( r% ~ - // 创建根实例7 n, S; i! W: s# X1 C+ O9 x) O& X$ _
- new Vue({
& g$ A9 G* W+ T7 H v/ }0 T z2 o - el: '#app',
! N" K Y! F8 b" D1 X4 [ - data:{( b' Q1 T# B, M. K" K9 [9 z
- message:"hello",
, w8 q6 L8 c. m+ X/ ]* Q1 A - }
! }3 s: l: g* W: X - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {( J7 |$ [2 E* |# e3 D2 w Y
- incrementHandler: function (v) {
) C4 N6 g6 ]8 v& s6 g - if(v==1){
8 n% ?3 R! n4 s# n& Y5 D$ B - this.counter -= 1
9 t7 K7 s$ n, p O- e- e - this.$emit('increment',[1])
, m+ a6 y% ^, r k- v( f ] - }else{
; D( n m4 t7 ~ - this.counter += 1
) p$ \6 W* X- [* O5 \ - this.$emit('increment',[2])# e0 |7 C: x6 b* [- ^. ` v! X1 U ~
- }; z( D- ]- C8 z {2 Z& F
- }0 f8 \- p. {9 l) l; W8 A$ m
- }
复制代码 ) X/ x( w. ?$ U% x
7 F3 V6 U- I! o% q, v' h
|