|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它: ) h- ]7 w* N/ M$ K/ m! A ?8 o
- <div id="app">
6 e6 n$ ?' c+ I: H7 I. s8 f1 ? - <runoob></runoob>
6 m4 q* v' G1 \8 O& H - </div>
7 D1 `1 r" B( w( _. u - 9 X! d, a2 W% B7 t
- <script>; n* G$ d, H& e; v- T* e
- // 注册
# b z( G5 Z5 Y4 E) }$ A - Vue.component('runoob', {/ z L% V" L1 Z6 d/ E8 I6 E
- template: '<h1>自定义组件!</h1>'
/ K" ]6 O/ Y% V( y3 [ - })
0 v) n! _; m% a - // 创建根实例; V! C8 {) J7 l! L( z
- new Vue({
% J8 f+ q. l5 i C- q8 O" [* [ - el: '#app'' Z3 E/ R2 H: f" ]' l: u
- })
- O' @9 x# b, T3 Q4 g) @/ W - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它:
. h. j3 Q) \/ Z- <div id="app">
T) B B+ k9 u H- M# M3 v2 j' L - <runoob></runoob>& D( J- Y- a" ^3 ~* ?* C& i/ B
- </div>8 t- T7 j, j$ `- G: h
-
$ u1 b4 Y; }+ M( ?* i% \ - <script>
' d4 K* C# e# W0 S2 n, [ - var Child = {0 J2 h( T5 _! T0 L" j+ `0 C+ E* }' e
- template: '<h1>自定义组件!</h1>'
8 b8 j& |8 e5 r1 T1 V( B - }
+ a+ {( C$ v) ^, k -
2 o) n! x0 X, g - // 创建根实例$ i5 u" o. \ f8 U. P/ E
- new Vue({
- o4 p2 v1 ]3 b% @ - el: '#app',
6 Q; L7 }7 D) d& \ - components: {
- m) j, O( Y6 R; F - // <runoob> 将只在父模板可用
4 D4 _# d4 ~8 [; A+ e: r - 'runoob': Child
6 y; ], r+ ^* U+ [, G2 n2 V* A - }
5 b P3 @( T: |6 u! A - })3 h% M& G+ n4 X& s0 q1 D! U% [: t9 z- c
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例* _# S+ P4 f( Y- U7 V+ n
- <div id="app">4 g N' U0 ?. \0 m g
- <child message="hello!"></child>
) c* R% K& Z H" i$ f3 _8 F% N! w7 i - </div>8 M; w8 x. B2 `0 s4 T/ r k! w
-
) \0 X8 V: I9 V& |3 s& A3 V" U9 r - <script>
. e+ s, t/ k. H7 |1 ?( S6 y2 j( ? - // 注册6 J, T/ E: C7 E! i4 w
- Vue.component('child', {; R) _$ k3 R. y& i5 k2 |
- // 声明 props" B5 f' [8 G! K# k* [6 ?4 m% k4 X
- props: ['message'],
% h' i- l- H0 o - // 同样也可以在 vm 实例中像 "this.message" 这样使用! ~7 m$ a# V4 f* \( d
- template: '<span>{{ message }}</span>' w# G2 \8 y: N0 q/ k7 { u0 H: p
- })
2 q* V, t( W4 a( t - // 创建根实例
# r" Z5 ~, x. w* y( j3 y" j1 Z" @ - new Vue({
$ l* v+ z# H2 c/ Q$ E& w - el: '#app'
! c- l& e; k$ \4 V# u - })
3 U( s7 }5 o' Y - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
' Z- P) J8 b7 L; u1 P- <div id="app">
9 g; O/ \+ n' L6 }7 j - <div>
0 v/ g' U. l& s0 Y. U - <input v-model="parentMsg">
/ x5 P6 F5 a2 S4 O0 q8 I% J - <br>* t8 I- |" }0 n1 H
- <child v-bind:message="parentMsg"></child>
5 @9 g2 @; a* N. K, t: Q# r - </div>0 J) _1 d/ r6 _2 J9 `. W
- </div>
) L; F- H# V$ H+ }4 l w -
# a# L* S6 Z/ h! R6 I+ ^ - <script>7 k/ L, l% p& J/ E, n: W! D
- // 注册
5 P' u! M: f2 b( E - Vue.component('child', {( S. l; z% o: G* P3 f7 _
- // 声明 props g$ ~, I- W; e( g, D* E! X7 z- h
- props: ['message'],% I0 n3 e9 a' L3 y+ O# W0 g
- // 同样也可以在 vm 实例中像 "this.message" 这样使用1 ~( ]* V5 J8 s) T$ N; m% l
- template: '<span>{{ message }}</span>') n) O; t8 V: N7 Y8 \2 P( G: l
- })
1 C9 M( z% L9 t! O' w9 } - // 创建根实例; H- D0 K" `1 N
- new Vue({
& Y- v+ k: Z$ `* n - el: '#app',
6 Y$ Z0 Z! E& u) ?! h. \ - data: {
1 I. C/ L. w) ~2 h - parentMsg: '父组件内容', `" _) O4 }" _& F
- }
( _2 P9 Z+ p' z' Q, ~ - })
/ B5 Q% V' Y" L$ [ - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
: L+ \" W q8 h' ` M' v- <div id="app">7 \ u- B6 q7 t7 o* ^$ z9 f4 k! R/ _4 h
- <ol>) E: g7 M- d$ u) S3 U4 c0 E
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>! H* D6 j5 K) I/ C& S" N! Y
- </ol>
0 C( {. B. L$ a( W9 `. H - </div>4 x; t6 c/ ]2 L2 ^: y) v
- . V4 Y; S9 O% V8 z1 _/ ^) X
- <script>
& e8 Q7 H1 E" X+ t+ m - Vue.component('todo-item', {4 g( c. x$ h$ `* H* s+ e4 G/ {) ?8 ^0 t
- props: ['todo'],
8 X6 a4 j1 r; _& T% h" E; B - template: '<li>{{ todo.text }}</li>'
* b6 X6 M& O+ N- {' Z# X - })1 x$ z- x* K. \- C- s; m) C8 |
- new Vue({2 r7 K6 o F9 h8 ?
- el: '#app',% V# A$ T& O2 U; x1 J, P/ N
- data: {* d6 j6 u8 r T9 e3 t: u
- sites: [
( J1 ~: ?$ Y9 g3 q8 O2 `. ? - { text: 'Runoob' },
3 y# B* o2 M6 C" X: i. u* f% l - { text: 'Google' },
( u$ `6 q8 p$ S. K$ o! I- v& O/ r - { text: 'Taobao' }
. j/ l4 h( Q- s) }7 D* E( a* O5 U - ]
; I9 F5 ] G, T/ H* o. W# U - }
+ y6 N6 u- S9 t3 A* |' k/ Z: x - })
+ E! h9 e# L* v1 e4 R( Y5 q" h9 J - </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {3 W3 @& Y2 G N" E8 y- K; i& d2 }
- props: {5 X4 H( o- H! Z% D; t
- // 基础类型检测 (`null` 意思是任何类型都可以)6 h" n% u0 h, R5 W
- propA: Number,
1 F& P% D$ L& Z; q. i* p" O6 P: M+ Q - // 多种类型
! q- Q8 q! }0 _8 A6 y' \3 D - propB: [String, Number],7 V: b: z% r& O8 t& S8 o* h) B2 ~, W: y
- // 必传且是字符串' i' c+ j- w/ o8 R
- propC: {
8 g3 ]1 L3 a+ C8 g. h8 W - type: String,
) c- Z) m G5 X" w8 _ - required: true3 g8 K! |0 a' l0 a$ H, X
- },
- F; m9 }8 C d) |$ r - // 数字,有默认值
; K2 W* w6 r# t8 ^ - propD: {
1 N& z) \* s7 S8 T$ F - type: Number,
; f) {% w, x' f0 e& d - default: 100
, C4 \ s, D: J4 L' n$ O - },) d, S6 t7 M9 M, f- w
- // 数组/对象的默认值应当由一个工厂函数返回
! l* S: w+ G/ i& O4 O4 { - propE: {7 {- ?9 p7 P _. A, L& ?+ L
- type: Object,
' z; q t# A$ R, d R* [5 M- v - default: function () {
" k- W$ k3 X0 Z" j- y' Y - return { message: 'hello' } \! x, {6 y* E/ P
- }5 o1 e( V, f# A! f$ V# M
- },
9 f9 q7 _7 A7 \- d/ f - // 自定义验证函数
& R# x+ P/ I! X; y# u6 A - propF: {, n7 [3 ?5 b: q% o$ K w& ~
- validator: function (value) {7 n6 t! P+ G: {; S% i8 w
- return value > 10( r$ _0 p2 m1 m; i
- }
, y" \* D( _- X! R/ \, c1 p - }
+ N/ x ^5 V% p- G. q+ w6 i - }9 \0 ?- q. z) u; ~3 p6 S
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
' `; D$ |( Z! @' n% x! t; \& o% P
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
~4 I8 u- A5 `
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例
% T$ q) Q; Z; Y r4 P- <div id="app">1 n# F# A# V& Q; a4 v2 _% n _
- <div id="counter-event-example">$ W2 B2 W) i6 h2 M+ y
- <p>{{ total }}</p>. W4 ~, [7 A* W/ B! P' \6 p: v2 o
- <button-counter v-on:increment="incrementTotal"></button-counter>% Y5 C3 r6 `% j$ x4 ]
- <button-counter v-on:increment="incrementTotal"></button-counter>
8 ]7 y. t, |7 ]5 i- d4 n; w0 \& k - </div>4 C- }: m5 `+ h5 O# l) K: O
- </div>
6 j5 ^) b- o% u9 J+ V; \& | - : V: {- L: j" _+ n7 j
- <script>: J; g5 S' u' [: U; T) Q/ v3 ]6 E
- Vue.component('button-counter', {5 y: @7 A6 |; P, B" K7 q3 h
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
% e3 s! W5 Z' d4 ^ - data: function () {8 l- q; i1 h d* G
- return {2 U& l' B+ q; l$ e* U
- counter: 08 M. n% _: g2 O" N# P
- }1 y p5 h! k/ t: o( I3 d Q I
- },# }6 t0 x1 l4 E6 x- ^9 g1 e% a
- methods: {
; h0 A" S6 T4 T' e6 l' \- F8 b - incrementHandler: function () {
8 L w) b( \) \5 ]3 ?4 j, y - this.counter += 1. q V) S* d- O. x. l
- this.$emit('increment'); E8 K1 _$ A0 n7 Z. d
- }# J' x O* `3 h( V
- },
/ c% h: w0 g9 E9 z - }); O+ O& J& x( K) L( M" L# |, ]+ I
- new Vue({1 e1 g+ A7 J/ V- V- z& d
- el: '#counter-event-example',3 b' M! J) B8 G+ S9 C7 [
- data: {+ J* j: s" I S* b
- total: 0( F) p8 B9 u( V
- },
! k2 b1 n' t* L W - methods: {2 ^/ \8 T8 ^) c& K! @
- incrementTotal: function () {
3 H5 B$ f/ _9 L - this.total += 1. q. y* S8 D4 q! }4 ?4 a8 d! n
- }
: Y5 A$ @8 c) A4 X3 m - }
% c6 _, A. M/ d8 ` - }): \) i* T& V& c
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册9 z( Q7 N+ V4 C, P& x' I2 X
- Vue.component('child', {
8 v" W. r8 m8 I - // 声明 props$ N/ v+ ]) ~$ g2 U% ^% O% _
- props: ['message'],- s7 G; c* u2 Q a* G+ n8 T
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
7 N0 l8 q, t. U9 s* y+ ~ - template: '<span>{{ message }}</span>'+ V3 b6 j$ s* @- ]5 w
- })" Y3 s. J( z: h0 w* q7 j8 C
- // 创建根实例- G( \1 j" \1 o" k5 w8 I* [
- new Vue({/ c# u- y* t6 ~3 r* L
- el: '#app',1 @. Y9 s& }; X$ G& ?5 K% t
- data:{, M. b7 V: N# u% Z7 [
- message:"hello",- ]7 @% [. I- B- N4 U; M1 J+ e
- }# n, \- v. c! F2 G1 E# c+ p
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {: W3 l' F$ i: P, J
- incrementHandler: function (v) {% {3 C4 T5 S8 }+ t5 X+ E/ p
- if(v==1){+ J5 m: N% }2 M8 J
- this.counter -= 1
, B/ a I W( U+ i/ D7 g - this.$emit('increment',[1])
+ U/ m- C% d" b. ^# c9 ? - }else{
! W V$ I: C" p, T7 R+ \" q M+ p7 H9 a - this.counter += 1
# K' G r" W# v* U - this.$emit('increment',[2])3 f% Z: v% s1 @7 D2 t
- }
8 |- L9 b1 b( ?4 ] - }
0 \9 D! `* Y6 H0 O4 | H - }
复制代码
( H( f$ {+ F+ v% J; b
9 b, @; ?# Q3 q% v |