|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
/ @4 O- `" T/ m, q: G- <div id="app">1 i% d4 D% T# ^) K- z
- <runoob></runoob>
k" Z) s \! {' @3 P& I, G1 ~8 u+ b3 a - </div>' V7 C: D" h( V( Y: X$ `! g, T
- 7 p4 e4 L6 r6 Z4 E; x( ^
- <script>
4 R0 `6 r5 M. V! f" T# r( q! }: q - // 注册# f$ H5 k1 l; S% M- }% r
- Vue.component('runoob', {
6 {" [* J- n3 j [/ g. C7 k - template: '<h1>自定义组件!</h1>'2 ]0 n( v# [% u" Y; k
- })/ C# Y! \# M9 E$ L
- // 创建根实例
G1 O5 d3 p# e8 \3 E - new Vue({
! T& S9 D3 ?* F+ a$ T/ @* Z - el: '#app', {5 Z1 d, ~" x% I5 I9 @ n
- })
0 K R7 D1 E0 u5 Z, x - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它:
1 |/ X3 }' Y$ j! ?- <div id="app">/ T6 [8 v( |4 L- k# E4 s, z
- <runoob></runoob>- T8 Y) \8 N; v5 F
- </div># d; `2 |0 S4 h0 w. }
-
4 _7 \# V4 f4 C3 [ - <script>4 G7 o" L; }7 t. t6 K: X2 E
- var Child = {. ^( L4 _6 m" e) p3 u3 b1 M
- template: '<h1>自定义组件!</h1>'1 C4 v" }5 `, o4 ]( b0 l( }
- }& }, k7 i4 l7 B. _" J* ^/ t9 H
- # j0 d/ s* ?) ?4 U! e
- // 创建根实例
! k; D" C* ?% Y - new Vue({% B' K* [( f# q, _1 Z/ p4 }
- el: '#app',; L4 D* S% h7 I2 `% m
- components: {6 H; Q6 @9 p, U. Q
- // <runoob> 将只在父模板可用
% p; O$ u1 ~1 ^ - 'runoob': Child% `' U" F5 x' u2 ~
- }4 `5 U q; n& D" K! ]$ V. \
- }): U6 `" G$ @5 h; J0 \0 @% b8 J$ z. V* I h
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例
: d* ^& t% ~; c C- <div id="app">
( F# H' ^- H8 d8 b8 g" Z8 g! W - <child message="hello!"></child>. @5 \. v. ?# a) m9 Y
- </div>
/ R6 B" u& W4 U+ g -
1 i* P9 x, D5 F1 t - <script>
6 a0 f0 b! [' d; e/ }$ o3 Z - // 注册
. K W# R3 j, P' s% V7 a. q - Vue.component('child', {
+ [$ P k5 o# P1 n1 t: N2 w - // 声明 props) C* c+ x# W0 b* P
- props: ['message'],
8 W9 j( t9 R% K* R' j% } - // 同样也可以在 vm 实例中像 "this.message" 这样使用
6 F. b( Z* Y# D/ W8 @ - template: '<span>{{ message }}</span>'
/ y5 g& X8 B5 ^9 A! Q7 n - }), n6 X- {2 w6 ]3 ]
- // 创建根实例
$ x) h' i' j) p3 }5 f - new Vue({
8 _. g' ^* M* v2 h& |' u% @- t - el: '#app'7 \/ e1 C$ P3 j+ l
- })
5 ~# d$ E9 s" v2 t$ V/ ^6 f - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
+ U5 |0 o4 r% ^" R! @. g) F, x- <div id="app">( Y+ p! H% z2 Z
- <div>2 Q: X% X5 n4 N. O& [7 b, Y! Q
- <input v-model="parentMsg">4 n; {# p' E2 F% g
- <br>4 Q- L" K& p" j
- <child v-bind:message="parentMsg"></child>9 u( [( T! X6 r3 y+ d
- </div>& P- \# l% S) `% Y* N: K
- </div>+ k( p: w" I) u9 J! C5 x; J6 M. P
-
4 A) z4 z7 h$ Z z4 u$ l2 W# B" G - <script>7 ~/ Y! E% J/ @6 ^6 ^
- // 注册7 c* ~$ D7 W8 w
- Vue.component('child', {9 N5 O7 h. w0 G; E- g0 s
- // 声明 props6 h+ V: x2 ?+ v' k3 c+ K( h' G
- props: ['message'], \, \9 R( H( N" c1 m" A5 X& Y
- // 同样也可以在 vm 实例中像 "this.message" 这样使用6 M2 T; [3 Z; p
- template: '<span>{{ message }}</span>'$ C0 b. s: p, q; i& z" e; h
- })( Z2 I0 `8 Y5 {6 M! E
- // 创建根实例
: w' [5 U2 M3 l5 N! N% Z8 E - new Vue({
3 [, h+ Z( R* r' d. Y1 M* z* g - el: '#app',2 v0 ^: [" ]) N+ C7 N* g6 i
- data: {
) ?2 p$ N) H1 f - parentMsg: '父组件内容'
3 x3 _: K# B1 u8 T. o( D1 X9 p - }. c$ W3 l5 c* U. M$ o0 Y
- })5 Z! Q- ?" R t M- H
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例# s9 X% q1 e5 e a; q
- <div id="app">
) E) z$ o7 e3 } - <ol>
9 {4 }: Q6 f# C; t1 e" p/ Q - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
2 X+ K- ?5 Q/ n: B' [/ _ - </ol>( @3 ]2 e* L4 V" ?
- </div>$ K' V4 O/ A) g) |2 H
- 1 ~' ^, u" w% z: `
- <script>
, s, n2 n& h5 N, i4 h* a' z - Vue.component('todo-item', {, Y4 \% x- j' C* m9 q9 ~: I$ E" l
- props: ['todo'],6 v' b* V9 j% e/ H
- template: '<li>{{ todo.text }}</li>'
+ l% C k3 G/ a2 K: a - })
% F* B& m' c5 p3 P3 a# k - new Vue({
% r3 O. [, K* e( ?: ` - el: '#app',7 F2 [2 m( }* `! M# {- ]
- data: { o4 H# |' p7 q
- sites: [
* l+ c+ ]4 W6 v - { text: 'Runoob' },
2 V7 q! {# R( f" I2 g - { text: 'Google' },) p9 r" \, J* s( T+ K9 f- x) _
- { text: 'Taobao' }
1 c6 x. m. j2 N/ B+ w8 M+ c" c - ]8 H6 _: P" k& a
- }
7 k5 G/ o0 C: p0 w# s - }) g" d" T8 t" ?
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {! H, A, j4 p0 _- ^- K8 {
- props: {
2 z( V O' O# M: V. T - // 基础类型检测 (`null` 意思是任何类型都可以): k% K2 R$ N" R
- propA: Number," {+ X& @1 K8 s ?) c2 l
- // 多种类型
8 R' v; M+ M& e4 t* W2 Q; g - propB: [String, Number],$ k2 Q6 [/ c( q- |, [
- // 必传且是字符串
( ?% b3 o7 A: S/ F" r" y - propC: {
# c! L: d! I: H- ~* X - type: String,
8 G7 p: S7 S* g: F, R0 g8 |; \3 ^ - required: true
) W. k" S1 _& e0 |* {# M; |3 p - },
6 H: U/ W# a; I E7 h - // 数字,有默认值6 B& p+ }* M8 {1 v0 x. o3 D( ~- ` L
- propD: {( V5 \8 b) T5 B( r( y9 O ]) F7 d
- type: Number,
# K; O* X( A/ W( z% K( c5 R X ? - default: 100
5 I9 F# E4 x U A, a' _ - },- v! `+ ~/ r5 ?
- // 数组/对象的默认值应当由一个工厂函数返回
+ D0 Z4 o7 c# b: D% W' R: r - propE: {
; J8 m* A" a0 F - type: Object,
* b6 U/ ^% e" p - default: function () {" J1 _ f7 L P1 E4 @; X- ^- e
- return { message: 'hello' }" v5 g g$ k7 S. P& ^5 D) a
- }, K6 [; j0 k! r7 e8 I% B& W$ E) f
- },
( K$ s: r, N6 C8 w1 O% G8 v - // 自定义验证函数 r7 S/ ^/ E! S9 R h* O5 C
- propF: {
6 s2 B+ a* z; f - validator: function (value) {5 ]0 K) e% N2 J
- return value > 10
0 x# J# G$ H& t - }
0 e- v, J/ ~7 J0 V, A6 y( U - }
8 @5 S7 ]: M$ n. J" Y: o6 g - }
* w9 o0 O8 J) O6 ~9 d - })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
' x& _6 \: c$ k
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件8 _) f- _# O8 w! K* I
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例2 e! q' `$ K W) g1 x& G3 C
- <div id="app">
: O, h/ p- \5 f" Q8 q9 W - <div id="counter-event-example">
8 L6 D" C9 g3 k7 H - <p>{{ total }}</p>3 ?) A( k) l8 @0 }( `
- <button-counter v-on:increment="incrementTotal"></button-counter>9 m7 b5 C1 F- t; Q
- <button-counter v-on:increment="incrementTotal"></button-counter>5 k6 O3 w4 K0 W
- </div>
( z; a+ G& m! z) Z. Z+ G$ S6 N - </div>
& y8 t; @1 d9 w4 S4 o s -
/ w% u* g5 p2 s: ?" w' l - <script>
( x* ~$ D% d) T3 R - Vue.component('button-counter', {
, W9 k5 }4 |1 w$ r - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
+ v( x) `5 M, e; S5 D9 u - data: function () {
6 N! B% `* e& w( y - return {
4 m. C! |) D% G2 Z" h* n - counter: 05 V" n5 ?- V( R( T: c% j1 ?- D
- }2 A) `7 J1 K; @
- },3 P4 b! g# T, @' h! R! d) u' n
- methods: {! h- J3 C2 C9 J N. i5 T
- incrementHandler: function () {" {7 x8 w# P$ U
- this.counter += 1, K3 ?& B8 N' a0 Z+ _9 E
- this.$emit('increment')
- L' a3 ?% N* M, { - }6 I2 t5 I3 o( @) p
- },
' Q# l0 x3 C7 g2 l7 u+ O6 D - })/ U4 M- ~. \$ r2 @, W6 P5 ~$ N; i d' F
- new Vue({# S! m% w M# z: u# J+ E9 |
- el: '#counter-event-example',, A( l' G1 w0 G* u7 C
- data: {
9 f. Q8 n0 U# j! ^% ~- c" z - total: 0
' a4 G; z/ l% n8 ~6 X - },
( X/ |! B7 u. o: V' d. b+ B/ p: x A - methods: { o6 c- n* w6 l4 O, C# b
- incrementTotal: function () {
; l8 M, N: v# |' @; { - this.total += 1
6 ^$ F5 J2 {/ u( K7 H# h - }4 U+ V, \! D5 y2 j9 [+ M' c
- }. |7 y. I3 O! P
- })
. M7 e. s+ r3 H- }7 v7 ], a& x K. v - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
! T/ B* _. S& f* u/ X+ e3 [) G - Vue.component('child', {
2 M+ x7 O' y: T9 W: C3 y" \ - // 声明 props' L0 V- N" P) T& R; T. t
- props: ['message'],+ d2 @+ @ G! B, U8 Q5 Y$ Z3 l
- // 同样也可以在 vm 实例中像 "this.message" 这样使用" ]4 S- n8 K# H
- template: '<span>{{ message }}</span>'
+ C; X. u6 \( X' _# }$ K0 p8 S! ^ - })0 X, P+ d# B/ S) H# O9 I) z7 ~8 O
- // 创建根实例$ T7 Y6 a7 l; U! _: r+ `: T7 A: I: z
- new Vue({, Z5 c+ W+ A D4 j% d7 q+ J( d9 K
- el: '#app',
& Y" z0 a; ]1 i: u+ Z- s; s - data:{
# M+ _# x. @# E d$ P$ }' G - message:"hello",0 A* _1 V6 @: j2 e+ s/ [ ~
- }( k J* u) h: Y6 e8 r
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {) t2 E4 [% {* X, z' ~5 u3 P6 t r
- incrementHandler: function (v) {& \: T6 w# m( j: Y& Z8 Q9 M. m
- if(v==1){
4 o) G# p' `( l; w& D' [' P - this.counter -= 1
4 g6 O* q" y5 q( E: c4 o+ X1 v: a- } - this.$emit('increment',[1])
0 W2 O7 Z" X% n0 ^' j) O - }else{! V1 _( C5 b2 U/ V1 F
- this.counter += 1
& d, r B' Q7 F7 M7 L - this.$emit('increment',[2]), u3 d! x4 V: i& b
- }+ |! o1 t: \: ^( |( o4 w3 M" y; p
- }* F' U8 E- G; l$ j3 M0 q! a" ^( I8 @
- }
复制代码 - b; p2 r" K* Z7 c
! l! R- t' V' S. Q' `4 ?
|