|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它: & i, c3 G( g% R4 ~, b) d
- <div id="app">/ H6 ^: L) a) [) @7 C
- <runoob></runoob>" C. S2 H; b0 e1 \# I
- </div>, p$ f$ e4 n% {8 |" f" R
- ' v& W R+ A; Z% I$ l! e7 m$ x
- <script>: N3 X, Q! o. I* z. `% o& N
- // 注册
! i0 p9 Y9 V3 X8 A - Vue.component('runoob', {
2 i# W" e5 F8 J) z+ q - template: '<h1>自定义组件!</h1>'5 t" s- e- x6 S2 k8 Z
- })
5 J! p: W3 B, n4 s I" q - // 创建根实例
# M) j! {1 H% G$ s; h' w - new Vue({
4 t: W7 l0 S! X- |! n - el: '#app'
% r1 |" y% j& y( z& }1 n - })" ~7 n/ |9 g! h+ ]/ c; A" C$ T
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它:
' a% v! `+ R4 a' P! f3 N- <div id="app">7 q# K+ S* Y: ]. y- S
- <runoob></runoob>6 z3 A( K5 S3 e% e9 @
- </div>
& W7 K+ h3 D9 `3 \1 d$ X -
- U6 D+ A# o5 j, n5 N. w9 _2 J - <script>6 y z1 e, y/ k' z$ w" Q+ c3 ~0 F/ G
- var Child = {. f9 x6 K6 A) e: _
- template: '<h1>自定义组件!</h1>'( g3 w; E3 o5 @$ G9 v
- }. g% f' Z! s, C5 Q- `
- & `8 \) s+ j. `
- // 创建根实例
3 X( @' k8 o$ R - new Vue({0 g, _6 H( { |. [$ C& h$ g
- el: '#app',
5 W$ m- O, s3 d - components: {
6 W" t6 p* [* y6 D/ h" [ - // <runoob> 将只在父模板可用. _5 ]9 S y$ D- ~2 }: i
- 'runoob': Child
) [- l4 s- @* m - }7 h/ ?7 O! g0 r7 X w0 w0 @- J$ A
- }); X+ v4 Y* [* J* p( W$ ?3 `8 \
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例* t# m4 L8 o* G& j) c5 T3 d
- <div id="app">" q) K; x l1 S+ y9 P
- <child message="hello!"></child>1 x) d+ Z% x8 H. t
- </div>1 `/ m6 G/ x( X | M- h
- ) }+ f9 o# g( \1 y3 ?* b
- <script>
4 l* y% p2 {6 Q( W M - // 注册
7 B8 r( f( ^$ w T2 d - Vue.component('child', {
! X, o7 r/ |8 U4 b/ t - // 声明 props. C/ o) M% [% u
- props: ['message'],
: z+ R, w+ [3 j* Q+ [" m! N9 T - // 同样也可以在 vm 实例中像 "this.message" 这样使用' o2 v9 l! M b. m/ ~
- template: '<span>{{ message }}</span>'
" |" O! u3 _# \5 t - })
0 g6 q) Z# }+ Q# P - // 创建根实例( f' m' D, x( Y; m
- new Vue({
1 S. G3 v/ }9 K) N1 D - el: '#app'8 M% k3 b& t+ k6 o
- }) m8 x1 N o" J: q: r) U; _* b9 x
- </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
: H4 l7 k" J W1 Z; W9 v! \* Y- <div id="app">
, R- B; ]* L" D7 {7 [, D - <div>) m; c5 r5 m( Z+ \# e
- <input v-model="parentMsg">
% _$ [: J; k4 A4 n; Z - <br>
8 H; C" ^! p. I2 I& ?! g- O6 _ - <child v-bind:message="parentMsg"></child>; F% _2 i- E! s- n& [/ T
- </div>
0 P. b$ [( m$ ^* v* I. R - </div>! l' R2 z3 A- z; H6 j
-
+ Z ^4 F6 j/ P - <script>3 k) {. T. y, ], R
- // 注册
- P* Z. B r7 x/ x j - Vue.component('child', {- g6 i1 s. ]& C2 L# T4 f
- // 声明 props9 S! Q9 [- k6 _
- props: ['message'],
( f& W+ S) Y" G8 ]0 G6 F - // 同样也可以在 vm 实例中像 "this.message" 这样使用( P" [- s: @, n9 }& k) e- c% Z
- template: '<span>{{ message }}</span>'
+ C1 S K1 z6 `5 R - })' y; |/ G' _* h6 H+ D
- // 创建根实例
1 V9 F( ~* A9 S( p+ l2 z - new Vue({ _: y8 k% z1 w V( L9 b
- el: '#app',5 w$ z( `* D$ }1 Q/ z: ?& b8 [$ T5 H8 o
- data: {
% }5 u% v4 [* h4 Z5 W - parentMsg: '父组件内容'# X) x2 |1 w+ k9 F- @
- }5 C5 B u' @. h" ]9 Y( \8 x- v
- })
7 I; Z+ m0 x+ u - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例/ p8 [# ~5 O% T' g& a% m
- <div id="app">
2 w( k- z* L& }1 z - <ol>
6 m6 ?4 c# `: i - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
0 Y6 [6 C6 h( R2 t9 s, X8 P4 R - </ol>% Z+ B1 x" u1 P; }- m
- </div>& q) ?+ j# [- {9 G0 k; M
-
. j8 t$ H+ v. C; K0 J - <script>! Y4 L) r; y; N% t" D3 }0 j. f( f
- Vue.component('todo-item', {
0 H! a6 a2 b/ K# @1 D - props: ['todo'],8 ?6 ]/ g- }3 M7 E5 H: j
- template: '<li>{{ todo.text }}</li>': K$ [0 j1 u+ m4 j0 R
- })
' M- K8 U' X* u4 a+ R# B) f - new Vue({3 l d$ \! ^1 V, T" {0 f& O" s
- el: '#app',! r$ b9 I# P3 V- m/ h0 K
- data: {3 a2 i/ D' e# t+ w- T* @2 ]
- sites: [
! R2 c$ W" H! \: Y; h$ d - { text: 'Runoob' },
( v: X3 k; \, U/ s6 p; E - { text: 'Google' },
9 D& r5 l* \+ H* H - { text: 'Taobao' }
2 r8 a5 ]; k) D; V - ]
! B3 v, Q% q3 m6 i) O7 S, _ - }
3 b) x( g" I/ ]- W2 P - })
" Y" b. t4 w) H& ] - </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
! a; W! K9 E& h% T# K" j1 m; S - props: {
6 n' _" a+ o0 \) o* C - // 基础类型检测 (`null` 意思是任何类型都可以)
) O j& t% K! Q$ ` - propA: Number,5 L8 Z: `- W* W {! y$ [7 C1 x: x
- // 多种类型6 E% A. m! |$ V
- propB: [String, Number],
4 R8 c4 K: O( y. a* L - // 必传且是字符串
/ B$ g, ]3 k7 a( ^ - propC: {2 t7 _ {2 m( K7 o* h% v& i
- type: String,9 i/ q) d. B7 W: B8 L8 G
- required: true
+ I' t6 F6 J5 y3 j6 R& M - },; t5 `0 u9 y: `5 W8 ]; t7 b& ]
- // 数字,有默认值
* b6 Y2 S* _6 A - propD: {
* o# p! o" ?1 U- C- l1 x7 f3 T - type: Number,
. U2 j G! A5 u - default: 100
+ h, _$ E0 n+ S6 X ^, p) v) C8 N, P - },
6 \3 ^" F" K+ z" S* Q( ^3 d' S, P7 e/ s- I - // 数组/对象的默认值应当由一个工厂函数返回' ^. d0 O1 A, R8 k s3 O1 K: E# E# s
- propE: {
5 N3 c7 K* q( n$ I - type: Object,
: R* w3 d4 O1 A - default: function () {' j- ~- ?+ c" G/ u5 G
- return { message: 'hello' }
$ p3 p4 _, E( z - }
1 M7 Z6 k3 F: H3 \ - },) J5 ~% o1 g7 B# B
- // 自定义验证函数2 h; h- J+ G W+ O {- M3 [
- propF: {6 L3 r- u0 C0 M K2 f7 h4 H
- validator: function (value) {
6 U5 W# X9 x2 \3 r# n8 v/ o - return value > 10' Y. t7 G" L9 F9 k
- }
: D; @. H% m, m; N4 c7 M9 {- } - }% B' Y6 L! V4 }$ z
- }1 t9 Q$ W+ n1 s& b2 o: l. u& r# J9 ~& v
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array! f2 |7 t) w! x
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件+ w) V; [1 z: G0 W) a% X m" k- S
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例
$ Y! r8 P z c9 ~- <div id="app">
/ O# e$ S- M7 O% F* ~. p! x - <div id="counter-event-example">
0 G8 F) l/ ^, M" E4 n8 M - <p>{{ total }}</p>
5 Z# ]( X6 `7 R0 `3 w, k9 A - <button-counter v-on:increment="incrementTotal"></button-counter>1 g1 W3 z$ l! l7 B1 x+ K7 @
- <button-counter v-on:increment="incrementTotal"></button-counter>' D7 U: m. i: D! C7 i3 T# N
- </div>
& I, n3 D! I5 e( o- s+ _/ G - </div>
2 c0 s/ x7 S2 a2 K -
* m/ x: L5 U- d - <script>+ B ]& @/ v9 p) ?, q
- Vue.component('button-counter', {; _/ X+ O8 H& _: K" r
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
, w; q9 M8 C) K/ Y: ? @ - data: function () {
1 Y, ~+ t6 ~ L c% P X - return {* P4 i0 T, T0 {6 f( K' o
- counter: 0) X, b* ~5 J8 E6 |- ]) r8 }3 z
- }8 h2 l+ n9 L9 w9 E/ |' z2 N
- },- i1 O; @1 f- ]4 w; [- Q
- methods: {1 @( D! @4 H6 U- N# N
- incrementHandler: function () {/ K2 t9 Y2 ^: e$ E
- this.counter += 1
6 v4 @: K/ H3 L, U. f5 L6 @6 n - this.$emit('increment')
% Q, |' ~4 w, T3 g2 V - }
, ^" C2 ^3 j* z3 X [2 h3 R1 p - },
: o9 X1 @( a- P% _; D. b - })" l ]7 ]% t+ K0 T
- new Vue({& o' [$ C& w9 y& M
- el: '#counter-event-example',
! b: X6 N6 k) U% x. @" P& D/ _7 T - data: {
$ ] O% `1 k- X* `) a - total: 0' L, _8 f' W" U7 Q1 C
- },- w8 j) W/ }4 e7 G; `& A
- methods: {; E4 T, f& b$ C+ A
- incrementTotal: function () {+ Z- V5 ?4 o5 {" u
- this.total += 1: I/ v9 r. B; k% B9 I$ Z, q
- }: X- N4 M0 A3 K( Z! i% b% L
- }7 P5 S e* s) {0 c# Q
- })
- I* l* i! S5 n - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
4 r: L9 U! y- W* F# [ - Vue.component('child', {8 O5 J0 R$ @7 S
- // 声明 props
; O4 p6 ~; P' |% L3 V7 B - props: ['message'],; B) b( G4 l3 p# u+ A/ P0 L5 q
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
) L* E* K8 |- S# j - template: '<span>{{ message }}</span>'
6 V8 J4 g# R4 {6 r. w7 p* B - }); @; z5 ?; W$ p, I; J
- // 创建根实例' c! U$ S% i$ r1 k: B8 U
- new Vue({
- u, g% L' U( A( [5 | - el: '#app',
! w; c6 H+ ?5 [ - data:{
9 w) ?; `* e6 {- Z F - message:"hello",
; t" m4 A: N8 l6 G4 n# l& f - }
+ X3 o7 c$ y% G( R" J. E - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {3 g1 ?- u: ^& A1 q4 p7 ~
- incrementHandler: function (v) {& G1 s. S! i! c F. o3 K( x3 }4 [
- if(v==1){ G; w8 f/ M3 d1 U3 J
- this.counter -= 1' ? k2 r/ k9 P- e: o. S L# \
- this.$emit('increment',[1])
% ]& Z7 Q& ]# b, N9 \- b - }else{
" r: B5 {, M) F - this.counter += 1
- L* x B6 x" w# ] - this.$emit('increment',[2])# X7 t" v8 W4 `7 Q$ M5 l$ r
- }
9 Y% i8 o* b: ^6 v# B! P - }
1 p# O& V! F+ Y; A - }
复制代码 . u2 k8 @9 n3 v p6 c4 E$ U( v
. t8 l" u1 r n5 T9 O: D9 A# g
|