组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
. o& R5 o& j0 T- <div id="app">- L8 p* K0 m; O8 X
- <runoob></runoob>
6 n/ X5 k, @+ Q - </div>2 |, f! w8 x( J1 U/ |
-
% B& ^+ w. _* c% _ - <script>
3 u2 t! R3 o6 M4 L - // 注册
, @/ F8 W7 {. V, W& N - Vue.component('runoob', {$ d% L4 y3 M. _# r
- template: '<h1>自定义组件!</h1>'
' W2 o5 g2 o3 t R - })
f& |1 V# C+ E( J; g7 C. z - // 创建根实例
1 S1 X, |; T, [ q& | - new Vue({1 z1 I- G/ C8 o- d* a
- el: '#app'$ {/ H6 g/ y: Z7 e% P5 @% i3 L0 T
- })- c( j! T# \$ K+ E" A
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: 2 Y7 t4 n- v ^- C' t, e# U$ v7 Z
- <div id="app">0 a" z( @& `5 m: C# @
- <runoob></runoob>* W( r# H$ R) r& J) M
- </div>& M. s, s3 t7 [0 S4 r7 D M( o
-
1 ]4 O2 x# y- y" H! i& l - <script>! s/ X' w2 h! ?7 F. \
- var Child = {
4 _6 U- Q& P6 ?% `% Z - template: '<h1>自定义组件!</h1>'3 a" |* d" L1 P( J
- }
9 ~# h' J3 t/ _4 L( K1 i - 0 ?% y" b8 M! C. h# _, A% ?+ K( X
- // 创建根实例
# ?. h6 }3 c5 ]* J: D; p4 c - new Vue({) s/ A! F$ _+ ^& B) d# I1 K2 q) |9 C) ?
- el: '#app',
, ~. {) b& W$ r W) _1 ? - components: {$ c) \2 u; l* Y0 ?% l/ ?
- // <runoob> 将只在父模板可用
! U- O4 B+ g [$ y( C0 @ - 'runoob': Child: `- P7 |0 q3 ^9 k# E7 P: @
- }5 G) a8 K& n9 G" P. r, h
- })
$ Z' D# a+ f1 {9 k6 B - </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例
9 j* A; Q. B+ a3 I, U- <div id="app">
) O6 i) ^6 s5 z" {' Z - <child message="hello!"></child>
! R* |* E' X: @% b; Z - </div>+ Y* `, d- [- \( |& l# Y3 A
-
6 D6 k$ Y' T' e- \ - <script>
* Y2 B. \9 \: X+ Z4 }; o - // 注册$ v& K. o9 w1 s; S) t% B
- Vue.component('child', {$ m* m& |4 L I
- // 声明 props
( {, E/ h* @ } y - props: ['message'],
# W( }( P9 } ] - // 同样也可以在 vm 实例中像 "this.message" 这样使用' S; ^, G f4 E ^$ A. a5 W
- template: '<span>{{ message }}</span>', Z P& j, Z8 m; h2 T8 Q$ ]
- })2 N& Q, x" G; i/ ~5 A
- // 创建根实例& ~3 q" \; |# O$ _
- new Vue({ `+ i* F6 p0 ]4 m) d [6 \
- el: '#app': q' A# O; @, y9 I" q8 L( K
- })
( o7 G* s% J! h% O9 C - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
( {4 j* K3 U9 i- <div id="app">
( B" i& I9 M% P H9 B8 j5 B/ ^ - <div>
1 e( e4 x3 b3 d$ G3 ?3 v - <input v-model="parentMsg">& w$ [* p& m# u8 N( e+ q5 a9 D, o
- <br>: T; c6 O1 ^) V# z) l% S
- <child v-bind:message="parentMsg"></child>9 X# H- C+ i" `
- </div>. d0 `( w0 p9 v, B0 I2 \/ i3 @* Z
- </div> i* ?: q% U9 U' w; L
-
7 ]3 K6 S# z4 S - <script>
& Y. S# C) r4 A0 w# A! U - // 注册
$ C- X$ h, K. u1 g# |+ P - Vue.component('child', {- l, ~/ a% u7 j: w
- // 声明 props
- v8 A1 x7 r" w9 J; |; K: z0 H+ X- J - props: ['message'],
: N5 z/ s/ c6 e! x# u/ s - // 同样也可以在 vm 实例中像 "this.message" 这样使用; x/ s& \; \. ]6 ~
- template: '<span>{{ message }}</span>'( M% C- l3 i6 T9 G
- })" H5 f' V; `. X" p a
- // 创建根实例
$ S; f' h3 s1 Y0 J5 Q - new Vue({
: X% C/ m9 K, Y J% z - el: '#app',
H* {3 I1 T9 ^) D! A - data: {6 z! o% b! P( p l
- parentMsg: '父组件内容'
& ]7 W. A9 j! @% @; x" b- a - }" x9 I7 w. I9 }& e' p
- })
3 M8 f5 J! W; k7 C' C - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
* Z, y* ]8 r, ]! [. b- <div id="app">& }0 O+ A) p( R$ H! ]! X. ~# z
- <ol>
+ j# a* x+ {% R - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>9 Y* v* ?! i& B8 X0 D7 q
- </ol>
7 a$ x" {: j$ Q D* ~- v2 L - </div>4 v5 [# p# `/ }) E
- : T6 @" X' R- I- U
- <script>
" Y. @# _# z& ~* E! X& d - Vue.component('todo-item', { T, }7 n" s& U, d" h2 q
- props: ['todo'],
4 ^$ c, }+ F1 c - template: '<li>{{ todo.text }}</li>'* Q9 O6 a* \. d# H* S
- })2 M: I; {) W2 y. Z; v2 q1 y) i! A
- new Vue({2 Y' R2 c6 Z3 @3 ]1 O& S
- el: '#app',
4 i# F1 f+ V9 ~3 K - data: {
7 O: P- O, v' Y9 @1 f - sites: [
6 J$ r7 f" l' b! Q - { text: 'Runoob' },9 T8 H0 F. J) b" S& H s
- { text: 'Google' },
, O* {& N8 r) Q - { text: 'Taobao' }$ S% {1 {- n- {) w4 l8 x' l
- ]; K9 O$ I% \6 \5 i
- }( v" W' V k2 S0 _1 i. \) `
- }). Z8 l% W2 }4 K1 l I3 m4 ~" ^
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {9 G% p4 W4 | N8 p' b
- props: {: c9 j0 w( a0 P
- // 基础类型检测 (`null` 意思是任何类型都可以)
/ w0 I. `( P# r9 H1 V( L - propA: Number,* S3 ^$ h5 N7 O& L/ b! `2 k1 G' ~
- // 多种类型8 ^ B C: ^6 j' s7 A; t9 [
- propB: [String, Number],: _ k$ a& `0 o/ I" @$ a
- // 必传且是字符串. w& W3 t E! |! }2 ]8 A
- propC: {+ C2 B& v4 V/ i& X f
- type: String,
; m5 U9 s; j/ y# X, v o3 Y - required: true
& Q& n% N) n: }/ y - },. N! f/ N# K+ X; r% M
- // 数字,有默认值$ ^8 P. A; _& ~, i5 C0 m' a, Y$ I
- propD: {
. i. P1 p3 Z. y2 n& y - type: Number,
: [2 o0 f* g3 ]* h - default: 100
6 `% p5 ]/ ^3 p% |/ l9 b+ i - },& E+ u) P" E6 \/ K5 C( m3 l3 ?
- // 数组/对象的默认值应当由一个工厂函数返回8 U) z; `' h4 j5 Z' I
- propE: {
- q7 T2 `. F& x - type: Object,6 ] t/ H% [$ T" z7 C
- default: function () {
$ V) b) R( ?, F: n0 }( ~5 b( _ - return { message: 'hello' }
* ?) ]4 j0 e; E, u - }
+ \6 w) Y( t ^# h - },2 k: E4 v# @) {6 l/ ^# R, o) l8 N
- // 自定义验证函数1 P7 O$ t, @9 i
- propF: {
2 Y+ p$ N4 h) Q1 z V - validator: function (value) {+ z& n0 g4 L7 T1 ~ k% Z3 T
- return value > 10: E. R6 F2 Q3 ~0 Y: t' `: ?; Z
- }* ]; O* z9 J8 W2 q
- }
2 `0 }0 `0 Z9 h; q - }% p; Y( {) A k9 @& _3 y: s% a& [& f
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array' \8 `5 b5 C# m2 |
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
/ a1 |8 q7 S! z
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例8 w4 k& V/ o- D4 \* o6 R
- <div id="app">+ Z) u/ b1 P7 S( G9 N5 b
- <div id="counter-event-example">; _' B& T' H4 @, ^0 [3 i
- <p>{{ total }}</p>( \4 y7 O p! ~) H# A; o
- <button-counter v-on:increment="incrementTotal"></button-counter>6 Q3 t8 R& _4 n) W
- <button-counter v-on:increment="incrementTotal"></button-counter>
5 |6 h. i8 Q2 {6 M - </div>
' y- g: U' B( T4 e - </div>& l5 i& a a3 j( M9 o
- - C8 H0 v. Y0 p
- <script>
% I, U2 ` U( e, B9 ^! q - Vue.component('button-counter', {1 {! q( F* Z5 A2 V- w3 l
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
# p; [; u' ~! f- M1 k - data: function () {5 t" z m. n) }4 s" }: Z3 D% ^
- return {2 ?4 S. s4 X* t, u6 [
- counter: 0
* R( A0 L. M; j! Q( G" \ R4 q. H* L - }
7 U2 b+ v! `( [8 N, e6 G. j - },/ x# Q) T; c8 @. ?. o8 m
- methods: {1 l# ~# E+ P; ~% f B6 \* K
- incrementHandler: function () {0 N; `( L9 O* [" A9 T1 g) O! F
- this.counter += 1% D# }$ }- Z$ D+ x# P
- this.$emit('increment')7 Y1 ?3 h. b' W5 S$ K
- }
" E1 y% j! Z% O - },
4 F, p- n; {# E - })
& F2 x' T- m$ S! | - new Vue({
) S0 p) l( |+ ~& [ - el: '#counter-event-example',% `# R, B- i% b
- data: {3 E' q7 a1 C# p# o+ F9 g. R
- total: 0
/ u- {8 m, P2 w' b2 K3 {9 O/ S o( A - },
' Y7 _7 b1 C6 d - methods: { q5 b2 Q; b* z( Z2 l
- incrementTotal: function () { y# d+ D8 K- s( q
- this.total += 13 ?* \. F" p$ ?* Q+ r
- }3 U C4 k( J8 i$ N0 C
- }
9 o3 [; W" u h [; s - })
3 L( x3 A: L( b - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
1 [+ w" T$ W$ `$ m - Vue.component('child', {
& N' H2 h/ q; O% {9 x1 Y0 c( r - // 声明 props2 L4 R$ t2 s+ z) n2 i4 a
- props: ['message'],
1 ]9 s i2 }7 y. q6 n+ ~$ Q0 \ - // 同样也可以在 vm 实例中像 "this.message" 这样使用
. S5 t6 L, u! c+ Z - template: '<span>{{ message }}</span>'
l; O5 {" O q- B* f/ o - })5 s2 }! F. q; \; u
- // 创建根实例
+ _* r9 R3 E4 Y/ R - new Vue({; ?$ m/ U8 `2 J' @( l' t5 ~
- el: '#app',
1 P2 T7 [- q3 }+ l( E g+ P - data:{( {5 Z0 O0 ?1 a9 J3 w( e% A
- message:"hello",3 c! `6 r" U, J# K H% r6 p6 ]( C
- }# U5 i' K# q, N8 C! a& a( g' a# [# ^9 b, W
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {8 k! q: `, T' f9 G+ b! y1 w
- incrementHandler: function (v) {+ `3 V7 ?; {6 X% C
- if(v==1){
0 I( q D! L( Q. O" l - this.counter -= 1$ Y# V: A* d9 z1 s% Q* W
- this.$emit('increment',[1])
( c; [( O1 T4 o. p. c! b8 K - }else{4 L' _* V8 T" _2 w7 p
- this.counter += 1
. {! n! f$ J& w - this.$emit('increment',[2]), N( g T4 _. k1 @, g( {" q! l
- }& G: Y1 L' C# T5 S# S
- }
) p3 m0 Q7 A) W0 a - }
复制代码 " ?) F: |; E6 w- E
9 g0 h3 [, ~4 g0 J
|