|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它: . s! v9 o. @+ `; {: x5 z, O f8 u9 S
- <div id="app">
. P. {# X0 ?7 k1 M) M - <runoob></runoob>
2 t; H4 _4 ]) u6 N0 R) s# G - </div>
+ H; P* O1 B, Z/ ]7 F) ~7 j2 \ -
; ]( ?. j- e! }+ I1 Z2 B: } - <script>
/ F; c, a; ~# P6 q/ X# N - // 注册
/ {7 T1 i9 g( g- @0 k - Vue.component('runoob', {1 K+ N8 U- k, W0 g
- template: '<h1>自定义组件!</h1>'
' N! [7 M; f% l4 o; D - })
! u/ {1 F5 Y+ d0 h2 m - // 创建根实例: T( o4 J" s* H
- new Vue({0 e8 ?# X/ }# c% Y* v# r' q) @
- el: '#app'9 q8 t: j) k2 c9 g
- })
. k b6 A Q& u2 E - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: ( K# L5 H$ Y' V
- <div id="app">
3 s1 ]/ p- m! b: p& d - <runoob></runoob>
3 d' R, R2 }( t, q* J) i7 T - </div> s j" F5 A6 N/ M* m9 o
-
( T+ b, ]& m/ e. K4 u |& |- y5 \ - <script>3 ]+ ]% A: m" {& R, ?$ o) V5 r0 L
- var Child = {8 R9 L5 N6 X e/ `
- template: '<h1>自定义组件!</h1>'1 u. {; C' |5 I/ Z% c( r) f7 M
- }
2 R3 y* f' s E% a -
4 _- O0 J2 y- I, G5 A3 N8 q8 ^ - // 创建根实例+ T* y5 a6 K9 _# ?2 u
- new Vue({
" d/ ?! z4 W! P1 {9 b; H - el: '#app',
) k0 a9 m S0 ~' R - components: {+ \3 R) s7 o- @9 ?4 R7 P- l0 v+ A: Y
- // <runoob> 将只在父模板可用+ L# p6 _ p& U5 W4 U
- 'runoob': Child
! c4 ? W, w" F - }. a z1 g& L6 r2 T6 t; C( ^# T
- })
( {5 E- c$ l* R. y2 {$ `9 k - </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例! o ]& k5 o) z6 w$ l) e/ j
- <div id="app">' s& |7 G" T q& s' i, k
- <child message="hello!"></child>
, b# o9 ?( O0 r/ f: ` - </div>+ a) @: z. C2 o; A- I0 O
- # h) c+ T& S0 Y* y' I3 }
- <script>
: q: D; S5 q% H* C) g - // 注册- ~6 T% V' [% H% P
- Vue.component('child', {
% U' r1 l3 Z: F: j. ]' Y" b t9 A - // 声明 props
2 L/ |0 v2 A4 l7 W8 t1 V - props: ['message'],0 q) k4 {' I0 N+ Q1 O/ D
- // 同样也可以在 vm 实例中像 "this.message" 这样使用& O# b1 }! B7 q5 C0 F- l
- template: '<span>{{ message }}</span>'6 \1 R& a( a# O
- })
% a7 D' {; a6 s& a - // 创建根实例
; `9 V9 P6 X6 F - new Vue({
7 o2 g8 [2 s$ l3 P& T1 C - el: '#app'
1 {5 L2 u s; E5 E$ ~ - })
: E( u+ V M8 J" K$ {, _5 h7 q - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例" D0 y, {. [& Q1 L m
- <div id="app">
! {2 b3 T. `- u: d X/ L - <div>
; P% ]' y$ y5 s" ]/ L2 m - <input v-model="parentMsg">
+ U9 G+ L8 `" J# i - <br>( M! k) L8 i' }) g0 e4 l- h
- <child v-bind:message="parentMsg"></child>
: V$ s- m3 t8 `$ f, G/ g$ n& m - </div>! x) E! Y0 Y9 [7 u$ D3 L
- </div>, f4 G+ w' }/ R% B8 I* i
- 1 }8 [* r0 V4 M
- <script>
4 X/ M3 d- | L; D - // 注册
3 L$ W- u3 a) c - Vue.component('child', {" P' E- L9 ]0 i
- // 声明 props
/ p' k( T8 T7 j2 P& @. n9 S - props: ['message'],' t g B' f9 M( v& j
- // 同样也可以在 vm 实例中像 "this.message" 这样使用3 Z3 x+ x5 ^& o9 W$ ~1 B2 l
- template: '<span>{{ message }}</span>'
; A4 r6 F3 a z. D- [; a - })( ^5 x$ c" U3 r# g
- // 创建根实例
9 S* z$ w- A, `6 @ - new Vue({" {; E/ `+ F5 [8 \3 N0 ?
- el: '#app',
) {) k" s$ a' J5 O+ K7 Z7 ^* Q - data: {6 A: b# E& A+ d4 }6 g/ F' ~
- parentMsg: '父组件内容'% F4 b' h% I ~+ a' X; \/ f7 Q
- }
, H3 e- S$ l/ ]$ _" E - }). G6 R* S- }3 G" e$ J- R! n
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
# ]3 [, P/ J: _& ^3 ?- <div id="app">; l8 l6 k, D k9 H- p5 P
- <ol>
0 y8 j i. c$ e5 o5 ~ - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
1 e# q2 }* v5 |+ x* ] v - </ol>
* V. ]& A& O, K+ I' _ - </div>7 S3 B; V$ Y5 R C% V
- . M0 a( P w9 _% d& R+ `) @
- <script>
6 _6 C3 B& l8 g- P& u - Vue.component('todo-item', {
9 X3 T1 e# o8 |: T z - props: ['todo'],3 E8 s2 ?$ O0 E' L
- template: '<li>{{ todo.text }}</li>'& o1 }, j7 g% M( h
- })
0 l2 g6 ]* ~5 b! M2 D2 ?- | - new Vue({
* \, {/ o2 i0 v+ q; h2 T: n5 C, @ - el: '#app',
- {! R3 A9 w8 h: } - data: {
2 n6 T: G- ]( A, K - sites: [6 \, p' c# X' f- s B! E4 q5 l
- { text: 'Runoob' },
; Q9 i! U% p6 l3 [# F% A9 k+ ] - { text: 'Google' },
! Y! h( M8 y1 ^' A - { text: 'Taobao' }) Z6 b U6 K0 V7 }, G/ G$ a
- ]
/ a" M/ A* h; K9 Y n# K - }
# v: d: D. }& b4 ~$ S - })9 x: h* B2 }* \7 L
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
6 a# M |/ L, t4 Q7 ` - props: {4 `9 U4 y* J: t0 Z8 [2 a7 ]
- // 基础类型检测 (`null` 意思是任何类型都可以)
8 S$ n7 s, U6 m F8 G' i - propA: Number,
& V$ h0 K7 m+ U% L - // 多种类型& S. a( `0 o% X: F+ P" u0 H9 q5 M" y
- propB: [String, Number],
3 _1 b# A8 B2 [2 D m - // 必传且是字符串
) _2 w5 r2 Q9 D9 Q' r+ A - propC: {
2 b8 R) r3 p) ~& a1 r - type: String,: R9 i2 O3 m% t' g
- required: true- G- Q1 o" Q7 S W
- },
: c4 {4 N# Q" C5 }; P( b3 E - // 数字,有默认值5 q9 G6 o, O) @8 |
- propD: {7 @0 B4 V6 I9 g* O
- type: Number,
8 K* i0 k7 L" O$ J% ^ - default: 1009 a. G$ R$ T4 n9 y2 Q5 C
- },! u6 |; |) _ |8 T
- // 数组/对象的默认值应当由一个工厂函数返回
; U4 Y% X* Q. @$ i) K; P' Y* x - propE: {4 a1 ? s5 m3 y
- type: Object,( y% n( {. I8 o# N
- default: function () {
# g9 S" t1 I% a5 E( z - return { message: 'hello' }* `* {& K3 G8 \; X0 @' h
- }
$ h% D' e: c: S" I- n+ c - },* `9 ?3 U8 t3 D* i* Z j
- // 自定义验证函数
& V/ D* r9 e& {8 w6 [/ o - propF: {
6 Z2 W6 i" ~4 R8 f3 g - validator: function (value) {% J" I W4 t! _3 v# I
- return value > 10
. q! j2 J( U- E! |# t: L! e6 s; g - }
5 {& O: ^' N; K - }5 {; z% `$ H4 t7 |
- }
) @9 d; u' {! ?. j. m+ K0 [4 V - })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array7 A( t) d7 q. I) E9 s
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
, Z x1 R P" r# o, g
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例. s Z6 A9 n3 I+ q0 E1 G: J: w! P
- <div id="app">
7 i2 e9 A' h8 m& S. X N( {9 [ - <div id="counter-event-example">( l0 G6 S) k' ?# Y/ W9 ]
- <p>{{ total }}</p>6 ?* Q2 d$ U; M! ^, ]
- <button-counter v-on:increment="incrementTotal"></button-counter>
( L C% o5 R4 \8 R( t - <button-counter v-on:increment="incrementTotal"></button-counter>2 x2 e2 ?6 Z7 g+ G6 o
- </div>4 y+ \! E5 Z9 m* G% n5 ~
- </div>: | p3 N- ?: {
- . x( Z* F, f* f2 I# D
- <script>
o/ |- |; A( Z- r1 M - Vue.component('button-counter', {" k. f$ @+ J$ r. z6 C" Q
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
: E2 {6 k1 q+ b, l1 g - data: function () {
8 s5 B3 K" Z/ s- C' G: o - return {
0 S$ Y( V2 X' I- Y. a& m/ k& _9 A - counter: 0( u2 a' Q: M& J0 J* B' ~5 ~4 _7 w
- }; n, u! y' ^0 C9 o
- },! U1 U0 c( E. Y: t6 U# O
- methods: {& r3 ^* T$ x* N5 O2 A
- incrementHandler: function () {
+ u( d# }9 i1 F. x% e8 r0 A& p - this.counter += 1
; K! G( `' }' _* I3 ]$ Q - this.$emit('increment')# @3 J0 Z G( Z1 S, v( F/ \
- }
5 x9 x j' e/ U% A5 J$ Y4 s0 K1 \ - },6 i( N) N- l+ V4 c: i
- })9 x* @. \$ x% j4 t, I1 l+ ~$ K
- new Vue({% \. p" G) W! X; \9 a, v
- el: '#counter-event-example',
5 W" U% Y. x# d - data: {1 c( I9 d; V2 R; y6 n7 M
- total: 0' Y' _" |5 N& ]' W
- },$ I5 b2 a3 l5 ~( R5 j: \8 m0 l( b
- methods: {5 H+ L a# a" q$ P1 o8 J
- incrementTotal: function () {6 v- { D1 [7 P z, B
- this.total += 1
) Q( R$ d5 q* a8 u - }1 o x7 m$ F6 | ^% h
- }
+ n0 E$ c$ m3 ^" A% O3 f2 H4 b - })6 q6 j# ?+ v% C- w) A
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册. |1 V, Y- T( K% }2 E
- Vue.component('child', {
) G, j, L4 g0 U3 ^ V - // 声明 props; K( }1 H2 C+ o, Z' X6 c% h8 n
- props: ['message'],
+ D3 }2 d: T9 Q% { - // 同样也可以在 vm 实例中像 "this.message" 这样使用
2 q$ ]- u8 A/ Y' `% Y - template: '<span>{{ message }}</span>', m2 @, c9 v) X( n% \) ?
- })
+ J. j; `+ k. [& Q2 \# I - // 创建根实例2 R+ n6 J$ X$ s0 `
- new Vue({
# S! ] m) F7 F - el: '#app',' F5 z& ?, V( ^" O3 S& o5 `
- data:{
6 s5 d* X% U8 i$ u) k9 B, I - message:"hello",
# d3 h6 u( y% U1 \3 t5 l6 y - } C2 S+ `9 T/ j2 g# [
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
, O3 Y0 ^' H8 q+ L* ~ - incrementHandler: function (v) {
! U2 F! j9 |# l% ]% j5 c) E& A - if(v==1){
s" R D4 |/ L! X/ a - this.counter -= 1
; m; r% J( U( Q9 \; w' ?" D1 R) m - this.$emit('increment',[1])
; O2 o4 q3 Y p# @7 q: } - }else{, c" x# _3 M! B" O8 o/ M% Y# T6 Z
- this.counter += 1
9 j: n4 F$ A! _ - this.$emit('increment',[2])' \9 a( f* y, W) M f. a4 O9 d
- }* k z( g9 }; j3 o8 N
- }
# c7 W) S, l& y9 g - }
复制代码 $ J" j0 A8 r/ K! D4 b6 B
' ]5 |' t1 m+ h1 w/ q |