组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
2 v# v& _* B8 l0 R$ O5 e- <div id="app">
8 C; R/ [ D1 e# C4 o9 ]+ K - <runoob></runoob>
# v6 d3 i+ G- ?( ? - </div> g6 T, W! T: b @( c% R
-
' Y, l" p/ O, e# o5 T% m9 p - <script> R. h; D% ~8 `* q, X# H0 P
- // 注册; p3 O' \( I, `- `2 R% o- R
- Vue.component('runoob', {$ K: ?2 ]6 h' P, |9 ~2 o* `
- template: '<h1>自定义组件!</h1>'+ y/ w! B) g7 v9 j
- })
( A* S1 E4 X7 U- T0 k - // 创建根实例
4 ^- H* z1 ]8 {, o& z - new Vue({6 m/ w( m1 e9 E5 _2 }
- el: '#app'
& D3 ]/ h& ] d9 ^. D! q' b( V! I - })
2 ~+ S( }# e! C7 g- r4 q9 l - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: 9 [( P$ J; |" F6 r5 V5 @- F
- <div id="app">' ^: ~) @* t8 a4 E
- <runoob></runoob>( i, B7 R; E% X" W1 S% L
- </div>9 m4 `6 G9 _8 b, w7 M9 U; e6 Y/ U
-
$ C6 B+ V9 _5 f6 |1 B! _ t - <script>
* x% {5 |' e$ f$ U* Z - var Child = {) R. J# f: u z1 S1 B
- template: '<h1>自定义组件!</h1>'
v% J0 C5 A; C1 b0 X - }
- c W& v" o5 V( s$ B - 0 _$ R1 z# f4 J8 Y" q/ w
- // 创建根实例0 O; e# q- l, g1 v" P
- new Vue({
" ]. \. F* s. U- M% d - el: '#app',
9 o$ e$ M( e% `$ N - components: {
7 `8 O) K5 x6 m1 H- s - // <runoob> 将只在父模板可用* k8 ]0 M$ @9 G4 j
- 'runoob': Child. t. p, B/ n' G, t7 ^' M9 T( ^
- }( |7 U' u$ p0 D' `8 e% q
- })
0 O* Y# h9 }! ?+ p$ l - </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例! g* t% _9 `3 i' A% A! ^ y* j6 `
- <div id="app">
9 e2 t% U) A( n9 y - <child message="hello!"></child>
% d& Z q* U' W) E3 N: k - </div>
! e7 \1 y% N% i' R, f - 1 Q/ U1 @8 o6 E' a' d& Y
- <script>: T7 W+ z2 e9 P- r; S1 ^* p! z, N
- // 注册
# X5 g! ]$ p$ F8 U/ x; Y5 o - Vue.component('child', {
! z' b- J4 G9 _# x/ E4 I - // 声明 props
" Z5 a ^" Q* ~9 O$ e$ J - props: ['message'],7 w" w# b; p1 E. U9 k0 {; O2 e' K2 _
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
! B9 N/ M8 R% ^ P: C) N) v4 k2 F - template: '<span>{{ message }}</span>'
( s+ Q+ p1 v, j: [8 k/ S7 B; J - })
: O$ k C8 A$ t; I - // 创建根实例
& O9 B0 q7 H1 c- }6 ]4 Z - new Vue({$ U2 L" d0 W. _# @# ^( b& `
- el: '#app'
4 f% ?7 w8 l1 H! K: W - }) f" e/ w! O0 n5 C( i
- </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
. ~% k1 F0 ~% ?, ^; S2 d+ Y1 ?- <div id="app">7 a$ c! N$ j9 G3 L4 h* n V! a
- <div>
& w/ W+ ~1 e% {; @; [! N* ?0 A - <input v-model="parentMsg">
/ o" F8 W u; q! c) m3 P0 x, c% E - <br>
! o' O( S8 F. k4 [ - <child v-bind:message="parentMsg"></child>
" X7 b( n c& Q% q# ?2 [- R& N - </div>8 s1 m/ u: u& G- I4 M8 Z5 H
- </div>5 K& |! Q/ ~: o. P' B$ ?# d- u0 b l7 \
-
# T9 B. z- Z/ z% p* c' f6 T* K- F - <script>+ W; t0 o; U& O: C, ]; Y- n5 f
- // 注册8 n0 @" Q8 B) y' q: Z+ @
- Vue.component('child', {
( D' B1 C% P0 D5 } - // 声明 props
) u# t3 g6 q- A3 E0 ` - props: ['message'],
5 x! L! H) y3 g7 Z, @3 h8 P2 k - // 同样也可以在 vm 实例中像 "this.message" 这样使用* T9 v# n$ m! q) u
- template: '<span>{{ message }}</span>'( e7 C$ V8 a O- O
- })
9 g, g* ?' m2 z- X: u0 M - // 创建根实例3 t- f: g$ D7 r# ~: G' E' ]8 d
- new Vue({
& |( @6 b; p& @3 U* g) | - el: '#app',
, Q( \7 I8 F) J7 D5 L# J - data: {
& f6 l d& R% e; \- Q - parentMsg: '父组件内容'
% r7 P- V" q6 N, k6 `; P9 Z9 z - }
4 F* ^6 d5 I! P8 a% N1 C - })7 {8 A0 C- G& \$ X
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例: `9 P0 R5 W% R* x6 E1 @" C$ X% Q
- <div id="app">! }2 I7 \3 |" K9 H0 b
- <ol>6 F9 i( C ^. B2 c, D# e2 I, z
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
, E3 b9 U D6 H1 v; v. t6 v: t - </ol>: Y) }* t. R, d- e z
- </div>
( s. Z" S9 X n- b0 m/ S- y4 H - , m1 S5 R6 L6 o: v S
- <script>
: ]! F% z: [8 x6 h2 ], a7 _$ a - Vue.component('todo-item', {
" G3 D3 v/ M8 i# R - props: ['todo'],
0 p4 {" m7 ]5 V! J6 M - template: '<li>{{ todo.text }}</li>' H0 y7 W7 T- ? ^% n
- })
~3 P$ l: n- J: }& f - new Vue({& t6 s1 Q+ K7 b! H4 W! g
- el: '#app',! ?% l( E3 H" N# Y' a; q
- data: {2 V! E2 A# `3 m; i0 _. c
- sites: [
$ O" i; q$ C2 i5 y" ` - { text: 'Runoob' },
, t% n$ G* j7 I1 o2 [( E8 R$ d - { text: 'Google' },
$ _* c' ?8 h4 g5 f. n! o3 y/ M6 c - { text: 'Taobao' }& N6 c& r* _$ P1 i
- ]$ e; ^( r0 _) T" Y2 j
- }
, X9 t0 ]2 d4 R' L w7 x6 d( P# C - })
$ F: k1 I, J& L - </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {7 L; d2 H' z7 V1 f& V
- props: {
5 Y( s) c/ `" z, R( N6 B: F' A0 b - // 基础类型检测 (`null` 意思是任何类型都可以)
! b4 a6 @9 G m" g# o/ D - propA: Number,
, e g6 }7 g( K& O/ x4 O - // 多种类型1 j0 y5 C: h0 ^; ^2 o; M! }2 N
- propB: [String, Number],
0 s5 N; U+ n5 P - // 必传且是字符串
7 c+ p. C- e' `' |; s! q - propC: {
( O+ Y) T" C# d3 L1 d2 S% e - type: String,
+ c$ o* q5 w( ? - required: true
Q0 [% M5 ~6 n% m - },4 q8 O) g& T6 ^9 b
- // 数字,有默认值! R: c* }) M" {0 @ h, j4 i; M
- propD: {
9 A, q4 ]' Z7 g/ Z! } - type: Number,: j1 C# |9 E1 F6 m4 _! ]
- default: 100
9 x: l# _/ N9 p; G, P* h4 W$ a - },. ^$ c% ~* i/ m5 p6 B
- // 数组/对象的默认值应当由一个工厂函数返回
+ j. A; x& h- H9 G - propE: {
9 h, A* ~: e: v2 a0 }4 {* a - type: Object,
! i8 [' y- E0 B: _5 P8 d' t - default: function () {, S9 }4 _) A. v) ^. G% g6 a
- return { message: 'hello' }
& I) z- k6 T* g" L+ l - }) ~* a# d2 ~7 a# G' w( @- a
- },5 q( @1 _. ^8 z9 v% P! c
- // 自定义验证函数/ `' h3 T4 S2 ~7 {, a& \
- propF: {3 V+ ? N5 d+ n+ S% z; j) `- t$ B1 f, C! s
- validator: function (value) {
5 Z8 ^3 e% ^1 G4 x. E! i - return value > 10
7 p$ {/ ?3 X) @( [ - }
$ N9 }( ?! F4 G; i* c: T - }
# l5 d4 ~/ |! v5 W( I - }2 o, K& E4 Z1 i8 {
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array. l( I& B( E1 H- c; n
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件7 \5 ~9 y0 j4 `
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例4 y0 g- m$ G. a$ }
- <div id="app">: N$ x4 H" B3 {6 l+ g* w: _, G
- <div id="counter-event-example">
! b y0 Q& N3 @ - <p>{{ total }}</p>/ h# c4 k, b% Z
- <button-counter v-on:increment="incrementTotal"></button-counter>5 t5 R; C7 [6 q2 O8 C9 E
- <button-counter v-on:increment="incrementTotal"></button-counter>1 s) W: f) B1 Z, Z# k8 _
- </div>
8 ]: k/ ]# C( w! [ p - </div>) a7 i' @) o& ]) b* s
-
) f$ F4 J9 g8 ^* s% ] - <script>% c5 f! ?1 u+ W' Z
- Vue.component('button-counter', {0 `8 O8 z/ C% g: P q4 t
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>',, g3 ^! j: v! y+ C4 t; s- J |
- data: function () {
9 K' M' \7 y" K( x3 G - return {
% x6 m4 m9 R% O6 t8 s/ J. A9 a. _ - counter: 0
2 Y: d5 H! R5 e- d: { G - }
; q( {2 _0 @7 A/ T$ D+ T - },1 l( R' {5 ^9 Z; L+ I; ~3 d
- methods: {# D- O4 n/ ]4 V8 z% d9 l5 [. f
- incrementHandler: function () {
* v; o8 Z4 {: i) m- U a# s - this.counter += 1
% Z- a9 [0 I% D" @+ C# e - this.$emit('increment')
2 ^! D) R1 N5 }) s6 O, z8 d/ B - }- Z- o2 L( g) n+ q& ]5 k; ]( x
- },9 f* [- s8 p; Y* Z; K+ X
- })6 Q s# e8 O8 q3 _% e# E. m
- new Vue({
' t {8 y4 W+ o - el: '#counter-event-example',
0 L) X8 H6 {+ o& s2 ^ - data: {
@/ N2 ~3 ?+ J" i7 Q3 d - total: 02 I& t/ }9 g0 g b- V( r: m8 ^& t
- },
7 d9 z2 H' B" H% M- h - methods: {
1 p9 u* y; b- N; e! { - incrementTotal: function () {- z9 ~9 n1 Z- r: b1 ]( K, S: Y
- this.total += 1; v; F, i. V4 b# s' k
- }
% J. _% g* }9 |; j' ~3 r' U9 ^ - }2 [7 O6 m+ B V; K8 e
- })* H; ]7 p/ L' a5 S) R' T8 u
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册- D0 k3 j8 l4 w
- Vue.component('child', {
; y1 \) m+ A# o1 l - // 声明 props% V# ]3 D( m+ ?' S
- props: ['message'],
8 ^' ]: q0 V5 o# {' } - // 同样也可以在 vm 实例中像 "this.message" 这样使用# F% t9 [- f( ], z% \
- template: '<span>{{ message }}</span>'$ ?! x2 o, B3 w4 d5 @# p' m
- })% c; x% D! C# g! k7 o8 }
- // 创建根实例& Z( o8 N5 [$ `
- new Vue({
2 d2 o4 q$ ]" w/ F6 E# ^- V - el: '#app',
) ` ~/ ^/ ?3 n a* }! c) N - data:{9 k6 m1 i5 f& m; V
- message:"hello",
. y1 L2 h5 t1 ^2 n - }
6 J( z- C t7 ? - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
& P' x& W# x" s7 H+ E$ t' k - incrementHandler: function (v) {8 u+ I6 d( Z# S. m4 h
- if(v==1){
; i7 {, b: N8 g9 D - this.counter -= 1
5 n$ ?1 P0 |3 ^- `0 Q" M - this.$emit('increment',[1])
2 @' W; Z' f8 e' s- F) l" b - }else{0 R/ Q- |8 m/ r: B: s
- this.counter += 1
8 m' I) m9 l9 D) T* D& C' A - this.$emit('increment',[2])
3 X' Z$ g& x& V: Y- X - }+ d& Q3 y- z( J* x
- }
- I. {/ b( T, U* | - }
复制代码 ( W6 \/ C; m" Z0 o: Z5 I7 e
) l2 ?3 [3 a0 H- O x7 z
|