|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它: 0 A, ] G: k4 E, F
- <div id="app">
8 M. s! W) r5 L6 f8 m! M7 D8 | - <runoob></runoob>
3 q @# T4 D8 L) D - </div>
. U1 W, z0 s; D8 ~( ~: |& C -
/ E5 m$ T4 r% O) n2 P, ~4 d, Y9 R - <script>
) B9 `, A+ a# ~9 R7 V2 w- T - // 注册' {, k, A: ]9 V
- Vue.component('runoob', {- [$ ~# z H' o3 q: j+ X- D. K" u
- template: '<h1>自定义组件!</h1>'
0 f# F9 b- @( P - })% e1 F0 Q+ P; [5 s7 F! s
- // 创建根实例5 l% h6 [! w |+ R' W% `6 G0 K' ?
- new Vue({( p U' v, x4 I0 E
- el: '#app'
5 r5 w6 j6 c8 ]/ d( M- r6 y4 Q - })8 z/ T: \) ] g" u3 B2 b
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: 8 P, ]9 Z, x& A* [7 y# {
- <div id="app">
. v2 m: p/ w0 a5 E1 W - <runoob></runoob>. n% Y0 S' b0 v* _0 O
- </div>
- v% X* R+ a+ A3 }% \$ K8 _1 q -
* X) |# o. t& \# {+ e - <script>% n; d6 c' ~9 o" j6 X: L' s$ n
- var Child = {
7 y* B# V' q) j3 ]3 Y5 L* [0 E - template: '<h1>自定义组件!</h1>'
# h' r, F( F3 V* G$ x. a - }
p2 V* r* S0 h* G -
6 c1 x2 C4 k2 ]+ a - // 创建根实例
# b( g0 ?! l% R/ }$ m% l - new Vue({
/ x6 g5 s& S& _3 A T - el: '#app',
+ I- A4 g& i6 S) y - components: {
4 o2 i7 o% Y1 E/ V& p) a - // <runoob> 将只在父模板可用
# Q3 m* J8 C# J: t - 'runoob': Child
- d. s; S; Q9 ~7 u. x9 g - }% |2 [4 R2 S) Q; ^5 |# A2 m
- })) y( W5 t& U7 o5 G ]8 l5 h1 b9 Z( V
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例
3 Q: s4 D: P+ b& A" r& r- <div id="app">
1 H- _2 x% V, M - <child message="hello!"></child>6 r5 ^$ [& k: Q
- </div>
) y0 R/ T& _4 v7 k, @ - ) n3 H# r6 i: E, I9 R
- <script>
6 E) |. L7 B- A y+ ` - // 注册) Z& S b# s# }& j( J
- Vue.component('child', {5 }4 f6 r! B7 Q m" ~2 {0 M7 P+ `
- // 声明 props
) ~) @! G. A: v6 K) @( ^ - props: ['message'],! u: ~9 B$ k& \" X* C, J
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
" U( H3 }9 {" X% t! O6 B8 j - template: '<span>{{ message }}</span>'
( n% O9 @7 O% W; J3 G - }), o2 S- L1 R: }
- // 创建根实例
1 h9 L/ l2 {# v6 ^' c' z. t, A - new Vue({; u6 y, W8 k0 I, Z4 \0 H, B
- el: '#app'
" i5 I" F/ {( w4 I2 J9 ] - })
6 R1 ~$ w7 U& D4 T! c+ o - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例! d. {$ O* ?5 n/ I+ Z3 b
- <div id="app">* S2 W8 z% U w Y. l
- <div>, H$ k1 q- g- f( J4 Z
- <input v-model="parentMsg">
, t- _0 r& ?& p" Q; m1 m - <br>
. X ]. c. H B% |! t - <child v-bind:message="parentMsg"></child>. D2 Q2 K6 O9 f& Z( n& v
- </div>
8 ` q, f K {: O' S - </div>' M. k+ \3 c& t3 r7 v
- ( d9 i3 O4 ?/ E
- <script>
! D& m& v- W, ?: |- J8 Z - // 注册5 L" }1 P! Q+ A& ?% a9 U8 }8 Y S
- Vue.component('child', {3 x# t7 n+ B- v. g2 U
- // 声明 props: q$ @ u1 f8 t" ?
- props: ['message'],
! z$ q/ j) O' @) [: k - // 同样也可以在 vm 实例中像 "this.message" 这样使用
! m# B% G4 V4 I( y - template: '<span>{{ message }}</span>'
( Y/ _# C/ m" | - })) Z4 V- u( `% }& ~0 D
- // 创建根实例
/ Z! @+ E, f+ Q; g1 L) L7 p* M - new Vue({: T3 b( ~1 y" K, B
- el: '#app',5 U' O- g" w$ f' I, @; w
- data: {, g/ ~9 E( m7 g
- parentMsg: '父组件内容'+ n; |2 |/ _2 e+ s+ O# S0 `3 v
- }' j. d/ s5 I; l s) {$ k3 V* U T
- })
7 ]9 F# r& k( j6 h - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例+ E0 A$ _ i, z
- <div id="app">
" g6 e) q- h, D! l0 \1 B - <ol>
& M6 A( p( a/ e4 b e/ P - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
I" d3 W+ r7 w% {/ p* N - </ol>9 y7 x9 X; \5 e4 |! t
- </div>. a0 }7 }+ }8 Z) X
- $ }1 j% C: O ~$ A
- <script>5 u& w5 F6 D | M# a. i; B
- Vue.component('todo-item', {, w( ?- V. l: L' ?. I, R |
- props: ['todo']," M3 [1 r9 O( v5 |
- template: '<li>{{ todo.text }}</li>'
$ E9 ~% |* i5 I/ @9 a - })
$ i' g0 D7 E0 r' ~9 P! T! b" v8 Q8 X - new Vue({9 Y3 S, V4 r. l, u
- el: '#app',
5 R& [5 g4 H/ S) }& z - data: {
; |2 [8 Q% I) d7 R5 {3 Q- S - sites: [1 [0 b4 }* \: |( n
- { text: 'Runoob' },
5 g( |, U8 j0 i6 [; R9 X7 o+ ~* Z - { text: 'Google' },* _# a1 g3 e$ W
- { text: 'Taobao' }+ {- F9 \. b9 k6 W( t1 v: E' a
- ]
- L) O5 V9 ?6 A ?6 T, r - }: K8 y4 w* F) r( G
- })
& k5 z: u/ h: I7 t% G - </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {' H* d- q, y) X- V
- props: {
$ L. V f2 g/ O3 A, O ` - // 基础类型检测 (`null` 意思是任何类型都可以)* m I8 J h$ }5 g) a6 c( L" n, J1 |
- propA: Number,9 \' {% Q7 e# ~& J3 @0 ~
- // 多种类型" F9 @3 F; v5 h* d+ E$ v$ T1 e
- propB: [String, Number],1 K# E9 v9 v/ G9 F) E: W. |0 ?1 O
- // 必传且是字符串9 A+ x# v& {/ _
- propC: {
6 N' E) H1 o' u5 }3 L$ E - type: String,
3 G( _( T+ u1 X% w3 o - required: true! }0 r# g4 ~% d7 E) @
- },) Q7 }; a3 o7 N4 v" ~( H% G. d
- // 数字,有默认值
$ D- J' R( B$ E! o. o - propD: {# \6 q2 v4 |5 I( H$ z* r
- type: Number,: z' w" x- O% ?6 G
- default: 100
! N" ]5 L7 G' q$ J' ~3 _ - },: \- m. z$ c# ]) w$ s' u
- // 数组/对象的默认值应当由一个工厂函数返回
9 J3 f) a- g6 `3 [; Y: K5 c% o0 Q- Z+ B - propE: {
) H. E3 n* g2 b% D& r$ Y - type: Object,& t: i% P- u; v+ x- f7 f% @
- default: function () {
) _& Q$ p( w) O- R$ ~& S O; I - return { message: 'hello' }+ w& i( E( `4 V% b6 g: a3 F
- }
4 B* r( t4 u3 |" M& |; T - },8 k; q0 v. ?6 R9 C; \8 O' N
- // 自定义验证函数
, U8 G4 l& \9 r) j - propF: {
' i" Q. y5 w1 o8 K1 } - validator: function (value) {% P4 Y( h" ~9 x) v# W6 d& X
- return value > 10
% i3 w/ W# _+ a' ^ - }. C8 n0 `. c+ H
- }
% d8 _+ L/ _+ p - }' _6 B) @4 I4 k# t% v! Q2 _: a
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
2 s# Z1 g$ ? y
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
4 S3 j# L9 n B4 }- X. L6 z9 {
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例
' U2 s: d6 |1 l. x$ Y- <div id="app">1 N& x& W2 K/ w0 W
- <div id="counter-event-example">7 K7 k& w0 L8 m) s- | a* K
- <p>{{ total }}</p>% K$ H( g) Y4 n$ K
- <button-counter v-on:increment="incrementTotal"></button-counter>
5 Y$ ?2 C$ c m2 H - <button-counter v-on:increment="incrementTotal"></button-counter>
4 x n# e7 \# x* m% l. \* J - </div>( E2 X% |# z0 j8 ~ X, ?
- </div>6 y; H1 i& T" q0 K6 r7 p
-
9 N# j! |0 j0 Q* ]. p4 U* R$ ~5 L. q - <script>
9 T/ D/ s, n l7 ^ - Vue.component('button-counter', {
- t( {( b1 o1 S) s1 W" F) b4 Y, o - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
0 D, q, B! Z/ G1 T% p/ ` - data: function () {
; z, {+ k. W# H/ |1 e( e; P - return {7 n w; s, C# ~2 Y7 v% V0 w0 S }& L
- counter: 0
/ X6 z- e2 T! {+ s6 Z: y - }
* Q: R4 \& g4 w - },( Z4 x8 K, A* D% p" P
- methods: {8 k4 k3 X. U0 p; K) J# l
- incrementHandler: function () {
5 S% N) o/ U w! e7 k, K% g/ K5 _ - this.counter += 1. t3 V- ]$ s+ c2 D7 G
- this.$emit('increment'). ?- ~: u' I* Y' j
- }
5 D7 k. z) z9 O, q. m: } - },: ^# w; V4 \# C9 T' J
- })1 `$ k1 s4 c" x% B, ~+ Q- t8 q
- new Vue({
+ W3 p( C7 i' b - el: '#counter-event-example',
5 i2 }- Y. U7 a) ?/ P - data: {1 m2 e" Y; e+ f ~* M+ x) F
- total: 0
. W6 |+ h! N v - }, ]2 [( W' l/ @1 s4 m' C
- methods: {
+ J# e, T* u$ Z - incrementTotal: function () {
4 Q/ o' p/ k2 `! l - this.total += 1
. h0 W: a- a. Z* m h - }. P6 f' G [7 Z5 z' k
- }. K4 ]# g; S2 A0 q
- })3 f9 ^6 ^$ x* B) {, X s1 d1 n
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
, N: L) }' m2 o/ A5 c I$ e - Vue.component('child', {
5 Z& j1 N3 J& G+ W - // 声明 props! i- [ y- @, ^/ w- s
- props: ['message'],* G# J: }5 R6 @, ?+ f o u
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
# l; s' p, {0 n% P1 I - template: '<span>{{ message }}</span>'
; ?0 b. T: T: O" Z) I5 x - })
6 w: a8 w4 }" d0 h4 j* j - // 创建根实例* {/ N2 H, @% w$ t, t4 x2 ]
- new Vue({
. Y5 D1 D2 C8 }6 B& Z+ \1 W& w - el: '#app'," _5 {, D8 [! m& Y
- data:{; n; Q; Y9 ?+ u; P% y% a6 n
- message:"hello",
$ S `2 f$ B# r5 b' J+ D - }
, ~ z3 }: G) [: N/ B9 ^ t - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {1 ^) z3 H" g" ^5 B
- incrementHandler: function (v) {
8 [8 L2 B/ `5 P* p+ @& T, u; ^ - if(v==1){1 s% `3 |4 C0 P5 Y# H! [
- this.counter -= 1
$ B/ h) j$ P6 A7 A3 m, E - this.$emit('increment',[1])$ C) m% s% r8 ~# i0 r
- }else{ H' i+ N3 O8 g' d
- this.counter += 1
- X X j+ L' y* c$ {$ Y8 q+ ~ - this.$emit('increment',[2])# S; Q4 I6 A" Z' ^" V X
- }6 f$ E: T. R7 y0 W' q/ Y5 `
- }
2 ]3 F0 P- I; K1 n- W g$ i* j9 x - }
复制代码
8 g# i6 ~. _7 T4 y
/ B0 n2 ^9 C( {" [ |