|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
2 Y, m2 A6 F/ f$ O/ |1 h+ r$ k- <div id="app">$ T# l8 e% Y6 \ T0 \& R
- <runoob></runoob>$ d/ _- Q* }( H+ [' Z [% t
- </div>- h9 z) M: I* b0 r
- ( Z8 d9 ?, i7 `5 U/ L5 X% C% x2 P
- <script>
8 T; V3 e/ d- S% S- N - // 注册
% F; w8 K$ P' f1 [6 q Q8 G/ H+ U - Vue.component('runoob', {
( j4 L# E3 S; r' m9 y* I& z - template: '<h1>自定义组件!</h1>'% j; k' ]" `' L+ s7 U
- })
6 {" d9 r" ]$ ?6 B" Z" W7 R+ ^ - // 创建根实例2 @$ z0 A" e9 C2 K! s
- new Vue({, x/ b# ]9 o+ Z( O/ ?6 f
- el: '#app'
# T2 \7 t" ~( M1 D) d9 s1 s: T - })
: d. y. W) u% ~6 B* b" P - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它:
' z# N+ m6 S( Q6 q. a5 p$ t" V, @. ?- <div id="app">
6 |% x# l5 j7 q- H, z% T# N - <runoob></runoob>
" ?. A* [4 `+ U& p - </div>
, ?( t& O, X6 N; V* U -
# S* b6 t" E, k8 k1 M - <script>
6 S5 e+ R5 Y0 L& m* m0 ` - var Child = {1 y' f7 h: @9 W) H( P3 u" \ U5 N v
- template: '<h1>自定义组件!</h1>'
+ i- g7 ], U( J7 {" b - }
( v6 z: b; [0 ? -
' |1 K+ x8 l$ Q& I9 E) ^ - // 创建根实例
# j- X9 v) T. u9 F - new Vue({
8 d8 y' v. ^8 c2 B, Z - el: '#app',! V* R4 @' e, \8 E4 k# p( P
- components: {
7 e4 i1 f) C+ f" f) r& ~ - // <runoob> 将只在父模板可用
( y& H% X2 \8 @/ O5 S9 l+ J - 'runoob': Child
8 e2 p4 l& u+ L; w - }' }: Z5 }1 y0 _8 x, }
- })+ k, B1 x s- O+ D" h& T1 v
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例
$ Y8 |! @6 w& S: n, \3 @: g* T- <div id="app">" Q+ I- O/ y# N% I( J2 h$ y* N
- <child message="hello!"></child>
: v/ _# o3 z: N6 B H5 V7 a" B( L - </div>8 Z6 a& g t i4 L% l& e8 P
- 5 Y- L- L" k/ o# R( I0 f5 R
- <script>$ u0 X- e6 K3 I. r/ m, h4 x
- // 注册/ g) R1 v4 W( X/ \- R6 L7 t
- Vue.component('child', {
$ D; p+ ?4 n: @ e% y+ ]. r' B - // 声明 props
0 `3 H: J3 t" s/ B" y4 W. | - props: ['message'],
0 X0 _5 e- F( F1 Z - // 同样也可以在 vm 实例中像 "this.message" 这样使用
8 o6 g+ H! [! [( M+ T j. V' r - template: '<span>{{ message }}</span>'
$ m* Z8 t9 T( u - }) g( i) I( R% v' J7 e5 T S
- // 创建根实例! W6 p6 O9 t1 z
- new Vue({) e2 G- N8 c G" t
- el: '#app'4 ]( D, \, c. K" z6 s% o
- })
7 B$ ?7 q3 c& S: b, e% z - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
; @# s: g9 D1 Q0 {3 I+ A0 Y% b, Y- <div id="app">' {/ @( g5 ?# W3 R) P! K
- <div>
* C0 ~# N6 k% n, {' L8 w0 ?! q - <input v-model="parentMsg">
4 n5 ?5 }) d! k - <br>* N4 E, e7 r( p4 w$ A/ |2 ^
- <child v-bind:message="parentMsg"></child>+ C# ?1 M4 o( u
- </div>
% z# i* g4 M, P, H k; N - </div>
& }3 w0 v6 j' M2 n2 | -
( \ c2 c f# s - <script>
% e3 Q J e. Y. ~ - // 注册
1 B1 r/ r7 d8 y' ~" j - Vue.component('child', {
7 u3 O; m% U e - // 声明 props
: Z0 H3 v- a; b! x5 G H - props: ['message'],
/ T/ m( k) K; \7 j+ D8 ]' b - // 同样也可以在 vm 实例中像 "this.message" 这样使用
) q( w6 t0 L: V$ f9 T' \$ B6 R; Q - template: '<span>{{ message }}</span>'6 t, c7 _. ?9 c0 Z* ^5 V
- }). ~9 u" @! | v- n/ w8 s& z
- // 创建根实例( ~# Q( V( c5 z- v& i3 ~& i0 `* l7 N
- new Vue({
" y! o# H0 Y& f4 Z' X( T - el: '#app',
) G+ d+ ?! u6 N4 d$ R - data: {
; ~) k9 x" Z% g9 r; C - parentMsg: '父组件内容'8 @) c% J& D p$ |! o! B
- }6 d8 W, j- l0 C. R2 {
- }); D2 M) t0 ~6 F1 X2 g
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例4 h4 p. A% W; U) u; a7 a0 ^
- <div id="app">
7 e6 Q7 {. F- s4 C3 |2 R - <ol>
. U" y" j. n/ B9 B7 H - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item> `+ t8 G) O# q) N7 c, S! }) G0 L9 K. `6 n
- </ol>
- z* O" W9 R* j, c1 W5 w - </div>: H: [" P" @/ E/ d/ W9 }
-
' e, o8 A- |. U+ ?# A% T - <script>* K7 G$ V$ I( [' P
- Vue.component('todo-item', {
0 |1 C$ Q5 ` D h - props: ['todo'],
# ^6 b' }# Z/ Z; e9 E p1 M - template: '<li>{{ todo.text }}</li>'5 C2 t V% H# g! k
- })% C; o: V/ d) O
- new Vue({
: A" @8 d: u' s x ]$ J8 T, W - el: '#app',
% R0 v8 l! J3 u - data: {
; n @4 y/ C y% y, M, c( B - sites: [
7 u" L0 R9 H) _* j - { text: 'Runoob' },
3 w7 _( N; o V4 d* K% b' @0 } - { text: 'Google' },
- ?5 M; r/ V2 j0 d. `4 R; b - { text: 'Taobao' }
8 Z* J7 y: w2 l3 W - ]( h, w% h) U, F7 J8 o3 q
- }2 T( d3 H) |# R* y9 p' M
- }); G, D9 B& y) T9 i2 \- [& L+ n
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
( P: q$ I {+ H5 V8 ^- m8 @) u - props: {7 t7 y+ j3 T( J. [3 c" j
- // 基础类型检测 (`null` 意思是任何类型都可以)7 G9 @$ C+ d/ @4 ?+ G- N8 r
- propA: Number,
) @- H* q% O i. S s' B - // 多种类型
9 } I& u2 D6 B' F F - propB: [String, Number],
' U; l* T( F4 a7 t - // 必传且是字符串$ ?# w$ M1 \% R7 _! W% a
- propC: {$ o- I# T! h# x
- type: String,3 C2 K2 m F/ \* r7 X$ }* @4 x
- required: true
( k) R x1 Y4 a( ?* H% ?4 P% V+ s - },
& \; {- e- w- ~& L' O n - // 数字,有默认值
2 }+ B# O5 B/ {' M - propD: {
& h; s& J& G! X/ {6 b - type: Number,7 A! u) N" i7 e$ A& w" K( R( E# P
- default: 100
& U+ |7 Z. X7 m - },
) x. `- ]% @8 f% n: ^ - // 数组/对象的默认值应当由一个工厂函数返回! ^0 W u1 Y$ C9 d; N7 [
- propE: {
- C8 H+ a5 @/ R$ C; K Z; n - type: Object,, t! M7 C- \% v: R ?- H& f) K
- default: function () {1 J$ Q, F: L2 {) K
- return { message: 'hello' }
: s$ w1 ^4 e, m$ J& b - }
$ G) [+ ?: [5 c* p% V/ L - },
4 M c7 v) w8 Q9 ?9 u - // 自定义验证函数+ X q* Z* X4 M' M0 p
- propF: {
' p9 \7 @# f- j, J( L! k3 p - validator: function (value) {
7 E5 ]5 c! W6 q0 w+ n! t1 O M - return value > 10, c% b' h8 O e3 E2 v$ P( K2 c
- }
; q9 z r4 K( N2 a) E - }: s, r8 S1 ~: F% x" z
- }1 v% ~$ [ f* N$ w
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array6 B4 L- u g" E( z5 x6 [
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
$ I; D& f6 w( V
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例
. ^' m. F: c0 O- <div id="app"> m8 c0 A/ ^/ j6 `3 [4 N' o; i
- <div id="counter-event-example">* h7 U, S7 H5 q, e; }
- <p>{{ total }}</p>; r+ D6 I; k) n8 [/ P" F
- <button-counter v-on:increment="incrementTotal"></button-counter>
: O; L) E% ]+ u' A3 Q - <button-counter v-on:increment="incrementTotal"></button-counter>
. W) Q8 u" ~9 ?8 M+ h' G6 I: s - </div>' e q: X1 ~1 f" h9 }3 \# F
- </div>+ C9 n" W5 b/ Q1 Z& i) _, ?5 R
- 1 i# [2 \9 o8 p
- <script>! _" D" Y! S$ H6 A+ [8 V# ?" I
- Vue.component('button-counter', {$ s0 ~" h0 T; s% K4 \
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
$ w$ {2 Q6 O Y! ^( v8 r - data: function () {' d/ n1 U. e/ t" W3 k
- return {
C2 @* r2 H) ~ o# z - counter: 0
, y6 W# F- c; }1 {, v - }* Q0 O$ a5 P; D! w: S3 I. M- w
- },
+ u' J" {1 e0 h* j9 P& ]% j - methods: {
" e, d$ v4 ~3 ]0 w% F6 ^; d - incrementHandler: function () {
% l" J. @4 r* I% w9 M" { - this.counter += 1
% U, i. n' c8 h1 D+ Z - this.$emit('increment')
0 {- [, E2 e8 Z9 V) V - }! W$ ^- H6 S/ s6 Y) F( ` q Y" H( O
- },
6 N: ?0 U$ j" i& n - })
* R C# q7 C* P! I; r - new Vue({
- v# m, M* T# Z - el: '#counter-event-example',
8 B- K4 T* s; N( A5 u0 [& W4 M - data: {
- O- g/ B7 O4 ^ - total: 0% J( B- c! K5 Q8 Y$ u' |
- },& z- E) Y$ T s3 m% o
- methods: {
W6 h8 |$ Z7 Z( p1 q& D9 | - incrementTotal: function () {
3 c2 m6 D/ L3 T% r+ J6 p& M; P - this.total += 1
9 { o+ I& i2 D+ |: D; d - }
4 w$ X* M, {9 K* g+ j: W3 { - }
' V: J, E7 O* f# u: [- E - })
+ \. @1 O3 p8 L6 G( i - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
6 t- O0 c" I5 r; q' b - Vue.component('child', {* _+ u* w5 R+ n' {! O7 R
- // 声明 props
& D1 {: ?* t) L - props: ['message'],$ w% F1 `9 d t* ~# g1 q: b+ V/ g
- // 同样也可以在 vm 实例中像 "this.message" 这样使用0 P; g% Q% K7 t& h+ X! K
- template: '<span>{{ message }}</span>'
0 { p+ f3 q. B( G* r8 _ - })
$ E) W; _) d2 Z- z9 s4 t - // 创建根实例& p; [7 j4 k2 i8 R t
- new Vue({
$ n6 g* _% g4 u3 E - el: '#app',: x8 ^0 F* i# e% J/ O
- data:{
1 @+ B; W8 F) z, t1 g - message:"hello",
( @. N. K1 j- A8 y - }
% w1 M# d% Y+ p( ?% j! H9 } - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {9 m3 E0 `+ w* Z/ Q& ]) c
- incrementHandler: function (v) { Y% C; c$ x, W! E
- if(v==1){
2 L3 n1 J3 v4 a* S+ L9 |0 L2 B - this.counter -= 1
5 M- A# X$ a8 V1 _: a% v - this.$emit('increment',[1])' _2 S3 P# j7 V9 b2 @% \6 f _, q
- }else{, e; i- [3 S6 D4 a# d% [1 ?
- this.counter += 1
/ {8 c' o" T" R' x# B5 J - this.$emit('increment',[2])& h- @ W( }- L) G- `: ~1 M
- }
2 ~" I4 U4 x, d8 p - }1 n6 E* ]; R+ j) z
- }
复制代码
& s3 ? K+ J' L) e+ u& e5 C- A5 U; x& n7 p+ P& K
|