|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它: % R2 A0 T- e% e7 B {, N W& W
- <div id="app">
/ f2 Y8 H* j$ e7 h, n8 T* c - <runoob></runoob>
2 ?/ L/ F- X+ I0 E - </div>6 x3 D; K8 M/ f! Y- q6 L1 M
- , m! [9 C) R) g; ?5 D2 Q
- <script>
! o+ o0 @# F( w - // 注册+ @" C0 I7 G' _) Q- z% k
- Vue.component('runoob', {) r8 z$ e; a/ T. f" l) H& k
- template: '<h1>自定义组件!</h1>'3 O( B6 Y s) ~6 \$ r$ ~
- })2 H* G9 p0 r, Y: s- `
- // 创建根实例
7 c$ u- m: F9 ^, R' K& n) X, ^; M - new Vue({% z# `& K. z$ @! x
- el: '#app'/ Z/ u, M, ], W9 R8 | [5 q4 `3 d
- })- C+ ~$ q# N& ~( Q6 p
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它:
( J' d" \8 B0 A8 w8 B- <div id="app">, R! w5 j, ]- D/ _6 p% G- B" z# |
- <runoob></runoob>
- h) y, ~, L1 |' l) ^2 A+ d - </div>( W" |: L3 p# E5 v& U
-
$ r! Z+ n) z6 s+ v - <script>
6 ?9 r7 E5 j9 s& d - var Child = {
u2 ?$ e; D+ N# c; U5 y - template: '<h1>自定义组件!</h1>'0 W: a: ?$ v, Q0 F2 V/ p
- }
3 K2 w, l- s' P -
5 r% g' d, A" Z8 o: e1 E! |2 B6 E - // 创建根实例. L7 ?0 J7 X8 y9 P$ h: w
- new Vue({1 [6 h; S) l7 \1 t/ `9 z
- el: '#app',
V% M6 q1 K5 n& _! M* ~2 X - components: {1 \$ Q! v" v: Y# I7 K6 ?) J
- // <runoob> 将只在父模板可用
1 u8 ~+ g1 {* _, ?& m - 'runoob': Child- K8 S4 F1 [/ k; l# |
- }
" M0 x! H! x9 D& k' v4 N9 N - })" n# N d7 R! S+ H2 W' _
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例1 c; P& H' O2 p/ j& E3 f
- <div id="app">
' h# y( r) n) i% ~ - <child message="hello!"></child>" h# S- r+ J# N: [3 d0 {8 U0 n: Z8 h
- </div>
9 Z6 z7 h [1 N2 ? - ! |' u8 n2 I6 s* r5 {- z1 d
- <script>: }: R- V+ f+ M
- // 注册. Z$ ]) z) ?7 R3 B3 K$ e9 O
- Vue.component('child', {
# P2 b! l& k7 q0 u& c f7 @ - // 声明 props& P# i1 ]# C- W% Z: F, l( F
- props: ['message'],' f9 Q3 x U4 `
- // 同样也可以在 vm 实例中像 "this.message" 这样使用6 j8 ]6 ?: G. D9 i. h) O5 Y
- template: '<span>{{ message }}</span>'8 [ C! w5 _; @1 f
- })
& l; U/ c& y1 @7 I' s& Z - // 创建根实例
" _! a6 K0 J0 Y7 k( l- @& n - new Vue({2 Q1 p! U9 s7 z; y/ v7 }7 M
- el: '#app'6 e% L1 a. |! K3 Z, [
- })3 n& Q- ^1 E3 q5 ^ d4 g$ m" b+ w$ @% M
- </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例" h9 \2 `& z: r! n, o# U! w
- <div id="app">
; n7 c4 ~9 D- U - <div>
$ {3 m! ^/ h a) } - <input v-model="parentMsg">* e$ d* Y- }! [% ^9 A3 v9 [
- <br>6 ]3 }2 n& g* ?# r
- <child v-bind:message="parentMsg"></child>8 u0 p8 q$ l. ^* k- _: M- D# z. O
- </div>
3 W! U3 K, g. H+ }" A - </div>
# ]0 i4 G9 s4 j -
( i( }* C9 ^; V' c+ [, l6 O - <script>4 d. k9 d& E; H7 t* y) ]' @. y/ n* v
- // 注册3 u2 c+ T$ `; o( ?, {7 F0 Y. @: d$ |
- Vue.component('child', {, {9 D3 _, I3 P
- // 声明 props Y: s5 |$ R; X" e0 t$ C- G: p
- props: ['message'],, c- ?& k" p' ?7 x' ~
- // 同样也可以在 vm 实例中像 "this.message" 这样使用+ F Q6 Y8 ]6 K: a0 m3 ^
- template: '<span>{{ message }}</span>'
6 `: {4 K: q! F: c, N3 z - })
j, {& Y0 |# r a# k4 f8 R: S - // 创建根实例$ y: B- _% Z- z3 j3 u3 @/ d
- new Vue({
+ R5 h2 L* L/ v5 z! k$ n - el: '#app',
7 {5 e$ W! }0 r! L; ` - data: {
6 {# p5 [$ `% ~; O" c4 B - parentMsg: '父组件内容'6 e! b# T [$ g
- } t* G, k+ r& e
- })7 \4 H$ h$ z9 x) h/ o6 @) V x* r
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例- U" ? p: Z. y. D
- <div id="app">
( \7 p$ U( p! k; h - <ol>
4 [1 d* A; \$ C - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
) U+ J2 l5 S" U4 \) y- g& k& n - </ol>3 B4 f m% s- Q A1 O2 k" g
- </div>- S: M- P& A1 P& f1 \
-
5 L% ^; ~. ~! _% t - <script>0 I% `4 Q6 f: ?) D& @8 b. X+ j+ G
- Vue.component('todo-item', {
2 c: V B" N. g - props: ['todo'],
2 F: ^" i. m8 `# [ - template: '<li>{{ todo.text }}</li>'9 f+ P8 \# t* V: m. C" P
- })8 K: f# v% j9 O* r! P$ g
- new Vue({- z/ E. e6 ?) ~; l0 D
- el: '#app',4 @$ g5 n6 t( a# {4 t' p
- data: {
! P* o5 ], }7 X# l" Z - sites: [. b( u7 I/ [: P w& m/ x/ ~
- { text: 'Runoob' },) l0 D; k' |6 H& s, y5 i; J( k
- { text: 'Google' },
4 C2 B1 P& T0 X( ] - { text: 'Taobao' }
$ r: K/ }* r ^/ m4 _/ F - ]
8 p) K$ O5 Z+ \# ]& b - }$ M8 [: T. s2 @4 g& Y$ n* y, _
- }). B0 Q* [% E" Z6 E C
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
$ S1 M( I0 g5 K F" @% P - props: {
4 S7 `7 |# o; x) c& |, Q2 J) j - // 基础类型检测 (`null` 意思是任何类型都可以)3 j4 t' A* v4 y# v A
- propA: Number,
, H& |& ]" E q4 Z& e& o - // 多种类型
% ~/ X/ M& X, M# X - propB: [String, Number],, N$ _ g& Q6 u0 x5 T
- // 必传且是字符串
$ m4 b8 k! Z, t v, y8 v- ?. x - propC: {: k- Y& ^0 @& g( E6 y
- type: String,
& K0 Z0 E+ G6 Q" b( Q0 }/ z - required: true: y+ p; N4 _* j5 G1 ^, P
- },
2 t, d, e% {: p m - // 数字,有默认值1 N8 q F; s! C8 |- t
- propD: {
, z6 _# ~/ v2 g- S1 F5 e - type: Number,# X$ V9 |8 B7 h; m* Q' O+ G+ j9 ]# e5 R5 w
- default: 100# w- ~% f" K) G) R D/ {5 p. B
- },! V4 W4 b, b, T- a1 R3 O
- // 数组/对象的默认值应当由一个工厂函数返回* F9 l/ |' t' q) f; L
- propE: {
: X4 L# `# A( d: d% _1 z - type: Object,
4 j& I; _- @' o W# c) ?0 z - default: function () {
9 [' \: D! s& C5 ~ ~ - return { message: 'hello' }" T2 `1 W( D# t8 Z1 Z4 J
- }% |0 @; m2 Q! I" L B4 [* u$ i
- },9 X# W, G% K8 Z) C d
- // 自定义验证函数" J! Z6 O) p; q) q( g6 A- Y
- propF: {
- v5 P) }7 r/ {5 k0 x1 _8 j! J - validator: function (value) {4 o( \; k2 m. b+ U6 j
- return value > 10# ?7 w& e6 ]- U$ J7 f
- }- c7 c; Z7 C/ Y) T- E
- }' j' C$ g$ n7 X/ i+ Q
- }
6 e) F, f K X - })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
. g% M2 B& z" _# u" c K% d
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件2 Q" s, C9 y5 C. B5 b
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例
8 V# |+ C) [/ C" i% @- <div id="app">1 e2 d7 L7 K( E0 U9 a
- <div id="counter-event-example">9 n# I; f, Z. c. [1 ^0 n
- <p>{{ total }}</p>
; }) @- g( e/ k( m) G - <button-counter v-on:increment="incrementTotal"></button-counter>5 M/ ^. J0 w0 p+ c3 A9 F3 H$ Q# Q, w
- <button-counter v-on:increment="incrementTotal"></button-counter>( a; {4 \2 S2 o) f& I) T
- </div>
; j: C7 O' B$ _- ]0 k" y - </div>9 b* Q. j8 U* o& n# u4 m. K E O
-
$ a: ^4 n! Z2 {. b- G, s. g" n/ X - <script>
' i6 O: K$ V: E" ~6 ^4 F - Vue.component('button-counter', {
( p0 E% D& K: J+ s - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
' u# Y: u3 ]+ P6 J* Y - data: function () {
, A& N, A4 C# ]: ~- ~8 p7 z& V! T8 w - return {
: S6 }. S5 |6 L+ B. G* M - counter: 0
% |8 ~5 l# w0 i9 t( O - }
9 A4 T8 ^3 s. Z4 A1 {2 q - },1 C/ d' w$ j U$ Y: P ?
- methods: {: n+ i# M! _ c& g2 ~* {
- incrementHandler: function () {* y3 `* ^6 s5 [6 x+ H
- this.counter += 1
( p. Y: J9 l" R; w: W! r: ~ - this.$emit('increment')
3 Q2 U9 z+ `; k" X" z - }9 ]0 Q( M! \8 Q' d9 f- N
- },2 \0 A# p. e3 U* J
- })8 K" x9 P9 V+ }0 ?7 E# o4 Y/ J
- new Vue({0 [" c6 q7 z2 H
- el: '#counter-event-example',1 C' K7 C- r: Y' @, T
- data: {
) c0 v, p0 P8 D0 I3 E& f - total: 0* J# R$ s# ~% \& p- l- s
- },
# q: X0 R& `+ h2 F: m: _ Y - methods: {& [$ `# M0 o9 G
- incrementTotal: function () {
2 |1 e4 s' t' L% `3 q: r: w - this.total += 1
+ a' n5 V1 T- L - }
; K7 d0 a3 \/ o" {/ l" M/ O - }; v% E& `" { y$ s
- }) a! N. Y/ {& B# v5 p& Y. V
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册1 j0 t9 _& f1 T4 }* h# V. q
- Vue.component('child', {
- N5 k* W" ~7 ~ - // 声明 props- F2 F9 }& x" Y4 M
- props: ['message'],
+ e0 u/ N! q% [7 e/ e6 k - // 同样也可以在 vm 实例中像 "this.message" 这样使用+ d5 u! G6 N& |1 `1 K: j/ T
- template: '<span>{{ message }}</span>'
+ k6 w& V; R2 O5 L - })
+ Q( g8 T5 j4 g6 v - // 创建根实例+ Z6 }+ y& j7 U/ Q5 Y
- new Vue({* G! Z5 R) I, p+ Y ?7 ]- R
- el: '#app',, }1 C- B2 h8 w$ d
- data:{
M3 U( ]/ _4 ]$ \ - message:"hello",3 r: ]6 Z" q) }2 ?
- }
1 b( w3 g5 H8 a- p% R2 V0 E - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {' c/ |/ F/ E3 l, u) F' ?
- incrementHandler: function (v) {
2 r4 R3 [& L' j* T! h( O - if(v==1){7 x( Q# O& j! E6 C
- this.counter -= 1: b! K4 ~' E1 p4 d% \
- this.$emit('increment',[1])' \9 a+ ^$ [; b: x: s( N d
- }else{' c( E1 n% H7 _9 o6 v3 v0 J- {
- this.counter += 12 T$ x( d) l9 N* d5 D
- this.$emit('increment',[2])2 f ^5 w0 g& C% R* @; V
- }2 p) I4 M- B9 @8 L
- }# ?0 Y% C6 P: W4 C5 W. c/ H
- }
复制代码 5 {1 E4 V9 S% I3 I1 ?
0 Q+ q# f1 [( W! W. _0 B3 F5 l# j |