组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
, ~9 @7 Z, ?& a8 n) N# j+ u- <div id="app">2 w |" s0 S l( B4 m: f
- <runoob></runoob>
: J* Q4 b8 T) m* S* R3 S2 [; c1 f( f A& T - </div>% ~) T; ^0 b7 l5 f
-
. c3 P6 f3 U' S7 \) J$ t - <script>
% L& _$ g) ~3 @& b2 F - // 注册) W; u& p% a5 w# U
- Vue.component('runoob', {
7 L" | [0 F2 o - template: '<h1>自定义组件!</h1>'
# S; u9 J8 c/ v8 h; n2 ~# o+ B8 R. r - })
2 p+ `* K- ?. e0 R: G# y; ^. s - // 创建根实例) s5 q0 R9 L! ^" r! q5 k6 R
- new Vue({' V' y6 r8 z9 A
- el: '#app'
( S" K- y: W/ s, F, b" f - })6 K) i# n' |' k9 c0 L* v1 c) {
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它:
" h# V8 |$ `( P9 b- U- <div id="app">
9 l: `8 X7 x& z7 Q - <runoob></runoob>/ `. ^+ k- B5 `4 m6 m
- </div>- B, O" }( G# \, w {3 E
- % o2 k3 u) o1 \! K- f: P7 k
- <script>
$ W. D2 K3 f: z - var Child = {
2 c2 P$ L/ A2 U; c( i+ n - template: '<h1>自定义组件!</h1>'
# [6 A) s; I1 N L# J [ y - }
) I# z# [7 N% Z* @4 } - , d% b& }# G5 H9 o6 K4 a# ]
- // 创建根实例! x* |; |1 O# z9 I* i. q T
- new Vue({
. w+ l& n' M9 Q - el: '#app',2 p# y2 d0 @( P/ M0 {, W/ | n4 W
- components: {- Q, D' J) z1 x' `+ v0 K( T
- // <runoob> 将只在父模板可用. Y; D$ H& t7 v5 ]$ F
- 'runoob': Child& s# C7 M0 f1 R
- }
& E r% V9 F i$ [3 C Z0 F7 Y - })$ h4 k3 M' c* E& s: Z) @' g
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例8 a# G/ i. l1 \ f" |6 F: O, E
- <div id="app">
+ t! b+ G0 K* Y9 R - <child message="hello!"></child>! w4 F1 I0 K8 Z( E+ z( G" ?
- </div>: n6 W/ V+ b, ?9 [: V' [( Q/ m
-
& D/ K( D. A+ I2 z B4 R - <script>
6 L9 p& |+ |. ~* M - // 注册# F5 q: ~ B8 E9 ?
- Vue.component('child', {0 x9 c6 I& h" j T$ z
- // 声明 props
; ?' m6 t2 m- ~" N' h - props: ['message'],# ~, N$ v% A! g
- // 同样也可以在 vm 实例中像 "this.message" 这样使用) j: l0 g) ]8 H# Q/ `, }; p
- template: '<span>{{ message }}</span>'
3 P+ F! X' V8 Q. Q: H/ U - })) j% m) S7 C3 x+ v% {1 F
- // 创建根实例
) s5 L" c6 t; I# y5 v% l - new Vue({
8 h6 K8 b9 W1 ]# { - el: '#app'& L0 x& b; K9 `
- })0 D% Y& Q2 v& Y) \3 X
- </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
% K% z/ V; i9 i! C; Q9 K4 y- <div id="app">
& z9 m# A* Q8 W4 R3 n/ v, } - <div>
' W; P1 F$ O5 [- V: K. U* @ ? - <input v-model="parentMsg">+ J/ c y; j6 p5 e, r
- <br>
1 }' e' ~4 P% t6 O6 M0 w! x - <child v-bind:message="parentMsg"></child>+ S. h$ Y( _" {- K) `, V
- </div>/ _1 U: }8 l7 X$ ^5 q1 P# i
- </div>
5 [5 n; L( J; R3 S$ w2 O4 O1 i6 R- j - ( l$ V) x* O* ]7 j, x) G+ I
- <script>% u o) e' e8 j( @, h
- // 注册# i/ P# F& | C' Z! b
- Vue.component('child', {
4 y ~: A+ g/ A" Q% A: J- R* _ - // 声明 props& J3 Q) g" l" M& R& `
- props: ['message'],6 S9 i+ D6 s9 B0 V
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
$ x. O( |- _+ w/ W/ ? - template: '<span>{{ message }}</span>'
9 ^+ K5 V7 s) @, H3 g6 L - })
* g- w8 Q: q& T- X - // 创建根实例; H) s! T8 X+ `3 ]2 Z# B
- new Vue({
P4 d: T1 R6 o/ ]+ x) ~6 m* V - el: '#app',
+ A: e2 J( t* y$ [/ M( n1 i/ Z l - data: {5 }- M2 `8 ^, i
- parentMsg: '父组件内容'0 [ Y" R% ~0 M
- }1 s' g0 P' N8 R
- })) O0 x; M' [/ R X5 S9 ?2 C9 b
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
6 D* `. ~% w( H( A- <div id="app">" @! z9 x5 j) R) j" k1 t6 Y' x
- <ol>
/ H" E$ g9 i% f" B* t - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
7 X" g" Q4 ^1 @1 C* @0 J g0 {7 _ - </ol>
& `) m5 H8 ]5 y* [- ` M* P - </div>
& I- }9 \ }; u+ ?0 T2 I - * ]( j& u6 v0 d0 w, E
- <script>
1 Q" [ ^( M$ l: t8 t* d - Vue.component('todo-item', {! ]2 h s" ^- ]$ `4 f h C
- props: ['todo'],
* r+ [3 a6 ^; D! F& p - template: '<li>{{ todo.text }}</li>'0 V/ U! u7 A7 O: V6 U) v! `. K
- })/ C+ K# ?3 p2 ] D- x: R3 e
- new Vue({' W3 h' F9 O: t
- el: '#app',7 [$ t+ f7 o' Z; s. X) }9 w/ B7 _: X" M
- data: {8 k5 {. J# |3 C1 D& {
- sites: [
9 l7 r6 w0 J+ b. }" u2 h - { text: 'Runoob' },
1 l* [, S$ @; s* |; t" E - { text: 'Google' },
. k6 Z# @& K3 h8 d& M - { text: 'Taobao' }
3 H7 F, l9 A/ E0 n+ O- q - ]8 _7 O" n1 f) u; H+ [# N
- }* w, }2 i7 w- ^3 x- z5 q
- })
$ C" a5 f" P& `6 O - </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
) q/ @5 \$ K5 n* g - props: {
2 g, A" f. b( F5 g - // 基础类型检测 (`null` 意思是任何类型都可以)
6 w/ J" {$ h. |1 `+ Q- j - propA: Number,
3 {5 S. `9 V& d0 Z9 p6 o - // 多种类型
$ g, b& Y" q) P* M+ ]9 \/ v7 } - propB: [String, Number],
' e2 W9 c6 P) f& x. Y1 Y - // 必传且是字符串6 R0 [, g' b5 N$ b& f2 T# Q& r6 p# T
- propC: {
$ `4 \6 @& f+ k& v0 P - type: String,
9 O& A5 U" X/ { }4 I9 e - required: true
) _/ u# t' A# K - },' Q( K3 N7 T; P, P' v
- // 数字,有默认值5 y2 K& W, _& ^" h, t
- propD: {5 u N* n1 X( C1 f6 I2 q/ H8 C
- type: Number,
* f8 Y9 E0 M( N& k - default: 100
8 l0 E3 s/ C+ ^$ O m - },$ J: A; d9 m3 w( w2 \$ D
- // 数组/对象的默认值应当由一个工厂函数返回
& H- ?- Z5 [- _. _' i# i - propE: {# ]' N8 h7 P* r1 Z5 J
- type: Object,5 c; t V: |7 _) y5 e! c
- default: function () {) v- D& g9 Q3 y% H
- return { message: 'hello' }. E; @% o! z* y
- }7 u& W4 n8 n0 ^# k* T* O
- },- |! s4 e7 q( D
- // 自定义验证函数1 P! q2 J& w5 h$ t8 B i
- propF: {; N8 m, x7 M3 G5 x, z
- validator: function (value) {2 B" Y0 B! L- J' F- h
- return value > 10
" ^ O! q8 r; V& Q" d- l8 N - }
3 w; \% M% k$ y3 \0 A, ?9 B - }; _6 R% ^2 [+ B) `8 a8 }! r
- }6 R" D4 ~; ?& {. `- R7 c
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
" ] f0 Y* l; L: ~+ P) U4 r
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件* x; F7 i( l/ x% k& A0 s8 u
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例
5 h$ m2 e# S( u* r8 c- <div id="app">$ V6 j( g+ u4 W/ ?7 a( l' [. `. ^
- <div id="counter-event-example">
5 r0 Z7 }, E1 X0 ^ - <p>{{ total }}</p>
p) c$ V; u/ k) E8 o$ @9 s - <button-counter v-on:increment="incrementTotal"></button-counter>
[; o4 L- J: l7 e - <button-counter v-on:increment="incrementTotal"></button-counter>0 }# Y2 o# N" b- ?4 X& D7 a3 O0 l) A `
- </div>
9 L0 |; ^( r: w5 @* k$ [3 [+ t/ ? - </div>* L! w, `% y& |2 S+ O. H8 h
-
) N; o( E% a; }& a6 M1 _- k - <script>4 L2 ~ B! R) f8 G
- Vue.component('button-counter', {: r" Q8 K8 _/ W6 f6 k. {0 H, T
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>',2 V9 Z8 P3 R* x- v; k' p- ]% \5 D d
- data: function () { I! E7 p1 t# f# z7 J! |
- return {
7 ?) {! }% D4 B% M. E - counter: 0& s" v! c7 v' b) b( B7 T+ G
- }
6 V4 L' v9 z8 F* a1 {5 F - },' n! ?! |, w2 E) ?" R
- methods: {
$ E6 l4 I+ ]" u4 V0 t - incrementHandler: function () {
% Y4 o# E3 Z& s2 w) Y; ?) G - this.counter += 1
2 m% d) l5 d; r7 t" k - this.$emit('increment')
: j2 O* H0 ^' z0 B+ ^2 @" V - }
" V2 i2 p5 C; n1 U, @& F' v3 ~( d - }," ]% U) p& C: H3 B S9 U
- })
- Y9 E+ r5 l, Y x* C& E+ m2 T% G - new Vue({6 o# y, J- ?" r+ w# o+ y* k( Z4 R
- el: '#counter-event-example',
; ?: H6 ^: R% O8 j, q - data: {- \7 r- z, }( P' } C1 R
- total: 0' J0 X* _/ I- v5 ]5 H
- },
6 @* s0 C2 j/ M- E8 T - methods: {# f: X( v; j1 c/ F- {
- incrementTotal: function () {
% O2 j0 N8 o7 i - this.total += 1
, m7 t2 _+ D7 |$ D- [# P; Z: | - }
$ v: U" \% l% I9 N! q2 \; T9 w - }
- A* G' Z) g; V3 U3 l - })
/ O: ]5 F. q9 e! x0 N0 e! c - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册6 w& o3 v4 b& } b3 n: P+ Y
- Vue.component('child', {
/ H8 F7 ~6 _1 X# r8 {) J; F5 B4 ~ - // 声明 props
) }' R5 j" X# n9 y - props: ['message'],
% s! b. C; ]( O/ J - // 同样也可以在 vm 实例中像 "this.message" 这样使用$ E; \0 j# {' D) J/ x
- template: '<span>{{ message }}</span>'' ^1 V) ~0 g; p) E
- })/ ?. V2 D/ @% ]) u I7 T
- // 创建根实例
4 ~1 ~7 B3 D& M' ?7 t& s; y# B - new Vue({
: H; L4 |% [2 m! z$ p/ E# L% D# V - el: '#app',& e5 E; }. l5 c" `: X
- data:{
, ]: k, z. W; ^1 T' ~ - message:"hello",8 v& p: z4 _! p) J( s5 d( G
- }6 f# R( y6 v/ [: G% O1 Y8 q
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
# L* L8 G$ S- X% L- N7 s1 n$ ` - incrementHandler: function (v) {
$ G' z. p' z( z; {% } - if(v==1){
* L! h" x: b3 X3 s/ D( H* ~; a2 k - this.counter -= 1, O+ r9 G3 d& q$ L, W' f& f
- this.$emit('increment',[1])
" G `9 Q. x& R- _, o8 _% o ]" S - }else{6 Q* b& z5 r' R8 C: @: s
- this.counter += 1
( g! ~4 g, b( }" Q8 j, q8 X7 ^ - this.$emit('increment',[2]) d; E/ g8 K" k) `$ O
- }! k* Z* t' S0 n/ N
- }. O3 j# G4 M# P3 R& m" p
- }
复制代码
- p% f" ` F! H2 ~/ q' ~, Z) l4 l( T% ?- H9 M. r4 D- U2 ^0 Q6 ~8 s
|