|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
$ ?% x' X$ |! Q% ]5 u- <div id="app"> y N4 e) s5 Y# X( E& j: f/ T& a
- <runoob></runoob>- v/ _- `1 x' F( f+ j' c
- </div>4 t# [+ D- X$ W/ i# D/ c+ F n
-
, n" r! D, n! D9 L" _ - <script>
/ i+ y, ]" ~1 x$ s7 I1 x/ ?, z - // 注册
! @8 R: H# O# ]7 ]0 n, { - Vue.component('runoob', { P6 g: s( h M* o0 Y9 G# K
- template: '<h1>自定义组件!</h1>'
. B( e( q" Z& Y" _ - }) n7 r% R5 o# l$ D% ]) @ @
- // 创建根实例6 X: V; I9 [& r4 b6 H" U/ t: [
- new Vue({& A- ^' W( E8 k7 f1 \3 z3 o: Q
- el: '#app'
, l0 \/ S' V s1 x! k0 ^8 H - })# o5 C2 B* M8 J# w1 E
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: % d3 T$ ^+ U% r; z8 F4 U1 k, L
- <div id="app">
' k: L+ ?/ w9 C - <runoob></runoob>: i: p# f* H0 u2 }8 I
- </div>
6 @5 G6 I- w7 Q -
. A: p% r0 a j/ K6 g( T! C8 e, h3 b* n - <script>
@6 c" [4 ]# q - var Child = {
! G! m' M+ h Z - template: '<h1>自定义组件!</h1>'9 f1 c- H' a; K+ T5 ]6 ^
- }
+ l' ^9 Q( K% {$ v$ J3 C' Y" F8 D - : E& ^- E2 X" E$ ~) }( L
- // 创建根实例
0 V8 k5 U3 m& t+ I - new Vue({% ]3 z4 X! [, V5 N! w+ a ?
- el: '#app',- @% x- U" q. g5 U
- components: {
( K/ i( O4 S3 C4 I - // <runoob> 将只在父模板可用" b: ~# \6 |- d9 e- K% G2 ]
- 'runoob': Child: N. D6 t2 R) w% }
- }
2 _# f% E- k. x* _2 }/ A8 |! D - })
' s, z4 x$ D K' U0 E - </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例3 J1 ^, N% I3 ?
- <div id="app">
% ?: ~6 I7 r8 ^7 r - <child message="hello!"></child>
. I! w6 l! s9 Z - </div>
8 Q; H1 H$ J7 C- z6 B, L - / c8 w. ~/ w0 x
- <script>9 w- m" e6 H9 z! T, _ J
- // 注册5 \6 {9 ?6 x; B' ^
- Vue.component('child', {
" u; W" ?4 m& I" s - // 声明 props
3 @' L8 J- ?$ k0 l" j& C+ e - props: ['message'],
& f) U! B3 y- h2 t - // 同样也可以在 vm 实例中像 "this.message" 这样使用# p& z3 y" T7 A4 g+ h3 i$ J
- template: '<span>{{ message }}</span>'
* @+ F4 O- s$ ~, Q9 T - })& {. w9 h/ F! S5 S+ }
- // 创建根实例
& D/ V: w; w W: m+ }0 h$ Y) K o - new Vue({
1 s. d2 b; e) ]' R A$ p$ G - el: '#app'
2 \2 J. t2 s8 ?" f1 O - })
d8 Q& X6 C+ ^3 G% s i - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例 i8 Z; I# r( f, R: T7 @+ d7 g9 J
- <div id="app">3 t9 a/ T( F& i6 c4 y" t
- <div>
4 X, k$ [! ~. \9 [9 s) s - <input v-model="parentMsg">6 y i- Z$ g$ K0 Q1 d1 _
- <br>( c2 d+ r2 b4 X# X9 P/ [( `
- <child v-bind:message="parentMsg"></child>
3 s' w' Z" t ~4 Y8 s" \ E - </div>: Q+ w: i, A- D% t( n- u% |
- </div>) f( p4 u$ |, I# n. ~) c! \
-
" [1 U' ^% v, D' `+ B" T: D) B - <script>
4 t3 E- a& a" u; u6 I. _/ y9 d - // 注册
( _% z5 |9 x! ~ - Vue.component('child', {1 w4 p; _3 {3 H, L% _* N
- // 声明 props
' O/ d* q* y1 {/ x# j' [' a - props: ['message'],
9 E7 Q( o& U6 O" `1 r: k - // 同样也可以在 vm 实例中像 "this.message" 这样使用, F X) Q5 L+ x& Y4 i
- template: '<span>{{ message }}</span>'" `' W: N: q3 n- s% F
- })
1 i) [. B) n o3 ?& y& X - // 创建根实例1 N# u8 L, w# g, u1 F( @- Z
- new Vue({
1 r4 A4 S/ v, c- K" n - el: '#app',
0 g# m5 ]! s$ d0 y* X) H: T - data: {
8 j/ x5 B; P; Z8 i* w' i8 k - parentMsg: '父组件内容': e X. n: l; W- x) Y2 l- O4 L
- }
4 I1 ?% b' k0 ~8 U# h) j& p - })
8 v: |3 r) ?/ L - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
( a5 Y; K/ D! Z, \: _& D' }- <div id="app">
+ _8 L9 p1 x1 u( g) X8 x - <ol>! P5 y4 X" d. \" L# J( O
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>2 F7 Q. v7 N# u8 F. r
- </ol>* `' a0 a+ I2 K% e* w" v. b, F( R- O9 d
- </div>
( z0 a6 P, t: [ -
+ _. j& o' x+ G: Q! z. f( D - <script>/ S( @! }& x! P1 C- {, r- @
- Vue.component('todo-item', {& p6 R! w+ R) O
- props: ['todo'],
" [6 |) \+ X4 m- o# n0 R+ q8 ^ - template: '<li>{{ todo.text }}</li>'5 | s( Z( n2 U( [2 W. R
- })
2 B1 r) U H- _# d0 |) E3 e - new Vue({0 G1 `" X$ @* C
- el: '#app',
; H+ }0 X. k z% q- p C - data: {
' k q7 N- v- j+ ?$ { - sites: [
1 s0 j- {- T: r( o+ d( z - { text: 'Runoob' },, s3 A6 Z8 c. z7 J3 [4 K3 k3 {
- { text: 'Google' },
/ H7 D9 C$ G% i7 U4 e, t/ n - { text: 'Taobao' }- l- `$ z0 [% ?/ X( U5 G
- ]# m v( H% X, A% K1 W) k7 H9 d
- }$ }0 \4 F$ {: Y- D
- })" @( S! F2 m$ i
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
1 J+ W8 p6 X0 T, b$ y6 r7 u - props: {
% M) ?7 L( ~0 P1 P - // 基础类型检测 (`null` 意思是任何类型都可以)
/ M" E! K p7 S1 e - propA: Number,
6 y% T7 t8 B) B& b) `2 U - // 多种类型
" j# X; T, ]- Y1 c - propB: [String, Number],% }" D1 ^7 t# ~2 F' z" Y
- // 必传且是字符串
( L! Y! l7 t1 b p- Z# v - propC: {5 i7 K1 A2 V9 U0 [. f2 J
- type: String,
0 x- u+ f$ n/ {/ ?+ W - required: true
+ b" r$ T& @5 @" y) i* {2 ~ - },0 ?$ x7 C0 M5 g6 F+ z. z0 a
- // 数字,有默认值+ M9 P2 W, X8 V9 @( V
- propD: {
! W3 r4 |: S0 D! @ - type: Number,
& P. J& r7 k; I6 i6 K" y - default: 100
], t% K6 h( f* K - },
, B5 {; W4 L( }( s - // 数组/对象的默认值应当由一个工厂函数返回
/ h+ c0 F& v1 X" i0 w: d) a2 ` - propE: {5 [2 F. I# x- s; d' ]1 ~
- type: Object,
: h3 ]; H1 f5 o - default: function () {
% L |' m( y; D' j% |! @8 L - return { message: 'hello' }
" b( h9 P! [: k% _$ p+ B$ g# K3 ] - }
0 s- k2 [0 k" W0 d+ \$ m3 z: W - },
/ k: U1 w( p H) ]9 B. {% G9 v - // 自定义验证函数
) M& R3 k: j% o- t* y2 E+ [( |. ^ - propF: {% M3 t$ m6 F V( f3 h/ b
- validator: function (value) {7 G Y% \4 a# T6 L0 d2 A2 X- O, a
- return value > 10) e/ ^7 F* J2 [" M5 a8 y
- }
' f, o0 `7 ]; J/ a" I0 i" K - }
3 H, A8 _" @$ F4 R, [ - }2 ]2 d( @) X7 ?& s2 i
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
# ~( j* e4 Z9 _% F6 [% c$ y$ A
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
8 R- W! n, a" D1 ], u
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例$ ~- i! s; E7 W4 I
- <div id="app">9 X4 \! }) q ^( Z& \2 m/ N
- <div id="counter-event-example">
) Y) n/ l% }1 ^, H8 H9 p' i* H - <p>{{ total }}</p>
$ b8 G5 E- d/ f J9 G- Z& n0 J: ]' } - <button-counter v-on:increment="incrementTotal"></button-counter>
+ H L/ h. Z1 I - <button-counter v-on:increment="incrementTotal"></button-counter>
# l, z, w) h; e$ F. C0 O - </div>
" ]2 c0 U; \' h! ^8 I: | - </div>
+ t- Z, m4 @+ g# P, D- ? - 2 Y! {+ ?; }' F( w8 \
- <script>
6 T. b# [5 U" h2 N4 t/ C - Vue.component('button-counter', {
/ w9 Y% K# a3 E$ x% L' p) a - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
* K6 W5 J. x, D - data: function () {1 a7 ?* X2 N( Y
- return {
/ b& B H: a' D' w! J - counter: 0; w! n* N* l6 U: [! j9 y# L3 y; u! A
- }' L# q1 D: {7 J* e
- },
- k, Z/ g/ {" E$ P# ?( j5 o1 U& A - methods: {" E3 o! m3 I8 S& o0 c
- incrementHandler: function () {
0 F8 `/ T2 f" I0 D - this.counter += 1
' a9 ]# r- m( x; s - this.$emit('increment')6 D9 R! f3 ]2 e, W5 V1 ^& [. _: r) k
- }
( D! A- V6 \- F - },7 g; q% R M3 e# k6 K- v; j
- })( v2 v! k* H% o
- new Vue({
4 M3 o( W; W; m+ R9 W! M0 x - el: '#counter-event-example',
/ s) k9 M7 W* N( C$ P8 T - data: {0 ^8 f7 Q( Z; R4 i, [8 `
- total: 0
: U* w4 E# o% `. H4 H3 b - },
8 H" K) S( x# s! }: z - methods: {# F' j0 ^+ K+ Z1 Y, [2 a: q3 P
- incrementTotal: function () {
2 \. v* S! J5 l# |4 \ - this.total += 1
- x6 i7 p& J. a - }$ J, \0 S5 M4 i# x
- }' x" O7 P. N/ f+ K! K/ M
- })- l# f: A ^4 @
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
2 C. l. G6 q5 c, C t0 e4 m2 t - Vue.component('child', {6 ~: G! y% U+ W; `- Q8 ?+ r
- // 声明 props
5 g* o' A X% n { `1 d l - props: ['message'],
. o! ]* ]; v' T4 E# _6 j - // 同样也可以在 vm 实例中像 "this.message" 这样使用
7 F3 c8 f [0 j T' @# J4 R - template: '<span>{{ message }}</span>'. R, s; b5 H5 S$ Y' H' |3 ?
- })- ?+ G; \& y) y$ o& c+ ]/ D S4 ` u
- // 创建根实例+ Q: Y% H1 Q; ~' b3 _. p
- new Vue({
& U9 [' R$ z/ I) X, s2 ~ - el: '#app',
5 i7 \0 H# {7 a/ A - data:{
u4 A1 Z* y' N; G6 y - message:"hello",
4 `' A/ \ A, C* P5 D3 v - }0 Q$ Y v; X, n' h7 n8 _& E
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {5 x. ~9 V- B+ D/ W& A; `, P
- incrementHandler: function (v) {
1 _7 |( |# [/ b0 y3 B - if(v==1){
3 b* K! ^9 N8 k* y# ^3 p+ B - this.counter -= 1
* S$ p2 ` @: }: ]; S9 c1 w5 R' D8 y - this.$emit('increment',[1])5 Q: i+ g) z/ w w' C8 z0 l& Y
- }else{: k2 C+ M0 F0 I A+ q- X( X ]
- this.counter += 1% x, W6 m( v" V; y2 v
- this.$emit('increment',[2])
! ~+ s# l6 v( b$ T( h - }! V% t9 ]1 _$ ~/ S
- }
$ N% H9 I+ I; K* m - }
复制代码
0 S0 {" \9 D! ~
" X$ p: _% s$ A% } |