|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
) c( s9 C0 H2 `& P6 Z; l( c- <div id="app">6 g/ j1 q& h4 L* w M7 t0 L
- <runoob></runoob>; C3 y0 r! P; @/ ]
- </div>
% }4 Z$ {; s# o- I" {* E -
& W1 F, b2 V0 D - <script>* S2 }6 C: f# Y/ f- S7 h
- // 注册$ C) t" Q6 D- @4 n
- Vue.component('runoob', {% Y/ N1 b3 ^& C- O4 \
- template: '<h1>自定义组件!</h1>'
4 Z9 ]1 G6 g5 x - })
$ Q2 y& V2 d( }1 y - // 创建根实例0 I/ b+ B( f: M( e, k3 w+ v
- new Vue({5 D2 N$ ]4 s+ N4 R. Z
- el: '#app'
1 ~5 x8 P2 t3 y) y) } - })) `: y# o+ M! `& t0 K9 \
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: 9 e( T+ L' N+ f4 a3 U* F' y
- <div id="app">- f( b5 a# O+ A9 k! r; _
- <runoob></runoob># J, B+ P0 E. w6 B6 z3 S) J/ `
- </div> n7 e+ j' U8 V7 T A `- z
-
9 X( O6 w: q- b/ l, x% v( y R - <script>
. ^$ N- b2 P8 E5 `! k& ?" G - var Child = {0 q; Q, z& `$ V. I; z# p
- template: '<h1>自定义组件!</h1>'$ E J' X8 ~$ k6 l+ W" X" A
- }+ A, t9 m- N! N1 K, z
-
& V0 W0 {* M: v8 Y2 y: z- ~, B% M - // 创建根实例
E: j6 O4 A' Z Z Q - new Vue({9 V" A$ b8 ]1 D$ L0 O R& b! m
- el: '#app',. v' o" R5 M& V: Q* {8 z# ?
- components: {, ^& \' o F# F
- // <runoob> 将只在父模板可用, v; s5 S8 \! ]3 u0 O6 [
- 'runoob': Child
9 ~- k( w2 s9 K! Y - }5 ?: J4 w4 L- A; i: I! @9 }8 e
- })' @" y- N- O: |* _5 G
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例, `& V) |, x, l& g7 i/ P1 j
- <div id="app">$ Q- F! }6 x: p+ h o% y
- <child message="hello!"></child>$ B8 Q/ W" X4 ]. c
- </div>
! `* m. a% G2 T - W: e. z# M, R1 T5 z1 A
- <script>! W6 z" a* h0 ?$ @
- // 注册& z* d7 m2 ]1 p1 ^# T% b k' V) R4 {
- Vue.component('child', {# Y4 }1 J! c2 `+ \" {2 F
- // 声明 props
8 J1 U( d2 Y8 Q# g6 @* ^ - props: ['message'],3 R" J2 u! X( W
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
2 l( q: P- P7 O: L, N - template: '<span>{{ message }}</span>'
' Y. y0 o. g. p: |7 ~/ K9 U( P - })$ r- ~8 V9 u u7 z
- // 创建根实例1 C) H4 Z& a$ O
- new Vue({0 A% N" q5 u0 w; w( m! q! M
- el: '#app': h- Y8 J& @- M# h) E/ V V
- })) S* x5 O4 u& F! L- B8 T' U
- </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
8 v2 W6 d4 S2 H% L8 V, T- <div id="app">
! \& p+ ^# o9 E2 H5 ? - <div>
- |+ R1 f5 U5 F$ T" ^1 f; G - <input v-model="parentMsg">
$ B! }- c1 y U! ] - <br> L: i( Y* E4 Z3 \+ q4 W1 f
- <child v-bind:message="parentMsg"></child>1 A' w. C( V% E
- </div>9 j) ]# ?* O& @0 e# c8 D; a8 V8 ~
- </div>' e( `2 D4 N" i: b# q
-
4 m _$ N4 x* H* X0 M5 {& S - <script>
0 c0 y, R7 h- y) c5 t* W4 v - // 注册
1 c, X$ h1 o+ O, \( I2 s' G - Vue.component('child', {8 U& ^. t& N3 t% i
- // 声明 props
. X; v5 W. j% [) B1 e% | - props: ['message'],
! d/ q$ `& s0 M: {* C( W3 A; M' ? - // 同样也可以在 vm 实例中像 "this.message" 这样使用
2 b. O( `8 G/ {3 c3 E6 m% C) e - template: '<span>{{ message }}</span>'0 O- E. R: s2 H/ |) o, ~
- })
- R* l$ f- e) S9 N) l2 I2 ~ - // 创建根实例
$ d$ G/ p+ j w$ C5 p - new Vue({! p# A& \1 {+ @2 y- _
- el: '#app',% A! Q V6 U% i+ U
- data: {( n( L5 ^8 W/ X3 U) X
- parentMsg: '父组件内容'
& k9 A1 R& W7 \( E, ]9 U! P% K; Y - }
) W4 S6 y, k+ C' b, V - })
) F- {. k1 E F( d - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
( j+ S. v7 Z$ \9 ^& q- <div id="app">$ j0 M' g7 X) _1 q: n2 i
- <ol>' x9 m+ Z8 J/ J' ~% M0 d8 c4 m) Z% b9 N
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>7 y" O: P/ o% ~/ h3 p; V! g
- </ol>
% z* d; I+ ]) t0 W+ O - </div>
+ y" Q$ `" E8 V. [1 [5 s - . [ n0 K) q1 l( A) T" Z
- <script>
, Y' i4 m/ I8 E$ a+ z- q - Vue.component('todo-item', {% }, f: D0 o3 c6 y( j$ c
- props: ['todo'],; {$ @1 i" ]+ w ?. R& Z
- template: '<li>{{ todo.text }}</li>'
" _( M. V0 i q* L5 ^5 @' J- p' P - })
7 d% }$ W0 t: }* _8 e3 e& d4 f - new Vue({, N) f2 S- |/ I- L3 E8 H
- el: '#app',8 q, _/ d- i/ r3 o
- data: {
4 {: T' J9 l, S6 J7 R0 _( V5 {1 R - sites: [3 \9 i. B* w! ~( @
- { text: 'Runoob' },7 D9 k# Q( Y9 o) p; k, S! k5 ^
- { text: 'Google' },
1 ~. i, I2 h/ v3 D, U - { text: 'Taobao' }
- p) z7 @: C/ n6 @9 {- D - ]" l: U- `7 {; l0 H
- }
( u }4 d0 v! F0 Y' b - })
a1 O4 I2 _, B+ u9 p, p - </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {3 |6 z: }) e1 y/ b
- props: {6 V) J4 z0 a& h
- // 基础类型检测 (`null` 意思是任何类型都可以)
- P- ~# W1 u+ l6 Q - propA: Number,
/ I1 n; {# ?# T& I! A - // 多种类型+ S. }7 T3 a& m8 |; ~- r
- propB: [String, Number],3 p# j9 v* x1 }- x9 w& T, l: M: H
- // 必传且是字符串
+ c# U- Q5 y1 K+ N; `, r, `5 w - propC: {3 [- v0 |6 @% [+ h; q- E# q
- type: String,3 q! a- K4 o- V. F( W
- required: true
' w2 d4 s1 h6 m) Z - },7 n: _; x; ?0 u4 r: E
- // 数字,有默认值
2 ^ J' b9 V* o% A; i0 |! {8 L - propD: {
4 R4 ~7 n j, W q - type: Number,
% ?' j4 z6 M! w5 j: C3 O - default: 100
) p1 M5 C- s4 R1 [/ C - },8 X; r* x- {& B3 H2 J$ L
- // 数组/对象的默认值应当由一个工厂函数返回
5 `) C9 N3 ?6 V4 r/ `" W% L - propE: {
* l" A* X! s: ^! T P - type: Object,3 L* x# F; B8 e, A9 V! e, R
- default: function () {
, {3 p1 Z r: M, c! B. _ - return { message: 'hello' } R9 V6 U5 c! m
- }1 x U) L/ _# f5 }1 L
- },) ~/ ^8 N" ?! m% g* S
- // 自定义验证函数( ^ \7 l' a3 e! U) L
- propF: {
) @, b8 d+ ]4 _ - validator: function (value) {6 }' K5 {* q7 A% d# D
- return value > 100 S4 ]" X; t% w1 }. W4 P" i p1 ^
- }0 \, }1 ]9 S2 o8 m
- }
3 \2 ~6 Q; r5 O6 K/ f4 ?4 b) p - }
; y3 @5 j& T: }! |- f* ~7 [ - })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array1 S' H9 U$ O' n+ `) v+ Q. W
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
6 L# N/ _0 j# p. t/ M J: j
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例" T0 {- v0 H2 ^* Z
- <div id="app">% ^* y, `& ~1 X, T, _5 K
- <div id="counter-event-example">; t0 H+ r" G) e) f0 l! h
- <p>{{ total }}</p>
7 N, h4 z: j2 U: @ g) d - <button-counter v-on:increment="incrementTotal"></button-counter>
1 }6 A) ?8 e" I/ _, O: d6 c - <button-counter v-on:increment="incrementTotal"></button-counter>
2 O3 d- M# e. ]% Q - </div>
, ?6 @" e, X6 R* R3 |- ]* u) ]2 } - </div>
8 `1 P' e% Y6 ~. X" R0 } -
* e& W/ j0 f* J# R8 u7 D - <script>: ?0 |/ d) v& V3 O5 D& p. R
- Vue.component('button-counter', {
& ?' t$ a! @+ N7 p( \9 D* W9 J r - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',, S6 c0 y0 |( {, O! }% o
- data: function () {6 \4 t6 j D2 _" U/ ?8 V$ f
- return {% r! m+ q O. ^
- counter: 0# G S( f& [' L+ `9 t
- }5 c8 A# H/ M# k3 F
- },; B+ d0 o3 [, m/ o' X2 O E4 i
- methods: {" ^# B$ R ~: l
- incrementHandler: function () {
- i+ n8 c8 L% r$ R8 U) L) _1 }1 S - this.counter += 18 i R# r. s4 a3 t- s g) V8 ?2 B5 t7 Q
- this.$emit('increment')8 z, J' Q. h2 r( L
- }+ C' @/ I" {% y4 ~2 A) E7 g& K9 z
- },$ T" C2 j3 f0 }& _
- })' E* p9 j' i; `- D1 d. i! g
- new Vue({+ Q) m I- k% L6 `: z E
- el: '#counter-event-example',
5 l! t6 Z8 w) l- _- Y2 O - data: {
( T* x! }" B# X W" P. S, G - total: 09 Z$ v1 @4 u+ p& W8 |1 m
- },$ o; Z0 k* O: ~
- methods: {
6 j" j8 _1 b N& r: d$ J5 l$ Z; B - incrementTotal: function () {6 B0 U' g! l1 g
- this.total += 1+ z* O' {4 n2 h+ D
- }8 y0 ]0 V4 r5 o4 `& i
- }3 k5 ?/ }# V) G- o* r' k
- })
4 P( B" X! [. U - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
' y( H( B1 l: i/ |0 X# S% q L - Vue.component('child', {/ A( F3 p$ N+ N9 Q+ \$ e/ y
- // 声明 props( M, D; G4 c5 q; `2 L0 p1 P( E3 z
- props: ['message'],* N9 o) B+ z7 h5 m
- // 同样也可以在 vm 实例中像 "this.message" 这样使用" V/ e$ S6 m$ s
- template: '<span>{{ message }}</span>'
2 ]5 S1 i& F+ a; s9 [' n - })$ F- B; Q: V: X L" h; `9 _: ^
- // 创建根实例# o' f5 i P' ], @' o4 J% y! i% F' z
- new Vue({
: i2 m; \& M3 v - el: '#app',' b* k' y+ B3 m K8 ~- z8 y
- data:{% ]( K$ b1 m: J
- message:"hello",
: s% C- }, V3 D - }
( G% s3 d2 q" o N - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
' V/ n7 q @; W7 V - incrementHandler: function (v) {( l% r# d0 q: L* i
- if(v==1){
' p9 Z3 U/ O8 W( K - this.counter -= 18 r$ u* O' z. y; A/ j5 w
- this.$emit('increment',[1])+ Y5 J$ y9 Y9 ?4 e8 B/ n& F
- }else{
! }# G( F5 ?4 i# h3 F/ h - this.counter += 19 G1 v: D& P7 w, l# Q e+ S) s" d
- this.$emit('increment',[2])$ q9 v' d7 H6 m1 X
- }$ a$ p! k& @9 h% A2 w$ e0 q
- }
! l, l% e0 b) c. B: u @ - }
复制代码
( n) ^$ U* l3 K0 i- k
5 ~: o. k/ Z T0 V2 \ |