|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它: 4 t% f9 E9 b* o( g& q1 Z8 ~
- <div id="app">
% V |8 N5 t' o+ `8 L+ m - <runoob></runoob>
j/ l) w1 i8 ~8 B& o, B4 @1 v - </div>
; n4 A& R6 f$ t8 h" t" ~7 b% `" f - 9 v& q* ]3 Q4 @- O/ g- G! {
- <script>
& {2 e. N9 V' v' G) P9 p) m1 M - // 注册
2 y( F# P& h; D7 \) K7 H/ @" l: y - Vue.component('runoob', {
) f! m5 {! H, N: S - template: '<h1>自定义组件!</h1>'
& f/ l9 N1 T. l - })
( `& l! v8 K4 n5 ~9 M1 T - // 创建根实例9 Z7 F1 v- f# w) y
- new Vue({
6 w5 A. ^6 t: _' m& D4 j @ - el: '#app'
' z& O+ x2 n: R4 d" k* O6 O* p - })
2 n8 h0 r7 P; _2 a - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: 4 N. @. O( i- U7 z2 C9 |
- <div id="app">
* k8 x0 ^0 u+ T- M7 r) x( d8 W - <runoob></runoob>4 U8 X' L3 c2 U7 R/ u- i* o# x
- </div>
' l" J& R* u: C% a -
6 w$ I+ U0 m7 m5 S4 s - <script>
v3 M# a E' b! x - var Child = {! [! M8 D! r+ ~# T" ?7 k$ L- L
- template: '<h1>自定义组件!</h1>'6 [: ^$ w4 {! ]
- }4 ^ R# t6 H2 }- t: W" }
-
. d E. x& \5 y, z( V - // 创建根实例
. Z6 f1 y. J% f; O3 U6 M: p# S - new Vue({! p: U' H* G! I2 M6 W
- el: '#app',& U8 `* O/ l7 a W. c' ^
- components: {
3 R; {* x" B9 g. ?+ T - // <runoob> 将只在父模板可用
: s" H' j( y; w1 Q9 W9 f; H - 'runoob': Child8 u$ d/ Y/ X3 W$ g0 J# b
- }
9 @/ _" q3 ~1 q! T - }). F: D$ e2 G/ T% s
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例
2 I9 m2 y7 M3 Y9 y' s0 n- <div id="app">
7 r# O% ], y( Q' D - <child message="hello!"></child>3 t! J3 {5 R. a8 y. C: B
- </div>
* v2 Z2 n2 }% s0 `. q5 e$ i - # |0 T7 t& V5 T
- <script>$ e+ g, B2 y& v) \" d; u5 b
- // 注册+ M y5 x6 v$ j: {( U' m$ g
- Vue.component('child', {. Z4 y! ~/ N* F3 D, q
- // 声明 props% s; l: k. d: Q4 r" [9 b
- props: ['message'],0 J( [5 j" A2 v3 c6 |2 r
- // 同样也可以在 vm 实例中像 "this.message" 这样使用# P) f4 i8 O* g+ X4 r" F
- template: '<span>{{ message }}</span>'
, i; Z1 C F# c% A G: u; u - })+ N# c" S4 T4 i
- // 创建根实例
5 S; o8 }* u/ T& r7 c - new Vue({7 ?3 k5 x$ W1 p/ }5 y e% X1 u
- el: '#app'8 z& E/ F5 s% Z9 P3 l8 |) Z
- })
4 F7 D4 y# c5 N - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例, M' q& @) R# E: ]- u. c
- <div id="app">3 n) B" |6 }) t# e5 ?* j
- <div>3 i4 _$ z0 t9 K, M5 g' Y
- <input v-model="parentMsg">
t; }3 f) m! i( G* X - <br>
" o* w0 a1 v& b- N6 ? - <child v-bind:message="parentMsg"></child>5 ~/ y9 d# i0 G' N9 D) T
- </div>
, D. q& F; s P0 b2 q* F% @ - </div>
$ l' X$ S8 I) }* L- R/ m& z -
. i* R5 d2 ~3 [6 W5 [% Z - <script>
7 M M7 Q6 }) q/ j- ~) F - // 注册3 X9 A9 @" `1 D
- Vue.component('child', {0 {1 w6 m9 U- s) s0 H; S5 t- _
- // 声明 props. ]! n2 w& V) X# G8 B5 T
- props: ['message'],
/ ]& h- i5 J3 V2 N, f3 \ - // 同样也可以在 vm 实例中像 "this.message" 这样使用
. e/ z; z- B3 `9 J - template: '<span>{{ message }}</span>'
; T! C# D* G5 X$ v - })6 D7 }3 Y& Q6 [! |0 `, _7 h
- // 创建根实例
' i# P8 L- w) n: h - new Vue({
4 J1 A1 X9 `9 T. A# d7 ~( g, B - el: '#app',
4 B6 a7 G# x8 p+ p, M - data: {1 k, Y+ O$ C/ M. T2 Z
- parentMsg: '父组件内容'3 h$ b0 a* O) j- h7 s" P* Q: V, r
- }) N% Z" K$ @& e7 J* [
- })
. {' D8 g1 w8 P% K0 i - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例. ]! B1 ]8 I& k2 C
- <div id="app">+ u$ |1 L. Z, B3 \0 C
- <ol>
+ }2 G+ G- n% \ r - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>% S5 l, i9 l8 o+ a( N# r7 T. e; t
- </ol>) O+ u m8 L' l% i
- </div> F# o6 v4 R4 k* ^- [" a* b; E
- ' A8 ]" r2 a+ ~2 N+ w
- <script>0 p) K2 B1 q1 P$ T- s
- Vue.component('todo-item', {" i1 `' ]$ W' |
- props: ['todo'],* F' D$ N/ e; K# ]5 ?1 W
- template: '<li>{{ todo.text }}</li>': [& @+ w# h# s. M
- })9 g2 B/ p% F1 A# c& }
- new Vue({! p J8 A1 S3 ^1 x, E
- el: '#app',
: r+ c2 H* t1 B" ~% X- z - data: {5 M7 M; H2 V; e+ M/ i
- sites: [8 D6 c# _+ r7 X) k
- { text: 'Runoob' },
3 \) }; d$ t$ R. }4 G3 u. Z - { text: 'Google' },3 t) M1 C3 y6 P
- { text: 'Taobao' }
/ t) h8 k. n8 j- Q4 V - ]
' w% S9 x$ l8 c* }& g - }) g6 S& h- p+ C& f+ V" s; Q) _
- })
: v" ]' v7 {, Y - </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
4 X4 D; [" e" \ - props: {' O9 o' o1 A# l4 z
- // 基础类型检测 (`null` 意思是任何类型都可以)( ~- a: E2 x" s4 @1 i6 g7 E6 X
- propA: Number,
- B- G; j/ S6 F2 @( t. ~1 ]* V - // 多种类型
, n2 u) m2 |( B7 m; ^3 b% d - propB: [String, Number],/ _# _& [0 z3 Z4 f" x2 C: w
- // 必传且是字符串
. \( G' a# m' d( Z& R+ G& ?2 H. a - propC: {' I: [: M$ ^3 w P
- type: String,
1 c: v. g' h8 e2 Y. b' T - required: true) k" t5 ^, Z# V4 v5 l' T
- }," z0 c* j( H: @/ j. M* b. `
- // 数字,有默认值
' s, s0 B' j# `- [; K - propD: {
" D0 H$ f8 B( V1 r2 {6 @ - type: Number,
/ @3 i7 n& U+ R" v - default: 1005 C& M3 J3 _! E
- },
5 u$ l1 d$ {' Z' e# {: _& n - // 数组/对象的默认值应当由一个工厂函数返回
: M9 m+ h- j5 Z" c, n/ f; B+ u - propE: {: @. H }- o$ C; E5 \& H& |
- type: Object,
0 F5 R9 `& m! c- L - default: function () {; S7 q6 r; V5 ^! J
- return { message: 'hello' }
6 [ L0 T* D: U. q. \ - }
4 G8 q' a4 A$ D& Q8 i - },
+ g2 c2 u1 ~8 i& W& Q- X - // 自定义验证函数
) G1 @4 s- P$ o6 _ - propF: {
- D4 H: \3 p4 e$ I3 E1 c - validator: function (value) {6 \3 X+ X$ e* a& _. d6 X
- return value > 100 [) \- ^8 X8 B. u! c
- }8 L5 b8 i U/ d% M# ^* Q; F
- }' L6 A7 s: C0 K
- }
% Z7 s8 o. A7 T( Z3 p7 { - })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array/ y, E; `$ m* t2 N3 E" B7 {7 G
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
& a! V( a w/ {, A' f: b
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例, m" R; ^: j4 a$ K
- <div id="app">* M' `# Z( B3 T% T
- <div id="counter-event-example">* ?' A8 Z! _5 G/ k2 ~) Z
- <p>{{ total }}</p>0 w1 A- S3 E1 Y. G- `* N
- <button-counter v-on:increment="incrementTotal"></button-counter>2 e. Q- ^4 X& J6 v: U9 C
- <button-counter v-on:increment="incrementTotal"></button-counter>
) ^9 i8 X3 x, f1 [8 u1 _- M$ V% A. z4 W - </div>. M5 d' B, k. ~1 s' }4 X2 C
- </div>
2 w, U& b* ]3 v; L/ _6 n- V- G -
, a; q) c4 c I* O7 w% Y - <script>
3 [7 v1 x7 O6 L; ?/ S$ j: R - Vue.component('button-counter', {; Y7 s! X8 E2 p6 i7 T! u* K
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>',* M7 o, w# a8 l/ |" ?& J C3 K
- data: function () {; v7 Y, g; r; a1 y$ z
- return {
1 J* k4 k, W$ U, v4 s" n0 w - counter: 0
% }* Z& A ?5 p& Z& W4 R7 f - }
1 y3 F7 Z. F" N A7 |) { - },; a: k% J# l# |0 I! n
- methods: {& U+ J" D/ Y* f1 Z# C+ w
- incrementHandler: function () {
7 F0 i( D. t" [! y9 T% w - this.counter += 1
7 ~- U4 Q- _/ }9 s& z5 `- | - this.$emit('increment')* z- p+ E* E1 `+ E5 q' X7 i& y0 x
- }
/ V4 ?- ?- a$ t; p m2 e - },
0 z" Q* s/ y5 T4 M0 d. H! I! y - })" Y; b4 d. b8 a% t9 k
- new Vue({
6 X8 w7 D3 |) b- b; _1 h9 k - el: '#counter-event-example',
" @! ]8 I- C1 _, m - data: {
9 M9 E6 k9 ^. ^' E8 t. \ - total: 0
5 Q! R$ U" a" \ g; ~ - },
& y& {+ O: s% L3 D) e3 A7 z3 X# C - methods: {
' _3 H8 @" X- r+ z* a6 f: f1 z - incrementTotal: function () {" S, B4 E/ v/ J% y0 i- ^
- this.total += 1/ a4 f. |6 y6 g
- }
' z& Q& i) K) l1 g% l5 D; Q - }7 m) |. i- Q+ P1 y6 V8 A
- })
$ K# R0 e# y* G" g# z$ s& G - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册; s' i4 J% R5 A
- Vue.component('child', {- b4 p3 @. O, f+ M- l* a( @* G
- // 声明 props) o# C0 t8 _7 Y4 v
- props: ['message'],3 V8 H3 C' r+ j
- // 同样也可以在 vm 实例中像 "this.message" 这样使用% g: \ q8 L! ^* _9 A" I2 K% [$ R; o
- template: '<span>{{ message }}</span>'. \' ?* `3 @8 w2 Z+ r$ f
- })6 s! J6 e! D; ]& G9 F: n
- // 创建根实例
" ]- ]# `7 m5 t. E( y6 I) q - new Vue({
$ Z3 g) f1 P. Q* [* g/ X( o - el: '#app',
4 k7 j! `7 m& R+ d9 [4 F+ b - data:{
' L5 D# [3 s* O( J! }' e; z - message:"hello",
5 ^! Y( G) x N - }/ b- v# T8 h' T" ~- ~0 o/ J
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {( R- x( }+ V0 y3 ^
- incrementHandler: function (v) {
+ d9 S4 C9 o% L& Y' S; l( Q# R - if(v==1){
- E5 d; f% u; F& t1 v- h. S! O - this.counter -= 1% u& l! l$ o* i% r: d! A O
- this.$emit('increment',[1])
$ R l# h ?# L& Z6 e g1 t' |6 \ - }else{% N. b: O& Q* n$ r! q
- this.counter += 1
V9 B7 ?5 s# \7 b" ~ - this.$emit('increment',[2])* y2 v5 R) G% R& y/ s
- }
0 \( G1 B* t' n7 n$ ?* r - }. |# x! q P& n
- }
复制代码 , ^' f X3 k- D9 Q, s
, e3 R$ |# I) x, N, s$ d$ n |