组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它: & k% E+ ^& b! f, M( m. [
- <div id="app">" V/ z/ D; A) @8 d; K7 m6 f
- <runoob></runoob>, B w; @* s' r9 L9 L" o5 y
- </div>2 K- K1 g, k9 ^9 k8 F: ^4 U
- " f8 w- R# S* O2 I) V1 x6 }
- <script>% Z7 P) ^4 j7 i3 `" i
- // 注册
6 r, P, V! c7 ~3 E" v - Vue.component('runoob', {& j3 x1 V5 ^2 A. i0 O
- template: '<h1>自定义组件!</h1>'
/ {2 W! L5 P& z; S4 s4 l7 n2 o6 O - })# n* \ q8 t8 \, L# C* K7 s2 X' Q
- // 创建根实例. K7 g' C! O/ ~* v' O) G) U. w
- new Vue({5 }- c! I8 D, [7 r! W
- el: '#app') w4 s: h! X9 ^/ r" c: j, ]: I
- })9 g: f9 k+ j) o# n6 z. }. |
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它:
" K7 m; n- ?# V7 C$ f9 i- <div id="app">- o( K. p! J) b* W
- <runoob></runoob>' c; c8 D5 W$ i/ }7 I% W
- </div>
2 L$ j" Y g3 d - ' W" d" i- d6 \$ M" E
- <script>
% ?) i' {% ]. p4 ] - var Child = {9 c9 |( z7 K# G. X
- template: '<h1>自定义组件!</h1>'
5 [9 M3 q9 Q7 ^# G - }. {" F" ?2 O U; c9 V
-
3 `6 M% j& N( @! C: V. o* Q8 i7 i - // 创建根实例
; [4 ~( |4 D6 D- W- g `8 G; G - new Vue({% z1 c, T: d6 [
- el: '#app',
* r* ]% `" z3 y - components: {
3 _1 n- q2 _/ V, n J& E& }/ a - // <runoob> 将只在父模板可用( e: n) y6 U0 f* p0 G$ v: b
- 'runoob': Child
/ D* l1 k% @9 j - }- W& _- D( W. {* C, n) O3 Z7 ]
- })" l9 K1 S+ ^" B: W+ z9 {
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例
+ F# K% \6 {; d. V/ l- <div id="app">; D& ] a E4 f. s" t9 [- Q* x
- <child message="hello!"></child>% A& b7 z9 x$ n' T: ? K" ]
- </div>
9 {) h/ J5 S/ U3 u9 A; G; [ - # ^% s6 g1 E7 M9 p3 O, ^. A3 t
- <script>1 M+ {! Q. Y2 d X. ?4 E# c
- // 注册
, o: s; \, }& h5 @ V7 Q3 M' D) O - Vue.component('child', {6 m# W. Y/ k$ N4 C; r- J, w
- // 声明 props
1 x+ r( D1 O7 g$ k5 s/ x - props: ['message'],
# _) ^& y' Q8 v! o# w0 M - // 同样也可以在 vm 实例中像 "this.message" 这样使用( _, g( R1 H1 w7 V+ z! j
- template: '<span>{{ message }}</span>'3 e# ^" h( |/ p+ A0 h; u6 g2 y
- })& z9 V7 ~7 |+ N# j- `$ N
- // 创建根实例) }' a! B2 E* n% k
- new Vue({# I$ b3 _- \/ w" ^- n
- el: '#app'2 M1 @- }& V1 b& S: V
- })) J, r' t- m/ u; Z0 p4 h2 N
- </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例3 {* c" s+ @% ^$ S1 b, T5 [
- <div id="app">
0 \7 X; R' u( S0 |7 K0 R - <div>1 w$ |' n" O7 Q( j5 R$ S1 D( P
- <input v-model="parentMsg">
2 ]: e" w# d# X) l+ z2 c1 m& d - <br>9 l/ [' ?$ r2 @- Q3 s3 A, ~/ D0 M
- <child v-bind:message="parentMsg"></child>
( z. w9 i, [0 e4 b. |* D# L. d% r - </div>$ c0 F* _/ f* t: g7 d1 K& V
- </div>4 y; i+ s' X" c! F9 I/ `
- / S( j5 r' V4 W9 n) b
- <script>0 a l& I) X% W
- // 注册
* A0 ?+ A" j3 t& z; J - Vue.component('child', {
* Z- ~) e% n% r+ e - // 声明 props% u' W3 X) V" m- X5 k! Y
- props: ['message'],7 w/ J+ _- p3 K- }5 b) v6 ^1 m( m
- // 同样也可以在 vm 实例中像 "this.message" 这样使用9 |$ B4 J0 X7 v$ |
- template: '<span>{{ message }}</span>'
9 k$ g* _7 \1 O' | - })6 {* s5 s6 Y0 l! @. x2 _
- // 创建根实例
( o% w0 @+ g0 @9 G6 C9 r- U - new Vue({. [$ B$ S' J# e+ t' L' X" n" N
- el: '#app',
- K& N/ E0 R4 ]" t - data: {
: L o2 }# }& Y% E2 D% r- ? - parentMsg: '父组件内容'
# W- W5 t2 u/ [# I p% `5 } - }
% o4 x4 P! x" T+ Y" k - })) R7 [/ ~* ~8 G6 n7 M4 V% \
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
2 t1 P; }# k; C% |1 Q' B, v& U, P4 s- <div id="app">' h$ i6 h# P# l* O8 L9 f) a
- <ol>8 i4 f: }, B( ]" Y
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
% E" t, L& K& R6 J' ~" ?! H - </ol>
! K% [$ s! D6 Q! _ - </div>5 h. G! b, {3 P
- 4 u/ Q6 ~4 B6 @3 {, _, `
- <script># n4 q5 q# Q, x6 U w" ]4 {
- Vue.component('todo-item', {& d. O& T2 K& C) _9 A+ J4 C7 \
- props: ['todo'],& h/ c$ k2 m: N) M i4 v" a
- template: '<li>{{ todo.text }}</li>'# h) p! z4 {& o3 {# K4 Y
- })
* u7 ?4 ~6 j X$ e* [* d - new Vue({4 I+ r3 U( V: d: E4 Y" p
- el: '#app',5 ^3 R! k" u1 g% z8 z. C' X
- data: {
d# Q" Y0 o4 l& G" I* [; A - sites: [# Z- l7 _0 t" l7 n2 Z1 j8 ^/ X
- { text: 'Runoob' },
% ~ E' y8 K/ x# |3 E6 f - { text: 'Google' },
6 R/ E, @% t; q* q) @6 S& u' e - { text: 'Taobao' }
% q. w/ P, j; v+ V7 P; V* `5 w - ]
2 u" v6 J$ y q) O - }" P; Z8 {/ M* Q9 f& ?$ I# f
- })
# r7 Z% c2 y B) |8 X$ Q - </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {, o8 R. d7 X% w( y7 ?$ M
- props: {
( h/ v- n# ^$ | `9 F - // 基础类型检测 (`null` 意思是任何类型都可以)
) ]' n* ?. N+ ] - propA: Number,
9 |4 y# x7 f2 d8 ?3 x - // 多种类型5 @- q7 P9 n# R5 T
- propB: [String, Number],
" s" y* i8 M9 J- L* C& T3 u - // 必传且是字符串) N, a/ X8 _" v3 w/ {
- propC: {
6 Q3 T3 K: Z$ ?9 Q4 ` - type: String,
1 H! q9 g2 r- x2 I6 ~8 E7 r - required: true
+ E) y, S# [& v! d0 R- ~ - },: c2 N! d( {0 s% a4 \
- // 数字,有默认值
4 ^) }5 T Z2 G: Q) W - propD: {
# J- N- Q% z+ H - type: Number,. w; T0 N1 d0 b0 F- N$ R/ n0 U0 m
- default: 100& L7 [4 P4 F6 u% o& g, o' ?
- },8 v3 X9 ]/ ?# s2 h5 ~( h
- // 数组/对象的默认值应当由一个工厂函数返回- N2 j+ g- K# B. w& {4 \7 x* J
- propE: {7 d1 P5 t! g: f1 B) a P/ t
- type: Object,! z. e3 ?# r; b3 Y, v! ? T9 B
- default: function () {5 ?/ T6 ?5 j/ m. `- ~( ? U) x
- return { message: 'hello' }1 W+ D% X1 k; d) |# E
- }+ J t, I9 N/ U* p( k. I6 f3 [
- },5 p( b6 Q1 _2 {% r, ^4 Q# W6 N& U
- // 自定义验证函数: J# z; O, ?7 E6 P% ^" H
- propF: {& V ]' n/ E2 g+ _; x( o. i* k
- validator: function (value) {# Q$ Y9 ]2 x# b- b; u# {6 ` Z
- return value > 102 f$ m4 f+ G5 ]: a5 e+ B
- }
. X% T4 e" Y' b+ S - }
1 }/ Y* o1 o0 Y+ q R2 P' B/ A - }0 a+ n0 ~) _; y- B9 e1 X
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
$ q+ U+ r6 @6 w' x5 Q( l
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
3 I j' l2 t% u: G( { A
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例
# z- s: W+ e" m7 F; K$ ]6 y$ K- <div id="app">. ^+ |3 {5 o L6 [7 E1 h
- <div id="counter-event-example">
0 v' c7 g0 m3 V% y) M# \7 q - <p>{{ total }}</p>
7 V3 n- a& O5 H5 O1 c9 ~ - <button-counter v-on:increment="incrementTotal"></button-counter>
4 T: u! E& F: d" J4 W - <button-counter v-on:increment="incrementTotal"></button-counter>
& n) m+ }" E) x- H- V4 ` - </div>) k3 t: }, S( F, ?
- </div>
; B# y, r, W2 R/ V5 t# q - # y1 W9 w' Q5 K. y/ F' Z1 W( Y
- <script>
) S! U! ^- B# T - Vue.component('button-counter', {0 L, R# y5 {: F, a
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
* m O/ M6 l6 \; {& o - data: function () {
. u+ K. g0 g% M9 B - return {# k1 R/ L4 i% ]* N6 N% I
- counter: 09 @1 K3 R2 W* K* L4 ]) J
- }* `$ @3 o2 U- I* T2 h. x0 J7 ~ T$ E$ o
- }," I8 j. z4 S4 |3 K% U
- methods: {
$ m' _/ ^7 F0 S' n+ |4 R& d T" { - incrementHandler: function () {
9 h3 O/ f( r8 m - this.counter += 1& |9 t7 S* z/ X9 k! S
- this.$emit('increment')
4 V: n" P, u/ ~7 H- Q - }
: S' m0 s( ?3 y5 [7 X - },
: |3 T3 L' ?0 t7 y - }), [6 |/ J' U5 P3 ~7 ?% r% T
- new Vue({
{8 r B6 P/ [ - el: '#counter-event-example',
, |6 H; @( v) e& I! {' S - data: {+ t8 F4 y% M$ T7 J& I
- total: 0
3 X4 r" d9 G5 X/ N3 d - },/ l9 n& K% U; F, D
- methods: {
" U# `& z$ [+ C - incrementTotal: function () {
5 r$ D: a* s4 f/ }% R& D2 P& d - this.total += 1
$ W) G) [, U: ^" e - }
! R# u1 w9 Z5 n) W - }& N& X+ j" S; t" h% a. k
- })
1 u2 h- O7 U4 H% W7 Z" ]2 ^ - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
4 a% I1 C& Z# w [" }/ x! s - Vue.component('child', {. M5 I }' q- L1 s; d. ^: |' b; D
- // 声明 props' A& ^1 ^4 y6 B* U- E4 G
- props: ['message'],; G# m0 z6 j, z; [
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
/ b* p8 V5 B5 `4 [ - template: '<span>{{ message }}</span>'
n# D# b- s: n8 d/ i2 p) L8 { - }). F2 J! p4 G1 p6 S
- // 创建根实例4 \, r% o Z% B, A" |8 e
- new Vue({
' c& E# {% b, L/ A* S - el: '#app',! k" M9 m* h* ^: r) v
- data:{
8 l, Z, W0 S* Q# [( r4 ^ - message:"hello",
% M! s) U+ q$ W ?4 l - }- V! k' _2 D5 h% x
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
0 [( M6 u' l. F0 c - incrementHandler: function (v) {: w' N( d2 x( z
- if(v==1){; V1 c9 w0 V. ^
- this.counter -= 16 d8 L0 f2 S( C- m
- this.$emit('increment',[1]), _' ?8 x, ^2 \$ ^& l
- }else{) D* ~# a8 H$ W
- this.counter += 1
( n3 w0 \' \ F# Q5 C5 J - this.$emit('increment',[2])- d6 W/ ~* X5 D5 j) J+ G4 |/ E- q2 }5 B- @
- }
+ _, D5 B( [9 y7 g( B+ v9 t - }6 W; n& T, U" H+ v3 u
- }
复制代码 : U; Y3 r" Q, l% J. M. ]+ I
# m( m% Z ^2 T7 J/ J |