|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它: ! f% n ?4 ^0 v
- <div id="app">2 y0 M7 g0 l3 W: n! ?! \
- <runoob></runoob>1 u, ]% \* F/ W2 D' N# v
- </div>
- ~* A' J) J8 q. ]0 P -
. Y- m" O3 Z# I0 c - <script>
O# K9 k" }% R - // 注册
) P& v. u: R) n/ H6 |; x - Vue.component('runoob', {
j$ q: _5 N0 `! Y/ v1 r; ?1 \ - template: '<h1>自定义组件!</h1>'8 Q2 {: ?+ }/ M* l, s
- }) E9 D- g! J( C P1 a) a0 j
- // 创建根实例- {9 |. D+ I9 q7 z p
- new Vue({5 }: w1 f9 Z0 c3 I1 G( d# |! T: @ _' X
- el: '#app'3 s8 o& w* s; R! g7 R* B
- })& t! }0 N& o! ^9 G6 H! o
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它:
0 c3 Z: O5 `5 i. T9 ~- <div id="app">
* {0 J+ Q7 x0 A L - <runoob></runoob>
/ h* C1 h9 p7 C! z" j - </div>' ^$ z, f0 X6 ~* N6 ^8 N
- # ] e' N5 B* W0 g+ ?! T+ p
- <script>
+ x% V1 T& l* ~7 M. a - var Child = {
$ k& u, A7 p& G) o3 I x - template: '<h1>自定义组件!</h1>'
1 B0 e4 _6 U- ~0 A" M" g - }
" l& D! Z9 S! i: `" M; I8 s1 ^! U -
. f! _" b: v5 I9 x* s+ ~) h - // 创建根实例
4 ~$ \4 Q2 F m+ K8 [- R! d, f - new Vue({+ {: Q% w! C2 l+ [, T
- el: '#app',
8 p6 G% b& U( g% M2 `/ E - components: {
) q" a. A/ F% k1 E; _ - // <runoob> 将只在父模板可用4 `" E: f9 I$ ]' _3 c5 W$ X* T9 x
- 'runoob': Child, O; `4 k4 A$ G3 p, q! {2 h4 t& i
- }
$ c. |' l7 r# _3 }' W- b q9 _ - })
7 K% L. H* Y* C; o9 P* ^& ~ - </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例. e$ F/ `2 z* K) C' L) X, O
- <div id="app">
. @$ r& [" T2 ?0 @5 }; i+ i - <child message="hello!"></child>
h) {) }: [, \- z6 a - </div>
' t, C0 e# v5 x' y! N0 O2 G -
' a7 {0 `: K. |% t - <script>3 J3 x' B! }# J# d2 W$ j
- // 注册% c* p' g: x. J
- Vue.component('child', {
& r, }! j J, K1 k) M4 o - // 声明 props
( P: p3 c. [% R: l B: `" c; j; ~ - props: ['message'],; N- C, P3 F- C" i2 n
- // 同样也可以在 vm 实例中像 "this.message" 这样使用' n1 r6 l* K5 e4 L
- template: '<span>{{ message }}</span>'
! n2 c8 R) a& | X - })
+ @6 e4 T- q! v7 C/ \8 p$ \ - // 创建根实例4 C. _. K; q) e4 W9 P" z+ a. c: N
- new Vue({
7 Z) B+ b) L' |4 F/ O; B - el: '#app', V. ^, d0 U) A8 x
- })
* ~- Y/ X$ \8 j$ C, e' P" B: D - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
8 {, q r( _. m( p. \- <div id="app">. y* W4 z# R4 ^% g3 N6 s
- <div>% ~9 Y% O' W+ _3 n' k& t c) O
- <input v-model="parentMsg">
& U3 s% R* g3 x8 w - <br>/ ^2 F: K& d, s+ N
- <child v-bind:message="parentMsg"></child>$ w3 \1 n* ^+ {% B# p
- </div>
G) W% P- G2 z) _+ N) T - </div>3 c( Z" |6 K- g- l) S# ~
-
( Q5 M% K! c, `8 W - <script>% B$ N, v/ ]2 ?% j1 [2 i! O3 e
- // 注册
% G; u' Q2 s, f' G' G! { - Vue.component('child', {3 K% u7 z4 K6 S+ H& s7 [, ?5 C. r6 O/ S9 ^ O
- // 声明 props) |, x# G9 M7 T0 s# D5 f$ Y
- props: ['message'],$ {# w$ b; k9 t& k7 r
- // 同样也可以在 vm 实例中像 "this.message" 这样使用' Q* d+ Z) |/ M
- template: '<span>{{ message }}</span>'
9 C: e9 H- M7 @ - }). h9 Y( p6 }/ G
- // 创建根实例) @4 @, Y* x5 l. S; V" ^
- new Vue({
, [8 e# i9 V! E Z4 f7 t4 p1 L - el: '#app',
7 W1 A/ L: k: p1 |3 Y1 H+ X - data: {5 V* U; b$ N+ ^2 c5 U9 D3 q
- parentMsg: '父组件内容'9 W% w d) z, }) p) x2 D
- } R( I& i/ W' U' T" F
- })
0 `+ M o# @1 R% r2 H- C) j - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例. D- _* B! {/ |
- <div id="app">: r5 g4 G' s( F! B
- <ol>
! Y {. U2 h; o - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>5 F! t- K$ k' Q3 o& u
- </ol>/ U& V% X0 u4 s" G7 K
- </div>
& M: G6 D" }0 J6 f - 3 G+ b9 n+ b6 f6 Z w
- <script>+ ]9 N2 s% |# Y; Y W+ J
- Vue.component('todo-item', {
, o8 V& h4 G- w$ P - props: ['todo'],
/ x/ E- S y6 X5 J" N - template: '<li>{{ todo.text }}</li>'( ~8 G! O+ a$ F9 b/ ^9 U
- })
7 P1 B1 d7 P/ x. Y" ?; E+ S - new Vue({
- |3 T. m3 E2 h/ P3 L2 ?1 C! t0 |/ { - el: '#app',
8 ^+ V& E" n! q9 A9 y. ~ - data: {
& `/ ?7 o9 b, H+ j7 U( C1 }' ?3 w - sites: [ U* C' N( o0 Z2 x0 n! {# g
- { text: 'Runoob' },$ s3 h# m4 r% L. ?
- { text: 'Google' },: E4 i, q- h8 d0 [% u
- { text: 'Taobao' }! ^/ f7 _0 e* E
- ]
! ?$ R0 }2 ?7 ^' A+ i# |5 C. x - }
* n. C, U/ w3 j - })
) H- ]' s1 x2 t% u" }) V; l - </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
A! H ~/ G# c9 | - props: {
6 y4 p- E0 r; [. T - // 基础类型检测 (`null` 意思是任何类型都可以)
; ], I4 k0 M, n" `, j3 u - propA: Number,( \5 U9 R9 h4 C
- // 多种类型
' X$ ]: k# s% W: V8 a" j - propB: [String, Number],7 m6 R' ~0 ^' m. O6 S P5 W
- // 必传且是字符串. B# u" e% c/ c- q- }
- propC: {
7 z* O3 c8 Q: @6 l - type: String,
0 T1 l X1 O6 ]* ^' g$ z( f, b - required: true
# l3 p: t7 i$ [# g - },: t; ^* V7 E9 N/ {" N1 r
- // 数字,有默认值
. l$ C4 l% u1 `7 c2 R - propD: {, S1 ]& ?( I4 W
- type: Number,3 Y! D8 g: j5 D3 C1 ^
- default: 100
& V/ E' I% _! c1 F9 ^" U - },; `. }7 R) u9 v* _
- // 数组/对象的默认值应当由一个工厂函数返回5 e0 o6 R) V! ]# K' ^# D
- propE: {$ Z+ d4 _) }& j, o' G3 N
- type: Object,3 l, {) ^9 E/ z5 ]
- default: function () {
v: H1 Z" T0 c2 g - return { message: 'hello' }
6 b9 S4 N8 y. w+ U% i - }
! n9 j5 A/ r; Y" y, z$ L$ W - },
. A# {9 [$ }- t - // 自定义验证函数
' N% Z6 B5 W' s" s1 u* n6 ~ - propF: {/ A$ ^3 G1 R) d! d. k: z, R
- validator: function (value) {
6 A' U* D# c0 E$ f- x" b, }# N9 Z - return value > 10& Q8 ~- n8 H; H
- }
, o( r8 W7 J$ W. x8 F) ` - }8 J* I2 m% [1 O& l1 M
- }' }- \9 R( g$ L+ L3 h
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
: F% Y/ m8 |7 T/ J% Q+ {
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
0 Z2 L- W9 ?4 _5 b
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例 }) V+ O2 x. O) ~ H; V
- <div id="app">
: b8 }. i/ d. G5 r4 d: e3 D - <div id="counter-event-example">
7 R# ]* B) g: [+ d: Y( g! i - <p>{{ total }}</p>0 y2 K- \2 r& P
- <button-counter v-on:increment="incrementTotal"></button-counter>
+ d+ ?) ^3 [$ [: Y1 m( i - <button-counter v-on:increment="incrementTotal"></button-counter>
% ]+ a5 M7 f2 x% R R \ - </div>
6 _& O4 L# M( L0 \* Z8 ^* A - </div>/ g3 J- \" d$ g5 a" O8 F
- % m4 x* H, f3 c2 r( _% ~ e9 E9 |. u
- <script>
4 k, \6 z& D: K; R- W; C/ L - Vue.component('button-counter', {
' ^0 q, M# T8 U1 M; D/ h# h - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',! x3 P4 q4 j' i) t% {
- data: function () {6 ~9 a! l, I; [/ f$ F* {0 y% r
- return {
0 @3 r5 `5 H3 N - counter: 0
& |% G0 ~6 y( \) L) Q# o - }" H2 L" @" J! X* Z
- },4 O0 {( W. y9 ^$ [
- methods: {3 {9 Z/ Z9 b! v ~ B5 |
- incrementHandler: function () {8 U* k6 n- x" V H; o
- this.counter += 1 i- _& E& L3 I c
- this.$emit('increment')1 Q0 |* u1 u6 `! Q; ~* D8 m
- }" p# p2 j5 e& U' t
- },0 k0 Y1 U) ?1 ?: n5 A0 ^2 a
- })
* u0 a7 R0 q! B - new Vue({3 y! O8 G4 e1 P7 L/ E& d# G5 ?. d
- el: '#counter-event-example',: k4 O/ P! i9 m( Z! M$ T
- data: {
8 {4 \+ N( _. a; A - total: 0
9 n, T7 \$ w5 e6 ]0 D6 Z8 X - },
' V1 p! y9 e" g2 k2 r# g& F& p - methods: {% R' }' J0 V7 p! B- y
- incrementTotal: function () {; i. l6 ]) `2 R" i( [3 X, T
- this.total += 1. x0 Q) c+ {7 s( P |6 T
- }7 @1 j& I: [5 }7 G" B i
- }7 p T5 r* [ k) j' K
- })
! H3 w+ Q- Z6 l. u- r - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
* H1 y. D( s8 I# c - Vue.component('child', {
/ k" Q) c( Y# d2 f* F# v5 I - // 声明 props
- ]9 f) \2 ?4 f5 E) B, S' P - props: ['message'],' S0 Z7 Q% z) R! d4 n7 e0 l
- // 同样也可以在 vm 实例中像 "this.message" 这样使用3 _' t. O$ S- Y: K
- template: '<span>{{ message }}</span>'
% Y9 L3 h6 J$ u) n3 m - })
3 y0 A" d9 g) a- K- P, C - // 创建根实例1 Y; J; A6 o+ n
- new Vue({6 @& r' A/ r$ H/ u" B
- el: '#app',
* v+ \( i" H- q$ N& W( A - data:{
$ q |; V; r4 r* H4 S! o - message:"hello",9 s/ t. n- Y; H* S, ^
- }
. e& q3 {9 v; M - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
g. t$ @. p Q - incrementHandler: function (v) {/ z$ K. }; e- }$ p
- if(v==1){6 F! k8 f7 z7 c; \% Q3 L9 I
- this.counter -= 18 n) h$ W* M, a: q( r# T( A
- this.$emit('increment',[1])
& Y3 S: P3 k2 E c) V - }else{5 {. u* |7 O# I. z$ u# G! }2 v
- this.counter += 1
& u; [+ o# ~5 G" T9 ]8 s. y J. p) u - this.$emit('increment',[2]): D; S2 v% p' \0 X! H: W1 G: _
- }
6 @ H6 e+ N/ J& ` - }; r2 `8 w8 E4 @$ s$ h$ l# Z" ]9 I
- }
复制代码
1 S5 y# `( E9 i7 H( a
2 u, ^7 U/ B ~& z$ H9 ?# Z |