|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它: ! M7 ?5 V w' l6 Q! M
- <div id="app">
: ^% @) o" l3 `6 ~% t3 a - <runoob></runoob>
1 H1 k% S* I, @4 y - </div> h6 ?; w" }" i( U
- ! O8 k) K f7 b% J; j
- <script>) E; N7 s, T2 l }+ v, F
- // 注册
! U1 f2 N0 X* |8 Z - Vue.component('runoob', {# X6 C* X G+ [* N* j
- template: '<h1>自定义组件!</h1>'6 Q/ ]7 ~" j6 o3 M7 g
- })! p) ?; z4 l# N' O3 b! ?' L
- // 创建根实例& Y9 ]0 [! R/ e# S+ i" b: J2 V
- new Vue({
$ K/ X3 r: K* C: P/ Q - el: '#app'; V0 w4 K+ c5 ~, c, k5 z
- })& ?6 m: i j8 B# W8 }% j V
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它:
+ g6 G8 g. @% \/ ` K# [/ N* B- <div id="app">9 j) r& ]' R) F) a2 x
- <runoob></runoob>
" W2 {- t. j- b0 y5 P/ `" V8 r- _ - </div>
" `" O5 s- C- N( ]& X8 O- Z - " j8 A l$ Y& G4 j$ p6 }* [
- <script>$ q7 U: b( | G. Z0 u( s
- var Child = {
6 t1 V$ p+ y; j - template: '<h1>自定义组件!</h1>'
. T% [, z6 |" N7 H& w% D& S - }, r" y+ G) E5 s: \/ l
-
6 Y# C* j Y3 s. l: G( f+ c$ b - // 创建根实例
' T* c! w8 {8 I7 V - new Vue({
( W1 R- ~2 e6 D# l( ] - el: '#app',7 u5 R0 Y* }4 U1 s
- components: {1 B9 L! H8 p) v1 d1 D3 R% l
- // <runoob> 将只在父模板可用# [0 @' R p( m! F3 \* m, m" u
- 'runoob': Child2 j. c8 a7 J5 w1 \
- }+ s/ x5 _: P' K+ l2 e8 H- o/ e
- }): ]3 e3 n/ [8 }) x
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例
6 p- I# p& `# F% Q& L5 z! x7 {2 c3 H2 y- <div id="app">$ B' m& M8 W6 [) h- Z0 S8 d# O9 P
- <child message="hello!"></child>2 p. Q: t5 c& G) z( h, W/ F& u
- </div>
, Q/ G9 _7 H! q' l5 `8 p - - c& l. y* n" G+ H2 F8 {1 p
- <script>( W" N* {8 O( T! d
- // 注册+ ^9 X* i/ q2 E3 \0 I
- Vue.component('child', {/ S! O5 K3 ]/ R6 Y; H# K8 l
- // 声明 props; `6 G& u( }5 u" A
- props: ['message'],5 b8 e% X* {8 J9 X
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
$ k( @$ t3 \6 P( L - template: '<span>{{ message }}</span>'
7 i7 @ ], K$ @; H, h: k3 z }# v" a - })0 f s8 n" K- T8 {( T
- // 创建根实例3 C: |( Z) K7 H4 T; l% v- s
- new Vue({, ?" Q- e2 ?$ F! U$ w
- el: '#app'
3 b. _2 _+ T1 p8 g4 G - })
0 \; t& I0 Q. ~$ G3 k d% \. o - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
4 \) D- g4 O5 S5 g: q) B6 U- <div id="app">4 J; w. h5 W! W; B
- <div>
& m ]' K- s5 Y7 {: |) C6 ` - <input v-model="parentMsg">+ F6 `! x% Y3 @) s
- <br>
, ]' l- o) \# o6 E# `0 z" d - <child v-bind:message="parentMsg"></child>$ Q" T' I# D# L
- </div>
) U0 h! J4 \& r7 \3 D7 N4 s - </div>
/ w4 o. V" W; D5 _5 @+ l$ W -
3 Q- s1 `/ p6 q4 Q1 I% E - <script>+ I0 g7 F* w$ `
- // 注册
, P0 P. I- ?2 H* [' y - Vue.component('child', {+ p7 M& p& a( G- e& k+ q5 Y) t
- // 声明 props3 |# m4 K0 g& Z, C: }
- props: ['message'],) L/ ?# H; }& y( e! M
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
9 @; ]+ ?. M$ Q8 L) n7 \ - template: '<span>{{ message }}</span>'
! [! Y1 H1 X2 K6 a( X/ ` - })6 \, R F$ P& H$ v0 u% |! _, m- l
- // 创建根实例6 j6 t. x# d. Y$ X k
- new Vue({2 s4 L; R5 }9 x; f* Z8 f% A* ~
- el: '#app',$ J: \0 g9 X4 C: C1 C) h0 M
- data: {
' D- g+ U% _" e1 [; _ - parentMsg: '父组件内容'
8 t1 ]3 L. C% W- c7 f' k5 Q - } L* l* ^- Q _& d& J
- })
2 t! d& d0 {( h - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例- F) C; r6 _9 k# L+ v4 Q, G0 Y2 D
- <div id="app">4 o5 T4 t4 V' c3 A
- <ol>
* ?- u9 O( C# q8 N" q - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>3 u+ }# V- N& J7 y& t
- </ol>; E2 f+ `; h" s+ N: ~' Y; y# r" P
- </div>; j1 m, T6 l% Y. d5 v6 J! S# q
- ' w1 l, t0 @ s4 b; X
- <script>0 _9 T! q$ J8 |) V7 h' X
- Vue.component('todo-item', {
4 T# X% y8 T- k+ ~2 O! |1 o3 @8 k3 T - props: ['todo'],
2 |' H R0 S3 d" `" }. u. V8 z# @6 {* \ - template: '<li>{{ todo.text }}</li>'1 s1 {5 s2 j( x, J& w4 x1 g
- })
# R# G% [- }1 e. F3 f* L: u - new Vue({: X- E0 r4 x# t& W) ^) j( P2 ~5 M! [
- el: '#app',- B8 l) |! o2 y* G) k
- data: {
) ^- L; s: R& S3 {+ S- Y1 D6 M - sites: [
9 M- K) Q$ K" I3 b0 Q, u - { text: 'Runoob' },
, p6 K, F u1 L: T- ^1 V - { text: 'Google' },
& s; L- F3 Z& j% c - { text: 'Taobao' }
. \% Q0 v/ o7 x, N - ]5 d2 @6 P$ Q) A! c
- }# D7 v- i' y6 j1 }* g5 }
- })
- Z- w+ r! ] k( Z2 m - </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
9 a' j+ X- {4 h, q6 v# ?) S9 Q. K; ] - props: {
9 }* h- K4 F( y5 X - // 基础类型检测 (`null` 意思是任何类型都可以)3 O8 K2 h( a/ F: g1 r
- propA: Number,
8 R% g- z5 v( l% I* C8 k3 {! h: s - // 多种类型
+ x) m! e5 \( h- ~% J. m/ F V( Q& n - propB: [String, Number],
% `* C2 d" _ V) Y g: u - // 必传且是字符串
) @* g% f2 r3 L. D5 P - propC: {
, x6 h* r6 ^" s% D* B/ s - type: String,
0 M. A* s- H& m- P e `0 E- s - required: true, g/ c' F% b7 U* A( a
- },8 F1 p7 l6 }) T* i# |" J- r
- // 数字,有默认值. i8 u( o7 e7 _; @' C" y7 I
- propD: {+ t" B. t# D6 o! y _7 w5 l
- type: Number,
4 D9 I- v7 j0 z1 i. a6 n - default: 100
, w9 g9 `3 @& f3 n - },9 g \; H; n& A% e: n m/ _7 n* {
- // 数组/对象的默认值应当由一个工厂函数返回
4 q$ w1 h" I5 V: e - propE: {
2 Y1 C* {) b1 y) x* Q) I) o' l7 n' T: [ - type: Object,5 b. n$ e# ~$ f
- default: function () {; m' s7 x p4 x, M
- return { message: 'hello' }5 D2 D$ K" `5 Y ?, h1 c9 s0 k" x
- }$ E# \7 O4 ]- Y; \8 Z$ x; d
- },
6 k; _" t5 v* I* G/ n% ] - // 自定义验证函数
6 y* Y' d8 g( M. V - propF: { k1 _* K+ g7 a" M
- validator: function (value) {
2 h* Q: y7 d+ N( v' [* H8 X! M4 H - return value > 10
+ @8 `& @- `) E3 n# S: ? - }8 J7 V6 o# o' L2 \' X1 R$ e
- }% \. M6 }, x* G3 I% Z
- }/ H) ^+ M, d% k/ }$ h4 v
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
3 [; B( q1 X6 `+ F4 _4 n
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
; }) P4 {6 _' R( e$ P, s
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例$ B" R: e7 i$ L* ~) {
- <div id="app">
) h, S# g7 _( X6 H L* u, ^ - <div id="counter-event-example">5 N& d6 {& R; c/ S
- <p>{{ total }}</p>
! s" c! k0 s t) Z& i. ~2 i - <button-counter v-on:increment="incrementTotal"></button-counter>
" {+ j8 O, d) [, h. W6 e2 H N# \ - <button-counter v-on:increment="incrementTotal"></button-counter>
6 d" w8 ~1 Y2 ?" N0 e$ M8 ]$ i - </div>
- @ M# k6 p o! E, p; F - </div>* M: {) a3 V f& S5 X4 P1 h x
- ( {: N: c! j! j* v% Z3 x
- <script>' G" j$ i. Y! _6 @5 c5 ?6 {
- Vue.component('button-counter', {
) r/ C C1 q& Q3 x - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
$ F8 V+ L5 i2 N2 y# e - data: function () {
$ X1 g/ g3 C! H - return {/ n: K) Y' w, L7 E& M( L
- counter: 0
* T1 s9 e( d+ y3 i* Q - }. ?+ h' v, }! y3 A. W Q
- },7 E7 J$ _" x3 Z
- methods: {4 q4 v4 @! l$ j* C
- incrementHandler: function () {
4 F# K1 y8 P3 g! C4 s; R) U) A& \ - this.counter += 1
1 e3 D/ a4 @7 Y4 l& l( |, c - this.$emit('increment')
! c+ |" u4 E0 L0 e, N - }4 T, {+ @2 k' ~
- },
: E0 _$ I: }) X3 h9 g2 @( p5 {, l F' w - })5 |- z) D7 p8 `0 n; [9 v1 R/ o
- new Vue({
9 q4 N2 q9 i( s% A9 q9 z% b) E, m5 a - el: '#counter-event-example',8 k9 Q1 [$ N3 C: j6 h+ @, S
- data: {2 Q' @. t# f3 U/ s% m A5 n% V$ G, V
- total: 0
" E8 T$ S9 o* c - },+ Z. v0 x+ _, g0 L7 o( ?
- methods: {6 R& u) ~6 P4 c: z/ d, n: H/ J7 t
- incrementTotal: function () {) A6 ^0 e; }0 D- ~9 o9 K0 Q8 M9 r
- this.total += 1/ O: H+ _; ?) H6 o
- }* b* W% W& I5 J$ C; L9 R
- }# e7 Z5 g8 |; j
- })2 w7 K: J: R: D' v2 N: }
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册+ h1 S, X! C. o4 w5 g
- Vue.component('child', {
$ x$ f, G) [: f3 n- d( |' t - // 声明 props
5 O Q. t( y+ m2 t" L - props: ['message'],
V& |5 P8 h% |7 A# F+ v - // 同样也可以在 vm 实例中像 "this.message" 这样使用4 ?" z) a4 e+ v: ^. X0 k+ L4 M
- template: '<span>{{ message }}</span>'
3 s# R: W) ^ W( w( ?& P - })
" e8 C. U% ]4 h3 W2 U; ~/ ~( f4 X - // 创建根实例3 C( F& u* E6 p, L: H3 F+ p5 { Z
- new Vue({
8 t. v9 m# Q: V# z* m5 O - el: '#app',
4 x" Z& @6 e; ~6 G+ `4 X6 [# X - data:{9 g. |! }: y7 w0 \ I& {7 p0 L
- message:"hello",+ F2 O4 |5 ? p% s3 \1 }0 x- u6 C7 B
- }( K% ]& ~- i& g ` E3 b
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
' s w- _) e# I5 s' A - incrementHandler: function (v) {; Y1 d0 q; @1 }0 |( y9 b) k+ Q# N
- if(v==1){8 M* _6 H6 z, Z k( \- j2 l. y2 P
- this.counter -= 1
5 u8 P& D% m" o - this.$emit('increment',[1])
, Y) o! X9 R0 P4 `( v' y: z - }else{
0 G; D* ]* R5 T6 E" @' ^2 t - this.counter += 1
) i6 @! I0 g/ b- {) H p - this.$emit('increment',[2])* X$ R' v: R7 v2 s, t( U
- }
1 v7 A& Q- i/ _* M - }
' G1 I5 ^* f, ]6 c - }
复制代码 5 V, a0 }( n9 i3 [/ ?
4 N, y' j( x0 h( q$ b3 v* a |