|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它: * k2 c/ z1 p1 p! \% h
- <div id="app">/ P! z5 M- O# ?9 i" L
- <runoob></runoob>
( V4 a- C1 b k7 i3 z" a/ Z - </div>
0 [, j! T E; x* y" c5 h+ w -
' v" g) J b8 K' P2 a$ ^. i - <script>& O4 U" z O( x: y2 v( W( d3 C
- // 注册
+ P+ b- D# k! f1 m" i: U# l - Vue.component('runoob', {& d$ T; X* q* l& u7 m7 n `
- template: '<h1>自定义组件!</h1>'! b u# y9 F9 Y! ^2 g! o1 J; Q8 C" U
- })0 t& ?) y9 R/ c
- // 创建根实例
' \. q0 Y8 Y! W& N - new Vue({3 n# P S# F. h1 K! R
- el: '#app'
7 w+ j2 ]" S, K1 p - })
% Q0 p! G4 s5 z# X - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它:
5 J& b1 d. z* [! J' n- <div id="app">
3 p$ A& X' a. k# L/ E% n) b - <runoob></runoob>; {8 l& M. U6 r6 T5 e
- </div> t6 H7 _0 Z# x9 l7 V
- ' R+ ~" i5 q' ?) _) v8 E
- <script>
& k4 O' [5 y c7 t) {$ g; n0 Y9 K - var Child = {
6 i, x8 ^# U5 k6 Y1 @ - template: '<h1>自定义组件!</h1>'
& x) _3 ~+ p5 u+ m( m - }
6 G+ x" s |* e% H -
2 z% J1 J. ^9 X$ p4 t. b* x - // 创建根实例+ G: [ T) ^9 n+ C4 f
- new Vue({ N D$ H6 M2 X9 P" ~( ~1 ]2 e: ^
- el: '#app',
+ l) ~, R! q* C4 d8 j' y j - components: {# d1 l- v9 M/ }/ L$ B
- // <runoob> 将只在父模板可用
. T, O) Y# M5 Y4 _3 u* o - 'runoob': Child1 P! S0 b( u0 r/ U- u
- }$ O! Q6 i2 @) r# v* o3 u
- })
4 K* S/ ^. x6 g/ y, k, N - </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例
4 F7 L% R4 R6 Y0 c+ l. u- <div id="app">+ Q2 y' f# v1 w/ @/ A
- <child message="hello!"></child># M) L" c4 u; u: D4 }* K
- </div>
% C5 W0 }3 f X4 Z -
& P" f6 b% X# i' i Y - <script>
% g+ X* ~* V3 e" F) B" | - // 注册+ j R d2 J! {$ X3 v9 Q
- Vue.component('child', {
# {; E& b5 i4 N; S5 c; X, C - // 声明 props2 `+ o5 m1 I0 Z
- props: ['message'],3 j' P5 N+ Y9 ~% m. E: d
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
! g. d5 `; A7 Z j& B* \ - template: '<span>{{ message }}</span>': E7 k5 r, q: O* ]7 @1 l- i% j) |
- })
% X* r; P( e5 {, N7 w - // 创建根实例
8 f9 e; `2 h; F- H: }" y - new Vue({- v8 j. ?% R# g/ A6 X
- el: '#app'9 Z# D Z. a0 {( p
- })
* ]9 w8 l5 ?& x0 |: W. } - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
) e$ H" ]# v4 L* {* ^8 j2 t9 e: S- <div id="app">
0 T) l5 |6 ^5 x& ]/ ~# K - <div>6 O$ M/ G8 o6 W1 _% P2 \$ d
- <input v-model="parentMsg">; s: H+ V$ u, L/ c2 r
- <br>
+ r" X9 O D7 E - <child v-bind:message="parentMsg"></child>
9 L# R- t. }' y( g5 t+ q* n9 ]+ q% x# \ - </div>
6 r- S; r) @, [; Z/ {+ P - </div># K% \; J* `2 `* H& V# v% p
-
* q- e9 p$ h( n. c: G6 x - <script>
* _$ N9 K# W5 j/ K# ` - // 注册
8 n+ m; ?' j: q. c* B - Vue.component('child', {8 L b! C* q: G. @. `0 U
- // 声明 props+ p4 I0 g+ J S2 x
- props: ['message'],/ r& t1 ~+ R6 `; L b ]9 `) ]' M& T
- // 同样也可以在 vm 实例中像 "this.message" 这样使用5 u" b, h# {1 u; z# l; t B
- template: '<span>{{ message }}</span>'
! }( T/ S8 m2 H" R8 ` - })/ K, |9 |1 X- y# b! S
- // 创建根实例! n L9 f. S( l1 n
- new Vue({
7 |; ^8 J% A5 o. K4 u! B* S' k - el: '#app',
4 m% J3 w0 \& i! @* R# w t - data: {
6 {' m3 _3 {: Y+ E - parentMsg: '父组件内容'5 g, W3 X. D+ L- ] T
- }8 q8 _" p, I( J# `7 m/ _) D
- })
' X& A4 o) b3 z4 t9 x - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
7 x: H* V0 T' M, W) {; {/ A- <div id="app">! P% O! y1 l9 H% [) Z$ ~
- <ol>! [! l* a# h3 {1 T; P' |
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
7 C% H7 X4 O% _ - </ol>8 p( N% \1 w( `( E! a; j
- </div>$ c/ h3 y/ f5 a- x& p* W
- + s" P' U" [$ [ j' q: a
- <script>! P# K% I# S6 u) G" {( a
- Vue.component('todo-item', {
/ p" U% i7 O; |; ^ - props: ['todo'],( i# ^/ j8 t7 x( I7 D/ m
- template: '<li>{{ todo.text }}</li>'
1 p$ B5 k+ B: F3 j5 K( E - })
# r8 `! c* z/ G - new Vue({
4 Y# w" \! Q2 z& Z6 u0 T7 ] - el: '#app',$ A" t, m5 C% u# }% r
- data: {; _4 t- Z& k/ e4 F" U
- sites: [
8 f/ T/ E- r. o6 M9 s - { text: 'Runoob' },
L* |0 a; F" W" C - { text: 'Google' },( h) K0 q( C/ S
- { text: 'Taobao' }
& c1 A* N7 i- `+ b0 \2 _ - ]3 L2 l, ~8 N( l, d+ r$ h: o, l+ u5 e
- }: g; n$ w/ q: p. _( C' G
- })- Q3 [7 d5 O: v1 [6 \* [( k3 R
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {2 w8 h% h. D, x. | M
- props: {
: n$ E) R# W; ]9 Z - // 基础类型检测 (`null` 意思是任何类型都可以)0 Y$ S! ~/ o" o1 W( Q5 g* I
- propA: Number,
2 c* o; K' [5 v/ K# D - // 多种类型7 W2 Z, n( o6 w2 V
- propB: [String, Number],: M" I( K* v$ _, k
- // 必传且是字符串0 D* L' f' N0 g( W" s
- propC: {9 ^3 E! E' u' H/ U' e; u
- type: String,( a4 l* _* J9 y
- required: true
, Y( C8 B, T' W/ K9 V - },) z9 }7 F9 v1 O4 X2 y
- // 数字,有默认值
# _! s8 |) J- G; {' `* v - propD: {
0 m5 `: {, J$ g) j4 q - type: Number,
O8 J( [8 S+ h" e8 E - default: 100
~5 R# ?% K) \( v9 \ - },. i" o2 l7 ^- H- |7 r
- // 数组/对象的默认值应当由一个工厂函数返回/ Q [0 x3 }' q/ Q- p# I
- propE: {
2 P d$ r2 N$ S- p/ x; j2 e - type: Object,
: H' }7 \* q5 X3 J! s# n - default: function () {
$ d4 ~, W- c/ X% g; t" N" l6 x - return { message: 'hello' }- T! ^4 {3 s; I' C9 }* ^7 R2 H
- }. E- M- G1 P& j5 r% B2 a C5 _ k
- },
U3 w7 T) `+ f. K' e: L+ s- _ - // 自定义验证函数
4 S/ M# T9 }& U5 s) u9 D/ _ - propF: {/ p7 G6 M& j$ L5 D3 ~4 W d
- validator: function (value) {2 k. K, X- H) {3 w6 G2 m1 u2 v2 M3 V
- return value > 10
7 k( O8 x: b) E" p - }. i, q1 N6 t8 M9 Q/ l
- }
' U+ U* I, B8 d) G6 d - }
- C# |7 A) U" N' ? - })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array( l7 h$ k6 u( C) a1 ?
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
3 g4 L) [. M; T6 s# O, A
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例% _4 o \" i F# @! G* `; Z. u
- <div id="app">
9 G1 ]2 {9 j9 H - <div id="counter-event-example">
. Y _! W4 E1 p- |! f2 ?2 }! b - <p>{{ total }}</p>' u% o0 ^/ e# M u
- <button-counter v-on:increment="incrementTotal"></button-counter>, Z# } H$ q! e' I( Z+ z
- <button-counter v-on:increment="incrementTotal"></button-counter>& m, C* e! w- k7 o
- </div>
5 t/ k: J- G% K. F - </div>
5 T1 u6 r6 n) [1 t - , X% L" L" W2 M% h, S/ p
- <script>
7 a) W: }3 \" e0 X! W. a - Vue.component('button-counter', {* b9 V' Z: _ x4 e: w* ]
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>',/ K$ W0 o% T5 s2 Q* w4 P' X" _
- data: function () {
) ^% u8 d: F: N/ s7 E- n0 a - return {/ N7 \) M! Y8 g6 ^# ~+ U
- counter: 01 ?: i2 ~' a$ f; J' C; t
- }
1 O$ S, I: I, q9 Q; P7 | - },
$ H% N) J8 N0 E7 h - methods: {
: R, \+ d, k# Q4 [ - incrementHandler: function () {
3 _, p' e8 j/ }/ n* ` Q - this.counter += 1* l8 t& c) L; l* U
- this.$emit('increment')
, O4 o- m* {$ v - }/ @# }! y* T$ w. K C. {
- },+ a& P5 }+ O1 [7 _8 R
- }), i6 G2 {% s; ^7 d1 m
- new Vue({
- H3 {4 `& g6 q2 S' D - el: '#counter-event-example',
/ i6 x/ v6 o, ~) K- R6 G, C+ I - data: {5 k4 L; f& q# s# s/ a
- total: 0
1 [2 W$ i0 P% M9 u7 j" J6 c - },5 E& J5 }3 f6 V- M% ~
- methods: {
' i- g5 \$ s! i - incrementTotal: function () {
3 J q) R, j) k/ w: U3 _' l; P - this.total += 1; U; C6 O- @% H# o2 H2 X
- }. P! h% U6 L+ t; s7 J H% w8 ]
- }
! h& {( k3 g9 j - })! Q3 o" O; R0 {) k
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册9 S) j$ C, v' x5 Y# U
- Vue.component('child', {
' Y5 l% r0 y) W5 [ - // 声明 props0 g. b. r, K* i' ]
- props: ['message'],
7 G, z. h, O- R3 p6 E - // 同样也可以在 vm 实例中像 "this.message" 这样使用
# t/ z% ?# q. g- {$ j+ b - template: '<span>{{ message }}</span>'1 g, j& [! Y+ m
- })
$ [2 p. _9 T3 a8 x$ l/ N% g - // 创建根实例
+ r' b% Q& r* Q) l$ r - new Vue({
+ n+ g& p3 M8 }6 }7 W0 W& ~# x/ M @ - el: '#app',
6 G- J" N: e c0 E - data:{; v- d% E) b- _# F1 X6 |% ^
- message:"hello",
8 u- J0 q2 g1 @1 Q1 V4 L# P: } - }
7 y, c7 L& E! K) c; x - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
$ \* E7 q7 a B f7 [ - incrementHandler: function (v) {, S5 {) Y, a. v( s6 F* t. Z" c. b
- if(v==1){
( Q' J7 Q+ _: t! p - this.counter -= 16 S+ D& k* S1 ]: l$ m- I( B! R
- this.$emit('increment',[1])
% \4 ?9 i8 t+ b, Z* Z6 o! o - }else{/ ? d9 I1 P3 I$ M3 a1 r
- this.counter += 1
' U( L7 j5 T+ f2 d" n, x - this.$emit('increment',[2]) @# m5 l* C- S; N4 ^
- }( H2 C& q1 C$ R# n
- }" \1 \; R, s. v0 J+ q' h6 x
- }
复制代码
) e; L; E) j8 n; ?8 A3 W" T6 E
+ [% s$ {5 m; K0 I8 ] |