组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它: ' i1 m) V3 L9 ^* ~3 v; Q% m- N
- <div id="app">$ P7 g+ D5 _4 Z7 u7 y# K" a. E
- <runoob></runoob>& e K; ^1 _8 Z, R) r6 ~. E
- </div>
7 u; u1 i0 p# s% m2 x -
: b# @; `" G/ ?7 L6 M: W# S - <script>
* \ `- A( M6 S* |8 ?* _9 a, n! T/ Z - // 注册: Q8 E! B7 Y2 i+ r( n2 b
- Vue.component('runoob', {
! t0 A/ N }0 A u - template: '<h1>自定义组件!</h1>'# ]3 e/ L* y0 j* f4 H& B+ D2 \
- })8 V; x1 J, \" \% s- E* z5 [
- // 创建根实例 C# z, j) x1 e9 G/ T& [
- new Vue({
& ~" Q( q; g. m* F# L% ~ - el: '#app'8 Z. l: j/ ]9 D; V7 O9 {, h: R u
- })6 x7 l4 Q8 r# K7 n2 P8 S8 C
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: * t( o5 o" l6 w) }1 D3 y% J
- <div id="app">
% J2 _& [% g( M6 U8 ? - <runoob></runoob> i# f. N4 t, B) f( M! ~# L" X# M
- </div>
7 J+ j# `* C, r5 _; R -
. N! S% _9 k0 C& e6 |( ? - <script>; u7 M( A$ ]8 f9 f( Q u( n3 o+ X
- var Child = {( W3 X" N. t% x: [+ B& Y, [! K
- template: '<h1>自定义组件!</h1>'8 c+ {! p$ L, [9 c; x
- }! _* _$ J) P7 H) n# f0 b( s! L; J2 X& N
-
' \! \' I& |6 K9 n - // 创建根实例" F- b& n8 L% r( q; Z
- new Vue({
z4 ^1 `9 L" U, P2 h3 n - el: '#app',7 }, Y7 F- s, M F% L2 ~$ S8 t9 V+ L) o
- components: {. P2 E: A0 S: P0 F0 I; A* H: h5 |
- // <runoob> 将只在父模板可用/ p! ]5 v7 O* u$ [6 A
- 'runoob': Child
4 a8 w8 U& c4 Z h - }3 o; |" B5 z% g2 i
- })$ Q( l- e2 h+ O
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例
/ j: P" b, h) r2 P3 A k- <div id="app">: X6 N g- z. s3 ]! d& T7 Z3 R
- <child message="hello!"></child>
) I$ W/ R ?. H- X Z - </div>( g8 d6 p" _ t
-
0 [7 G/ a3 o. G - <script>
+ L% c# `+ r- ?( r5 q4 W# J6 Y2 E - // 注册
) g* f# t5 z. m( L7 ]& T - Vue.component('child', {
; g# b4 |& S/ @ q- c - // 声明 props" q9 t; }; }5 x6 P" ?% t- o
- props: ['message'],2 i6 I! v( O# y
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
2 D. m. z( Y5 u6 S - template: '<span>{{ message }}</span>'
3 N* w6 X9 f" L - })5 d/ p i- b' [4 e1 p
- // 创建根实例8 k* | b4 b6 q. ^% b3 A {( w2 A
- new Vue({
9 b; `; B: m7 c. Z' o: ? - el: '#app'4 F! `. E" ]8 k) L6 V
- }): W7 ]+ ]$ w1 f' `4 \5 n0 y4 a
- </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例9 j7 i- { O+ @4 j* L% N
- <div id="app">
; R" p6 L* c# V. t - <div>$ y1 D1 Z5 y$ Z
- <input v-model="parentMsg">) t7 L0 z$ E$ k$ N
- <br>
' E8 h2 Q( q9 k8 c. g - <child v-bind:message="parentMsg"></child>- K( J6 F2 z: f
- </div>( `3 U2 F( h6 e- G6 h. S/ Y6 }) s
- </div>
" P# H) ~5 t! M5 D4 }/ O) v: X -
! Y- m$ c& v! Z) v6 Q* `8 | - <script>
3 L! t2 Z2 f9 F2 d5 l& d; V+ e - // 注册
$ h3 M- R$ j7 R1 ~ - Vue.component('child', {0 ]& w. l+ z; v( v. b) ?% l
- // 声明 props+ _; ^! Z& l2 f! o: ~5 C
- props: ['message'],
6 J5 F- I+ G+ h' u- k - // 同样也可以在 vm 实例中像 "this.message" 这样使用
% f# B" o. e* Y5 \, Q( n; ?3 L - template: '<span>{{ message }}</span>'' A2 W' N7 H. Y* Z
- }): N; J9 |0 |( J" v; N! y& c
- // 创建根实例
3 p( R6 p% k: ? y& k - new Vue({8 ?+ M: O g# k0 d6 G5 U% L3 l2 @6 m
- el: '#app',6 a& a( m. T6 h' S% d# A( ^+ w% J
- data: {
) h; J/ [; C0 S* z/ r4 w - parentMsg: '父组件内容'2 q2 M) |8 U/ M
- }6 t a9 B2 f; q1 k
- })
V* m; J3 `9 g8 I9 R* y$ P7 o - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
2 i5 n# }% I/ O X. ]3 n5 L& m- <div id="app">
( A# B! l/ \1 r* [' Q - <ol>% i' n6 O$ K& I- L
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>) K/ @' `. e" s5 H. H
- </ol>1 n; C6 \' H4 o, G% Q* C
- </div>
# a5 v" [7 R4 {- E6 ]1 \; ~6 g - + m8 ?, Y `9 j' M: p3 @* ]
- <script>
5 K5 C9 g' S- F- Y! n" Q8 E - Vue.component('todo-item', {
; H! v7 y. B1 P3 D$ E& b# R - props: ['todo'],0 f( y" c3 k3 Z4 V: E4 K
- template: '<li>{{ todo.text }}</li>'
+ d3 c/ D7 M6 C" l$ _* v - })$ \7 t: a$ G. Y* B1 ^# k
- new Vue({9 v, ~5 ^: |0 o. x
- el: '#app',
- j) B8 r8 ^9 U6 f: k; u - data: {
: Q" b! Q3 Q" C4 O1 k) U5 ^; r9 k - sites: [
6 ~1 F9 ^. @3 V - { text: 'Runoob' },7 i8 D8 M: i) Y$ |$ P
- { text: 'Google' },3 S: j; }7 X$ Q% g6 h* g' ^# P
- { text: 'Taobao' }
& D! x# w$ x, l8 Z - ]
+ T0 ?" {+ E( Q+ `' h( p4 o - }7 c M" j4 J% v9 ?0 {6 C {
- })# x7 z8 q( U% ~# t. q% }
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', { a' ? T3 g9 j3 U% C
- props: {5 J& S# o: ?- M4 _" j7 E; D
- // 基础类型检测 (`null` 意思是任何类型都可以)
- Y& L" v+ u$ I7 @" v( Q6 O% ~ - propA: Number,9 T3 T3 w5 ]$ X- p6 D0 Q
- // 多种类型
0 ?# T* Q5 ?0 S: q - propB: [String, Number],
' e2 d- `/ _" U: l& k* ~6 M - // 必传且是字符串+ k7 x. v3 @! Z0 N& O
- propC: {$ U8 ~; B1 v1 ^% w1 ?, z" T
- type: String,' \+ l- X1 w) m" a+ t
- required: true
$ b+ D' Y ]' L) X - },
8 p% S8 C% K1 ]2 G5 p$ P% k - // 数字,有默认值2 m$ L: u2 E4 w
- propD: {: T4 }! d5 O5 W1 N
- type: Number,
3 a2 Q' m9 k8 n - default: 100
$ w9 ]7 }9 s( D( D% n) ~ - },9 k* G2 ~: t0 m" ?& v: S9 \' L
- // 数组/对象的默认值应当由一个工厂函数返回* u4 c: D8 e: L. v5 e6 D: v
- propE: {/ q8 X; {* G. C( j9 _8 t, C
- type: Object,
& u6 E& Q" H3 x, C - default: function () {7 f5 J( U3 R7 U- T; g2 q7 J
- return { message: 'hello' }6 F* f( n- f% H" j. x
- }
/ }- s/ T! [+ E# F1 B9 n" L8 I - },
# J+ M* G: |" I2 b; R. u O+ e3 T - // 自定义验证函数" V: O( W* c; I- \3 P$ g. t
- propF: {
1 b& D1 i5 y6 c: e - validator: function (value) {, S- d9 l8 S" P; B# S5 K
- return value > 10
) \" C$ v0 K$ T' x: ~ - }
% }) ~( I# O4 f3 ]( e - }
* p5 y% c4 x1 v( O7 g$ v8 `$ w - }
2 n) Y! N3 X9 ~8 L) T2 ?7 M4 Q - })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array/ s- Z( p) q2 e4 p
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
! {: _& A* U& Y# p U
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例; |3 o4 \* {8 R Z5 n3 a4 n) h
- <div id="app">
+ c( R2 y/ `: Z/ ] - <div id="counter-event-example">! Q# K: A( _, m. ?; E
- <p>{{ total }}</p>
& U7 }. D, D% [6 e& C - <button-counter v-on:increment="incrementTotal"></button-counter>
' ]- H0 w* ~" O4 B1 m$ j$ H - <button-counter v-on:increment="incrementTotal"></button-counter>
. u$ r" k0 s7 ~# }; _% d - </div>
# h4 H3 G3 Y M( B - </div>
+ A& p# b7 U% o" [8 l: @ - % y' l: t* i- ?" l+ C
- <script>8 R# z$ z* c, [( }6 d+ u+ @
- Vue.component('button-counter', {0 l0 A' M% h/ U0 X+ h% _' C
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
7 ~7 D4 q' P) q - data: function () {! E! n4 g9 i! |" X J2 ?' c! N/ @
- return {4 @# f8 o6 t( K: {& Z
- counter: 0
% |+ v, R! g' _7 @0 b - }: X( k g6 q1 N# V& r1 [9 ^7 a+ ~
- },
) u3 e& O; X+ { - methods: {
* O, j+ j! z4 S# p7 p3 S7 G - incrementHandler: function () {
3 V8 d& k4 W, w# x' H7 o# R - this.counter += 1- L* b( |$ x% j) ~) M: |, e
- this.$emit('increment')
# z& d3 ~9 F2 S% r5 k - } ? x. }# e) u
- },7 a* @* V( [0 z' R8 b% G( e
- })' Q9 `4 w4 l: a
- new Vue({
9 ~6 [/ b6 H4 Q3 q: T$ K# g - el: '#counter-event-example',
: n. Z% h5 K# v" b# U/ p$ p - data: {
6 l+ b3 [. u' J1 F$ e: q% e - total: 04 F9 {9 t1 o- E/ A( P; r
- },
/ Q- ]/ D$ e. H2 K- o* H - methods: {4 [7 s2 `* N7 X
- incrementTotal: function () {
' s" g9 M7 V- z+ f) ^ - this.total += 1
T/ X8 Z/ o9 b4 u3 s - }
' s0 w& ?( N$ B& a e7 I9 A - }. _+ M3 @2 |# x/ q! D
- })2 `+ E" {% ^4 p& n; E- P& _3 j# _! o, d }
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册5 u; Z( L' J. |: x! t( O# {/ @
- Vue.component('child', {
6 H1 H' N& C8 F3 w& z - // 声明 props
- [% w& R0 n) d$ ^ - props: ['message'],
- @1 `2 N5 m1 S- V - // 同样也可以在 vm 实例中像 "this.message" 这样使用! n1 Y3 {& w/ S
- template: '<span>{{ message }}</span>'7 V) R* G8 V: ? ~3 M
- })
% {% f c, k! W7 Q$ z5 o4 F - // 创建根实例
. A4 `/ v" n0 Z+ U) P7 x - new Vue({
* f! W; _1 d& L( b0 J. f2 [: M |+ Q - el: '#app',
/ p' f5 X' @) ^( {* W, F - data:{7 H3 p* \0 ~; i
- message:"hello",' {- w% D/ R8 F" h5 h
- } I) a: u0 E/ B1 N i
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {7 b" E1 [, r2 q+ L7 m; a$ S
- incrementHandler: function (v) {- d9 @, b3 f6 F6 z
- if(v==1){
% J# y w& h. R2 K( d - this.counter -= 1
& r8 ^+ \3 ^8 u3 o - this.$emit('increment',[1])
: q) W* P/ p( \/ W$ M! J8 K - }else{
/ w( ^, g4 z4 z* I; j; q - this.counter += 1: `( v3 V: p m. s8 A9 ^, E
- this.$emit('increment',[2])5 \" p+ H) L# ?0 Z2 Y% e6 `
- }% _+ F+ K! N5 m4 H/ ?4 u# L% L5 d8 F4 Z
- }
' Q3 @0 R1 H0 Q( @4 ~8 p: _% Q - }
复制代码 0 H, O) L; x% l+ `( a
" H" Z# n+ g- @* l4 a" C |