组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
/ H5 b. g$ G& x# P/ `0 Q$ f- <div id="app">
, o: p5 u, W, F9 G - <runoob></runoob>
7 w2 b! C R2 N - </div>
& z! s, {1 A9 K1 h8 ? - ' [5 u, t5 {) K: T* o$ W! ]
- <script>. g/ K! C0 I ]0 @4 ~+ l5 N4 b+ L
- // 注册9 k6 w6 P! K1 d: h6 {4 }5 h
- Vue.component('runoob', {
4 T# Z' I! Y8 k5 \/ c9 S3 m. n - template: '<h1>自定义组件!</h1>'" H/ U( K& v8 g
- })
0 x7 L+ K# x' n9 e0 n - // 创建根实例 F8 Q5 S m: r6 J, P+ L- k* c
- new Vue({
! E5 ^7 x; s, L6 _7 ?! a - el: '#app'
+ [" u+ [' X7 d% u( n0 c& G1 G - })- v- e1 u& C. O' \: y- H( G
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: 9 Y# k/ v. ]" F1 r: e
- <div id="app">- J# A) ~# \0 P9 ^: R$ X
- <runoob></runoob>
0 ]; g# Q3 R- s - </div>
( l& i# B. V# [' ^! m o6 u } -
# \: l* m) @1 F - <script>2 t# X6 H. |& P3 _% U# D7 i" f( k
- var Child = {
/ l" _& Q2 R& F - template: '<h1>自定义组件!</h1>'
" g( V8 H) o" v$ R2 w1 @ - }
3 \6 ]' V3 {5 e1 c; f4 ` -
5 }$ a! @& r, {% ^! G; z - // 创建根实例
_' S d7 l" A L. H) a( x# c' a$ e - new Vue({
( M7 A) F- z% W - el: '#app',- d6 m$ e, J* {3 U
- components: {
" U: j P, Y( ?9 j& q+ H - // <runoob> 将只在父模板可用
- h6 W- J g- H5 M% h9 R5 M+ ? - 'runoob': Child
/ C! c! c4 }% u' c. `* F: `- ] - }/ d* P) N8 Y4 a- ?4 B
- })
; a m& J, F% f2 K, b% _% b. v - </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例) c, o) Q0 s% M& w& m. y2 q* k/ c
- <div id="app">0 w7 D7 a- k) x
- <child message="hello!"></child>
9 e% Z- a a& Q, o/ g - </div>4 D9 A9 e! A* Z& W5 ]4 W2 T) ]
-
' U$ g+ M' U8 O3 w3 H8 c - <script>
1 F' e! X# S0 D, r) t6 B- T' w - // 注册
1 m2 k6 x0 U* W - Vue.component('child', {- i* I0 Y) ?5 g* l5 R- k
- // 声明 props7 A$ f* s$ |% P* J
- props: ['message'],
6 q/ ~. D+ n) I. @3 d+ r' f7 [9 T - // 同样也可以在 vm 实例中像 "this.message" 这样使用
# R! X! M2 z3 P0 f1 i4 X2 h - template: '<span>{{ message }}</span>'. ^& h' d+ B* g% J# [$ N
- })) |; P% k& u+ g3 ]7 k
- // 创建根实例0 X# ]7 n r! \8 g
- new Vue({
, }! ?3 b* B4 ~) }: d y4 ~ - el: '#app'
, T8 X9 X5 P' f - })5 K: k; ?5 y- v* ^
- </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
. u0 C4 _+ h7 _8 K, k- <div id="app">: X: O/ a- P1 z2 v/ S
- <div>7 y9 F4 a1 R" J* H
- <input v-model="parentMsg">1 }1 G2 x+ I& O
- <br>
3 q7 _- X! W5 a s9 O - <child v-bind:message="parentMsg"></child>' |; H' ]1 X9 S
- </div>
( l% i+ U/ ~" y7 g' { - </div>
2 H: K# B0 r w1 |" H -
7 F5 ?1 Z& x; b! @. C% w$ O - <script>1 S& P. g, a& }# t2 V/ }' T
- // 注册* J! ?$ O/ j9 J5 f+ U
- Vue.component('child', {
. X! o$ n) c y, V# u5 B, c, N - // 声明 props- Q) r" B( `: r8 R7 R* Y2 K0 I8 g7 N: U; J
- props: ['message'],8 ~6 Z9 u% G0 ~ E8 X
- // 同样也可以在 vm 实例中像 "this.message" 这样使用, D! ?' i4 F) F, \7 k+ j3 x
- template: '<span>{{ message }}</span>'
# u0 [4 J r' v% Z+ r - })/ H0 P( R5 z, f! b8 Y. a' q
- // 创建根实例1 r& L! B2 v U0 F" c8 t) F M
- new Vue({
7 s( @, d! V1 e$ G- f - el: '#app',. ?8 ~6 U Y9 x/ S" i9 O
- data: {& F" D/ ]* V% G+ q
- parentMsg: '父组件内容'
+ ~( \9 z. \( W2 _9 ]! y( \5 B - }
. D4 R% ]- s: O - })
6 e, x% B/ Z3 G* h7 a" N - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
, Y- Z1 S# b1 P8 m0 k& ]4 N- <div id="app">* k; n# C! n6 h2 A) B% @, R
- <ol>. e+ C" Y9 f; n- X: t0 J
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
. l b U0 R! e1 i2 ?1 f$ b - </ol>
, o: K3 @- ~8 `0 G' O; N - </div>
6 S6 t4 A3 z3 N( G j - ; Q. I% V6 i/ M4 H9 |# q. i) k
- <script>
: [3 L8 \/ d* X$ k2 H2 \9 O - Vue.component('todo-item', {: ]( ?1 ~: F6 b' s
- props: ['todo'],
$ h, I% T6 G. Q% V. t% e2 v. Y - template: '<li>{{ todo.text }}</li>'; E0 Y6 h1 {5 Q
- })# `+ ?! d4 q8 g7 G, N
- new Vue({2 K! n; I5 E6 t! N
- el: '#app'," U3 p$ z( r% L$ c4 z5 b
- data: {& }3 p) Q' s% u% g) ~$ Q
- sites: [" M! A7 g W' |- G5 W
- { text: 'Runoob' },
1 d" f" K9 d" N- b' U. t - { text: 'Google' },
3 W" z. r, C3 s# u4 m2 c& n- ?$ f - { text: 'Taobao' }, ]; q: a% n$ G& O8 C+ j1 I$ o
- ]$ G6 ], A5 w0 |. J4 [5 A
- }
* [' N% C7 Y( k - })7 s, p! c" r3 x) X3 F
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
4 h1 ~+ r. `5 s7 r - props: {. \% p9 f& v, ~% f1 k
- // 基础类型检测 (`null` 意思是任何类型都可以). L# n9 m; U& D0 t
- propA: Number,
( N/ W I6 l6 x' {, W5 M/ _4 C - // 多种类型- `) d! N3 _) Y1 z- X
- propB: [String, Number],5 K: s+ r+ ]4 X
- // 必传且是字符串
# ^3 K6 K ? u$ w' O+ ^ - propC: {( v6 U; `) @5 J5 V( s6 j4 F8 v& D
- type: String,) o% P9 `. n$ V# |! l3 d
- required: true
8 u9 x! r9 p- S, R/ L$ u) K - },1 z- E, p5 Y# p
- // 数字,有默认值. v7 `5 y/ `8 v' n
- propD: {
g9 [ ]. k' [1 V2 e - type: Number,
6 a+ d. |7 Y# r- O& F - default: 100
7 }( |* `' \( ?" w; a7 n7 w - },
7 P0 I8 Z4 q7 U5 \0 p) D - // 数组/对象的默认值应当由一个工厂函数返回6 i" d4 i; e+ o- ?: Y x, Z
- propE: {
0 E) z$ [; n k! D I% W - type: Object,# g' |) p5 I; M5 v/ Z' k! ~
- default: function () {% Q, m/ W7 h/ j+ o: v
- return { message: 'hello' }4 E0 p9 D& ~% _" I$ F: X
- }" }6 v. L- a1 I
- },
4 B5 Q* l0 K4 ]9 M7 Z: H: O - // 自定义验证函数( o( ?: w6 X5 G0 G# e' U) s( B% k
- propF: {
1 i; I# R' ^) Q9 ?# {! J/ e8 i - validator: function (value) {4 J' J, w' M- P+ y
- return value > 10& S' S* W0 T' p* w9 _' X, M! G* ~' n
- }
/ ^# ^& g1 A! ~1 X; o/ C8 V3 w* V - }$ w7 G' ~, b" Q, O
- }" X& p- z! K7 H4 F
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array8 K# n" U6 o7 J0 D% b3 ~- k2 X2 f
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件0 k$ K# E, y* e# E/ ?% r
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例
0 a2 J' _' S- Y" q/ m" i- <div id="app">
: J) f8 W- U ^) @$ o - <div id="counter-event-example">
! i7 c0 X% z, T' }4 S - <p>{{ total }}</p>; e- |$ _5 t/ `( a8 i
- <button-counter v-on:increment="incrementTotal"></button-counter>- F! \9 Q9 s$ H1 I" }% B8 E) y8 U
- <button-counter v-on:increment="incrementTotal"></button-counter>
# F' V' o7 {/ w8 }, r/ P - </div>
; W; c+ b1 K$ l2 f w% [; U Y - </div>
6 E/ h( R8 `( J3 I6 O8 [$ E+ y -
( ^$ J; ~0 i) q/ t+ d2 y, e - <script>
! ^. ?. s H$ c1 t( w/ { - Vue.component('button-counter', {
- W' D& |6 d6 e - template: '<button v-on:click="incrementHandler">{{ counter }}</button>', q) `# a% p4 _* q" P1 N- n5 K2 ]( ^
- data: function () {' C4 t' }% h! m$ C
- return {
$ S1 a: m E2 |& O! I2 M - counter: 0% G& f, u- D6 Q4 w
- }3 _" i( D4 S- `/ F+ u
- },0 z* X2 o# z. J; { f0 H5 |
- methods: {) N& i" z/ w0 r* d* U7 P# c! ]
- incrementHandler: function () {, Y# K. L) C" t: ?0 U
- this.counter += 1) h7 U8 k- @. h8 ] H
- this.$emit('increment')
" I+ \, r! e( O" A$ M1 l1 Y - }2 K$ B7 o8 |+ ^, l% C
- },
0 b5 F/ X8 F8 [3 S - })! `7 u6 m- d4 Y, F
- new Vue({, p+ e: V. u0 `, _& h8 a1 a% @- C
- el: '#counter-event-example',
. z1 v. D3 ^+ A: Q3 b - data: {
1 J! Q; m& Q& _2 z# \# G4 j4 e - total: 0. C" B2 h5 _& w0 L
- },
/ m4 o# c) m: @: c, L+ v - methods: {7 A/ S9 E: r e. t
- incrementTotal: function () {" V* f( Z( I5 ?# Q3 {6 n; ^) Z
- this.total += 14 s+ u- p, J$ ~: t0 Q
- }4 b& n" v: s; s
- }
5 N# Z7 G' u0 v ]. O - })+ _, w9 Z* t) p7 _0 s1 Q4 g
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
( s o: m5 o5 l, C! L ~! l/ _ - Vue.component('child', {
3 e1 ~# N, ^+ z( G4 z, U) A1 G - // 声明 props
' r" P( Z8 @, R4 M - props: ['message'],# ]& _5 [" v# C2 g1 P, H' G
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
0 S6 b! d( P) v* f - template: '<span>{{ message }}</span>'
+ g9 [, F' D0 ]( E - })
4 e5 F; P6 D* P4 c - // 创建根实例% q6 o9 t' \& c( B! N% M
- new Vue({0 t7 I& @. H: G4 W; ^! R# J! i) B
- el: '#app',5 V' i% A9 X! C& A7 ^3 j
- data:{
6 G% V" F# A& d8 v# x8 G - message:"hello",2 s1 m) F [9 X1 k
- }
) ] e' a y/ N% w9 e# f - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {7 W9 b3 I5 z* @$ f5 E" M/ c
- incrementHandler: function (v) {* L, t- n% g1 k* \: b( V! _
- if(v==1){ z" s6 _6 M3 Q6 \
- this.counter -= 1) `9 Q' A, v/ `: t
- this.$emit('increment',[1])' L- \6 d( p! H2 x3 |& P
- }else{
& o% {0 Z* {& Y - this.counter += 1: q- h' b1 C, E3 C9 H
- this.$emit('increment',[2])
+ `1 |. y g5 K: J% {1 Z" h. p) z3 Q( l - }
3 `7 x. @( Z5 [/ V7 T - }- h' t0 J3 {6 v! o r D
- }
复制代码 # D* t' s! k# U7 M8 U7 j8 t
; C0 l. S$ h+ ]6 _5 x) m& F |