|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
" J9 F- L: Y) x8 x% l2 l- <div id="app">
& @9 z0 i+ I6 c1 U" L6 d- K2 C$ a - <runoob></runoob>6 o! C* i6 `; J2 a' ?$ i5 T Q
- </div>7 @1 m7 W/ b4 @" |$ |) ?8 l, ~5 B9 y
-
) G0 i/ P" Z+ O% T4 r2 q. T Q - <script>
2 e6 n( y. H, I/ I - // 注册
9 r# @5 e5 P- Y - Vue.component('runoob', {( P0 N- l: u9 ~# e; f% m
- template: '<h1>自定义组件!</h1>'
% V. m t2 t4 V( s% ]% G% ?/ [5 B - })
: Q! L/ _- x, E; Q - // 创建根实例5 y# E: G% a0 p. S; z+ B6 s; m
- new Vue({3 X7 a+ k, u- Y2 b% q: ` [2 ? L
- el: '#app'
8 @2 W5 k1 H, s- L0 l+ D - })
" E& U1 W1 R& M: \1 L6 b4 m - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: ( T3 O4 o! n$ m- Z; F( C$ c" K- Q
- <div id="app">
: F6 h+ j) h! S( | - <runoob></runoob>3 N2 P d: q5 |
- </div>
% b' X7 }$ d) h4 W - & ]3 q3 `" ?5 r3 d2 H* m: X
- <script>
G) [4 ]! o1 {3 R d4 e - var Child = {& Z4 a& [5 o) z8 _ g6 e2 l1 Q
- template: '<h1>自定义组件!</h1>'; {9 z0 r0 R8 W8 Y* D
- }) V5 o3 R: y* O1 z
-
6 d8 {" c9 X' E7 F/ Z5 j3 } - // 创建根实例* l$ m# G& P, {! O( @( h, `' G
- new Vue({ v- c4 a0 u: C: T" _% S/ K
- el: '#app',
: y2 u f# n* [7 V - components: {: L2 J6 m0 X( `4 j& s
- // <runoob> 将只在父模板可用' T" c u: U. n7 k6 I( l
- 'runoob': Child
! f$ U' v! u3 I- y - }
: Q7 K* m( }5 ]4 s0 n - })
' g* `& _& F& X: b* W8 E1 x% k - </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例
4 d, K' Y9 ~4 k3 V+ J, @: Y( P o- <div id="app">! @8 Z2 ]; Q: R+ u7 [4 w) r
- <child message="hello!"></child>6 g: q4 e; D+ E0 \
- </div>' Y7 w( V$ I2 S" u4 G
-
4 K+ [+ {% k" Z - <script>+ N+ S. @* [! X: P( o8 i
- // 注册
7 h! `. y# b0 @ - Vue.component('child', {
& V# y2 r3 i; N0 X( Q& I4 y - // 声明 props5 c6 E0 K& I* \( }
- props: ['message'],' O; W/ m- g& \' X* Q
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
! s7 O, K5 y7 j- c; V' t; a - template: '<span>{{ message }}</span>'; h, }* \8 b- x- ]
- })
r; C6 t+ z. j( g - // 创建根实例) u$ V+ z _$ W7 ~
- new Vue({
- _. V- [0 ~3 z% F+ \ - el: '#app'
* E0 j! U1 s; y& a# P - })0 W0 L3 X+ W! f$ }% x1 z. K
- </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
# `: c3 b7 n- ~$ c, k* c- <div id="app">
- P9 L! b2 g6 A8 d* L: {% Y - <div>
+ Q- I7 G( k) q% x5 l - <input v-model="parentMsg">
. f7 }2 _1 M9 X# p' | - <br># p! E4 F3 o; G* n7 X0 E
- <child v-bind:message="parentMsg"></child>5 W+ N# I3 D8 G
- </div>$ `% A) S G: r: x- ], |" J! `
- </div>% f0 s& @$ S2 b
-
' \% {% I. W4 M; G9 z - <script>
- _ M7 C d* x! D( o - // 注册4 l% [* Z6 u( l/ m; ^" r/ x U# k
- Vue.component('child', {
. l. Q2 f3 t/ |( \ - // 声明 props
7 V7 X7 I# m4 j- f% B - props: ['message'],9 a0 u3 ?5 f' r; _: j' v' j& p
- // 同样也可以在 vm 实例中像 "this.message" 这样使用) N" H8 J) }% ?
- template: '<span>{{ message }}</span>'$ b8 @% x9 [( `) C
- })! I, e6 {6 L! J
- // 创建根实例
! m) r% \* M% l; _" ? - new Vue({
$ u I. ~. r4 u8 C$ e( g2 c - el: '#app',8 Y; v3 _' v1 N" Y- ^0 u
- data: {9 M7 o5 A {& G6 M: h6 p. R1 X
- parentMsg: '父组件内容'' K% h6 n8 ^! ?. `0 x
- }
: \8 ~: g8 \# l" O7 s - })! s5 v' ~# {3 w, a5 g4 G! G
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
! U$ `/ n* @" B- <div id="app">
/ J1 U& R$ o0 C4 t" `. i) }2 _$ E - <ol>* Y7 c# {9 E: w3 H. D" \
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
7 _. `6 ~- a6 F8 l: v& F; Z - </ol>
4 f( d2 l" q, j" k: m - </div>
" ~/ z9 r4 G, C% m* _4 p - + D A0 @- V& Y7 T( S
- <script>
" Z- {5 |4 p9 w+ S6 A/ Q' Z - Vue.component('todo-item', {
. K' N3 F' x. y3 v - props: ['todo'],' w# L7 J7 u8 f5 {3 O8 z U
- template: '<li>{{ todo.text }}</li>': p1 B: x0 K: x0 T
- }); I! e7 p0 b- d3 G) Z
- new Vue({( Q. s. C5 \9 m5 {. K/ |9 f9 F
- el: '#app',' \) x5 g4 ]% P( @* V/ z0 s3 M R
- data: {
! P8 Q7 K$ U6 w7 C - sites: [1 G2 I5 l; I z" p! W
- { text: 'Runoob' },
" Q2 s' C# T* y7 k' k! M( Z7 H - { text: 'Google' },
* x" Z9 t0 ?# g' c3 [8 g; n+ v6 q - { text: 'Taobao' }+ B! x, E' }( Y4 F
- ]
( @' q) ]; U" R7 W5 b% X9 t - }) J5 U, @' k, v0 L) C- L
- }). Z6 Z/ M0 t3 ~+ ~" a
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
* D+ p1 d+ _5 w9 } - props: {2 j1 q+ F7 @$ L9 f9 R! s* g3 H
- // 基础类型检测 (`null` 意思是任何类型都可以)
) O* O' V- Q, e$ J: e- M- O$ C! V - propA: Number,
7 D6 U7 }+ \% T* @: m' Z7 a+ b - // 多种类型- W3 G9 v7 N: r9 ~$ h
- propB: [String, Number], b$ d9 y( W" ]4 t& B4 @) J
- // 必传且是字符串$ H: b6 ]1 ?8 h! O2 o; d# d# U
- propC: {
' s P# A: {/ h. ?6 U* B - type: String,
& _1 T B' P7 P9 a: d - required: true; w% o8 {: V; y! O* Y% v6 a1 [
- },1 `3 N9 z+ E5 [1 L
- // 数字,有默认值
# s- @8 C2 C# p0 {3 ~' H% ?& J$ C% g - propD: {* b5 }: W# [: q, A8 H0 T# a9 t% C
- type: Number,
% C0 ]( h, I! }) w - default: 100
9 h% `9 f9 H, r8 h9 K - },5 T* y- ?3 k% x& V7 p' k
- // 数组/对象的默认值应当由一个工厂函数返回
9 e3 D \* d; y9 q, O$ L9 C: a2 _ - propE: {
6 V8 [9 P5 Q0 a4 V. Y/ u - type: Object,1 } d9 y4 a- O- m# y. D
- default: function () {6 i) P) _# t4 \5 U/ G9 y2 j" A9 |
- return { message: 'hello' }
# t; \3 B1 h5 Q& O1 H% j; U - }
+ p% b0 _- U& T, c2 F$ H - },
0 o) v% d& y% d' f - // 自定义验证函数
* ]- l4 n& V) b# S# r& A0 i, f0 U - propF: {4 |/ ~7 ?) {9 I* x6 D( w, H7 I
- validator: function (value) {
7 A: d/ I9 Z4 w$ C' J% c% n; Q - return value > 10$ D% Z4 t# K" L' d* n% I
- }
1 m3 s5 i; |0 j* G - }9 y: r0 w8 I$ }
- }4 H" c& x$ y z- {
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array, ]+ b. j# M5 m+ O: @3 C5 ]
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件" Y+ U4 |( ?3 i) F$ Y- ]6 h# m
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例% y6 H. ]5 b: D3 H" T9 d
- <div id="app">
* z( V' |, W( k' J0 r8 d8 ^# m& F - <div id="counter-event-example">" @! p9 {# Y7 G; N0 [4 D+ G# H, {
- <p>{{ total }}</p>+ _; p3 V$ L0 c, y! R5 E
- <button-counter v-on:increment="incrementTotal"></button-counter>
X! O }8 i) r6 D- P" v: y - <button-counter v-on:increment="incrementTotal"></button-counter>2 M1 V! F6 R) W5 c( A; X
- </div>
8 i. B6 F4 b/ a# p- T) ^ - </div>' y5 _; b1 k, L
-
& E* r ]4 C2 v3 ]( N - <script>4 l8 i! }, C, ]" A8 b4 _: T- d! W; h
- Vue.component('button-counter', {
+ O5 |! g' b) U1 ^; \4 Z - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',; R) J. a, m a( J1 m5 a1 I6 B
- data: function () { q. c/ Y. m& N: p/ l1 V% X( f z3 [
- return {
& Q! P# m- {+ [ r/ e - counter: 0
7 w% V4 W2 n& O* i" u: ^6 W) u4 n - }) z- Z# O! y6 U0 n
- },- F# D1 s3 v3 ?$ v
- methods: { y! a7 G4 t5 g; k$ p
- incrementHandler: function () {: J) |' ^ P- C6 Y
- this.counter += 1* L2 B3 r- W2 d q* F7 M5 ?
- this.$emit('increment'); O3 e+ G; S b- b) u
- }1 f" V6 H: k9 y6 c( {
- },
& ~% D9 M- L. v. y6 H3 |: [, ~ - })( h1 J5 r. S. b( [9 z4 K
- new Vue({ G4 U/ P& x& P+ X$ j
- el: '#counter-event-example',9 @4 W- u$ p( B, @& U, P
- data: {
* h5 `3 k. W: @* x1 T) u - total: 0
! R8 s. d) G8 T9 j9 ]$ O3 T - },
. G* d9 g4 l2 D- F9 P - methods: {0 c# ?, U- [8 x
- incrementTotal: function () {
' i. u* F; o- b U) ]8 r - this.total += 1
9 @& G5 X3 H3 } O - }
5 [& p1 N% q$ k - }1 O7 e7 C7 R: a _( M7 H* V( s( J
- })
: J7 V( d8 a7 |$ U% m - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
* a9 Q% P, U3 `2 _ - Vue.component('child', {/ s5 F1 f8 J! c G' ^
- // 声明 props% H' S8 r& _8 k- ]; i
- props: ['message'],
4 p) \4 f8 a E; K$ I - // 同样也可以在 vm 实例中像 "this.message" 这样使用
7 o+ H% p4 E9 \/ l% K - template: '<span>{{ message }}</span>'5 q- C9 s V# B0 F6 _1 N
- })" R& F0 I# h3 ]8 V& w. F3 C
- // 创建根实例, ~3 u% P3 M- U1 t/ x4 `0 {
- new Vue({
' D" ^# @! |% T. G9 t9 q: ]- E - el: '#app',6 g; P: ^. o# ^! c
- data:{, Q. F5 M+ k9 S/ ~ C
- message:"hello",7 r A' L- @ t: c) p" x1 O
- }+ B$ r' O# J, x2 G) J
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
3 {! t: R, X+ I s - incrementHandler: function (v) {
j$ T5 c; g- ?& n - if(v==1){
% ?5 E% n1 a7 N) u* h! A+ w - this.counter -= 1
1 p' f' F8 u! R/ e7 u. J6 b( i1 C - this.$emit('increment',[1]); X4 i8 L' A4 a3 f* V
- }else{3 Y$ A% s7 Q' f' E, x n
- this.counter += 1
9 z1 j# q' p2 C* @3 w, @& H - this.$emit('increment',[2])- ^& x3 o6 a- M+ \: Q1 o q
- }
" l" R/ p, \% w, o, A - }
. t5 o( K4 b# _+ F/ [ - }
复制代码
3 H" k, \$ a, W- y* V9 b8 ~6 x; T/ l# o6 o( j8 p- Z
|