|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它: 3 Y$ t3 Z. X" u! v( j' L) d
- <div id="app">
0 y3 C" y* b2 y4 g - <runoob></runoob>
9 W/ ? v9 F e) v) {+ i9 N" v; P - </div>$ A4 G0 @. z0 k7 ]1 W/ o/ q4 g
-
4 q! J! x5 A! ], i - <script>& N- [# o$ k7 w& B! N, R$ r) @
- // 注册 g2 ~6 j, ?2 ?( a! C f
- Vue.component('runoob', {
4 |. _+ {/ K* o) v C - template: '<h1>自定义组件!</h1>') e1 j3 s* {- {2 P% g% l- {; L
- })
6 F. ]2 d& @8 h7 V; `' r# N" ? - // 创建根实例& x `# D6 I" s3 z$ {! M. K# {, H# h/ ?
- new Vue({
7 R8 O% u' ~5 x& B0 @$ W" | - el: '#app'
5 w; a7 D) }7 k: t+ s$ a - })
k/ k M) @3 u! f$ r - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: 3 r- Z8 r2 u* M& c
- <div id="app">
, b [+ B. [! P$ I - <runoob></runoob>
1 p( K% F2 O8 u& [6 z9 z( V% C - </div>0 X( Z, q' ^0 }( S
-
5 Y, }- Z7 }/ `* H+ y1 \' m! x - <script>
) S" j% {! a* y% V) o - var Child = {
7 I! G& O; ` K% ? - template: '<h1>自定义组件!</h1>'
! F) |3 P v# f, ^/ J - }* z) M2 K: z L0 h* q5 w
- " ^! o2 _2 Z) o3 y) K- d o4 t" |
- // 创建根实例* p# q' X" l$ c8 I y
- new Vue({
) {2 f9 d1 {6 C$ N7 r* h: R - el: '#app',
) C" U- u" Y# @3 p - components: {
0 F/ P, m# V5 c* r" M - // <runoob> 将只在父模板可用' }! f8 W0 u, D2 q9 C* {
- 'runoob': Child! _6 _4 [: F3 F) G# {& r/ ]4 ?
- }* U% _* `; T1 ~
- })
) j, |! P% Y5 V* `% ~! ^ - </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例0 B* ]. W$ R. u* \) C# J
- <div id="app">; @6 ^0 }; ]! r* l9 Q
- <child message="hello!"></child>! S" J' ~+ B/ ^3 X: z
- </div>
8 T9 M. X& e, e6 q' m+ n -
& @' v) O" E0 |% P/ D - <script>
! A/ y) U$ J% X0 ^! _ - // 注册
; B2 B) ^, i1 J Q - Vue.component('child', {1 M" C2 K/ ?* X, @
- // 声明 props
3 R4 F% ]. a" B5 E3 v - props: ['message'],/ }' t! m9 G* `7 d c0 i2 [
- // 同样也可以在 vm 实例中像 "this.message" 这样使用6 ? ]* [0 a/ u+ o k& }
- template: '<span>{{ message }}</span>'5 W7 P) f" U3 o( ]$ |+ q8 [! H2 p0 i
- })
; F- z [( X) ^ I5 A - // 创建根实例
7 b! U, [- f5 s4 p4 Z4 \# Z4 n - new Vue({; B! j+ ^( E: V1 R1 K7 @
- el: '#app'
D; W, \; S7 w8 V6 ?6 `/ L6 [ - })
9 ?/ F4 L; ^! z8 n: [7 h - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
4 y6 h, u# c* X! t& n9 T5 E- <div id="app">6 l& V2 E4 x! e1 o U
- <div>/ G& W. I% @3 ?" z
- <input v-model="parentMsg">( r! B( z# s( u( }4 m( K
- <br>+ ~+ e2 l7 [/ q$ I; s3 z6 T
- <child v-bind:message="parentMsg"></child>) {; q D5 x; ]* Z( Y
- </div>
5 ^7 O' W6 D9 D4 Q9 ^" g7 ?9 b2 ~ - </div>+ y% w# s+ A n" O
-
3 u3 ~ M" }9 T - <script>9 \6 |: [1 J6 p# k3 n% D7 \& s
- // 注册
2 ?2 a6 L! w7 h' O1 x. h8 `' _4 v$ f - Vue.component('child', {; e; S! Y: t- s& I! ~+ ^. a) K
- // 声明 props( `; E }! c& ?
- props: ['message'],
& i6 y; D0 Q% j' q C. a - // 同样也可以在 vm 实例中像 "this.message" 这样使用8 F; R+ ^4 J( {0 X7 H3 Z! ^6 b
- template: '<span>{{ message }}</span>'
3 L7 O# @8 r' b. ]% W" z6 z - })
0 E& Z/ s& c$ O# c3 O - // 创建根实例/ }7 S+ g; u, I* Y- @4 q/ _9 J
- new Vue({( F. M0 ?5 }; T$ W t
- el: '#app',% {1 K- V' g: B3 \: V/ {0 d1 L
- data: {+ n M! J$ U: n) n
- parentMsg: '父组件内容'
3 g) k0 t% v5 m. W( r+ E P$ @3 { - }$ t+ x; Q% ]' G* K/ W- p
- })7 _. m$ v) l2 c0 s+ j* Y
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
) S a, _4 q" A5 c0 `9 h+ {- <div id="app">
5 e; o/ @6 S$ l1 j2 ~ - <ol>
. ]- l% m: q1 j, V" \( u, {; @! D - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>8 a: V2 X% W. U6 W9 y+ R
- </ol>
4 @& p) L n* u' S$ W: n3 X! n - </div>- e% n: V3 @$ N8 p# I. _5 D7 l% ]: Q
-
5 ?' N5 }( l0 ~! Z, [ - <script>& l" s/ I8 i" R! z: N
- Vue.component('todo-item', {2 g: c( z. }% R$ r0 C
- props: ['todo'],9 f4 b1 J( U6 q# F; H1 L
- template: '<li>{{ todo.text }}</li>'
3 B S' ^7 {) ^- ~: \ - })
7 X5 p6 q7 d: `7 s# ~' ?7 r, } - new Vue({
4 m( a+ F* U5 g) P7 X6 q( f$ \+ R+ X - el: '#app',+ m& L! ^/ Z, _% }
- data: {
8 u4 D8 W! c( g# L - sites: [. J; v, N, b# l2 D; P
- { text: 'Runoob' },, W0 `1 }+ P. M
- { text: 'Google' },
( r5 ~7 k; f7 K# j - { text: 'Taobao' }
& C% t m `! Q - ]
3 U" L. _5 n- X9 R1 | - }6 q; {* K/ _% ~9 K% j" V
- })
. _1 y7 S" y5 d) ]. P. S: A6 d - </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {- t# T% E& x d6 x7 m9 b' W7 E a% ^
- props: {+ e4 q4 R `, e& O0 m6 O( h
- // 基础类型检测 (`null` 意思是任何类型都可以)
) N* E+ [& O3 f8 ?: g. c, b - propA: Number,3 n+ ?7 o; E# R% n
- // 多种类型# N7 A3 X( P! P* e* {& l& `
- propB: [String, Number],
$ s/ h5 o ^8 _, A, i - // 必传且是字符串
6 Z; A% G/ x% A - propC: {+ B- J+ a# J R1 K
- type: String,
0 {, B7 p+ G) ?4 s - required: true3 |9 ]5 N* ^! I" e. b
- },
) |4 X+ @& l+ x( ]4 p - // 数字,有默认值
# A$ l# o! V# X q - propD: {
4 h9 h4 e$ x1 _: n- n - type: Number,
' `; u2 ?) V; `8 ^' | - default: 100" j! R9 w6 Z/ g" B' m) r3 u3 A% |
- },8 L$ ]& p% i# I9 Y
- // 数组/对象的默认值应当由一个工厂函数返回
& q" L* H9 {5 ~" ^. b% i1 \ - propE: {; U# ~- F4 R' G6 O# g
- type: Object,
- _% N- X! K! x - default: function () {! f# [- q$ r0 ^* I
- return { message: 'hello' }
- h& }# e2 j& E$ ] - }! R3 C& \% K2 f
- },2 M; e5 p2 Y! R5 f ^; R
- // 自定义验证函数' P8 F) O9 \1 T4 |" V; V3 e3 U: i4 {
- propF: {
: _$ X) ~" k+ Q& z8 N4 V( J - validator: function (value) {! C" O M) b8 [4 Z5 ^5 Z1 D- h
- return value > 10
# S7 z0 L$ D6 Q& Q2 i - }* E9 y& l- c h6 d5 R
- }
( d/ d* G5 g1 m) K! ?1 ` - }5 r; P* h- L$ |+ e
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array, j S4 ~* l/ m. a7 u0 r
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件8 |$ ~5 c& j( P& i4 g, d- R
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例
/ u0 s' o; l. x- <div id="app">
' z. Z( u+ T6 M( U: h4 S: U - <div id="counter-event-example">
) ]4 U& U, s+ u O - <p>{{ total }}</p>
* v; z: A, Q. `* P+ l# R" d - <button-counter v-on:increment="incrementTotal"></button-counter>8 m5 A# s: [$ c" z
- <button-counter v-on:increment="incrementTotal"></button-counter># F" q# o! \- b3 M* U, H
- </div>
! H2 [* o/ {# n% C: X6 D O! B+ @; u5 I - </div>
4 Z7 h6 o8 r- _8 k ?" s1 F8 ?1 M -
2 g+ w! o& `+ f - <script>
* w5 P4 T. `4 ~5 k) A7 N I! m - Vue.component('button-counter', {8 g8 t3 _+ X9 E0 K- L2 b6 C
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
6 L) L4 R3 @3 s - data: function () {0 U8 w. G0 w, S, M/ C: Q
- return {* x5 S* J% d# |5 X& r7 X
- counter: 00 M* y% G# {% p2 |+ j4 B* K5 ~/ t, N
- }; I7 ^$ C1 c/ A6 I3 ` w
- },) Z1 t3 n7 P5 t0 @2 K4 ^+ J# @
- methods: {
5 ^; r' ^7 U/ [1 C4 N$ G - incrementHandler: function () { r8 J7 X- F- J* X$ |5 N
- this.counter += 1: B1 R9 l2 H. y, ?! A. O0 _
- this.$emit('increment')* C, k5 E7 m W F
- }' l! k5 q7 m: |, t/ A, v, K
- },
. o) ~" X! Y4 O' U9 j/ c* o - })' T+ `6 a* O. v
- new Vue({
# v# y8 H( k6 L7 Q$ p - el: '#counter-event-example',
- e1 R$ A% N1 K b - data: {
, S$ Z+ H( r6 |) R0 o( i - total: 0% x# ^/ e& [$ N& S3 N8 x! z
- },
( y8 m5 w0 r0 y, `; w4 b0 h - methods: {
: v, b7 h+ m, w3 h! z* ~" h6 H5 w( {' p - incrementTotal: function () {
4 A3 R" D7 a/ |8 v - this.total += 1; m M$ c D* @+ ^
- }
$ V5 @5 F( J+ B9 O - }
I& m; i; l0 K6 y, [7 t- Q - })
, ^( k, f8 x9 U4 V2 }4 } - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册2 M0 i' Z# }3 @; k" y. }7 N J: p
- Vue.component('child', {
" P2 {4 d- n7 i7 v+ u1 w - // 声明 props
9 f/ G1 V, w: K$ p! C7 @0 H - props: ['message'],
' G+ I5 n9 B9 o0 x* K! M" _! S - // 同样也可以在 vm 实例中像 "this.message" 这样使用3 U% M( Y" Q4 Y. b$ g3 L
- template: '<span>{{ message }}</span>', J c5 Y' H; i. ~. Q
- })
: k8 F+ s4 H, y% B. l. [ - // 创建根实例
0 F( ~; J( x, o( W* A4 ] - new Vue({
9 f/ `$ q2 R8 [' z8 D - el: '#app',' t5 ^: \& N+ F" T
- data:{
c1 Q+ p9 X/ ?/ y& b( ?* H8 [# t s* `. } - message:"hello",
/ I6 |4 u6 i: Y4 q. ~1 M, G( g - }
* Y3 q! B v4 {) i - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
; H/ ^# j6 d* B7 R7 F - incrementHandler: function (v) {" G2 O. f( B% F8 G$ b) Z. `
- if(v==1){
. N1 `3 I) ?. E+ _; {( Z2 y( @ - this.counter -= 1
6 w9 J* L& m2 J. z5 ~5 n) B/ n/ Y - this.$emit('increment',[1])
8 c+ l, o ^: U, m' f* I - }else{6 o Z" ]: _& [; y
- this.counter += 1/ c+ g. i. b0 P- L q S
- this.$emit('increment',[2])
3 K8 C2 K, V0 U1 f) E: t) |9 f - }
* |1 f5 c8 K0 K/ q n5 R: T+ u - }
, q- X) [; v. D' N" ^! W6 @3 U, b - }
复制代码 5 N+ v0 V. U+ [+ m. \
% c4 E) J3 d8 C+ R9 q |