|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它: 3 j! o! T* @( A6 Y `3 l; r g( G( o
- <div id="app">2 ^# C/ G! i6 A$ P3 z
- <runoob></runoob>7 N/ ` X# l. O. C/ O b+ ?
- </div>
0 @5 {" _) ~! `1 d- l9 k* l - 6 S; A3 [% |; ~$ H" _
- <script>
: n! m. D7 A4 O- d, N - // 注册
8 c; N7 a$ ~8 n. M6 V) ` - Vue.component('runoob', {
3 S1 B) ?& }1 E: I9 G - template: '<h1>自定义组件!</h1>'
7 W; Y. Y+ z/ Z7 L/ s; ~, } - })
+ V& n' H& ]* P3 p5 y- `7 U - // 创建根实例
) g9 f0 ]6 m) m* a$ e4 G" O - new Vue({/ l1 [7 s4 n: ]: Y6 @
- el: '#app'8 y- ~" t* X# r
- })3 \3 C% i9 t3 w% D/ {; A/ ^! Z) h) y' N
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: & d3 m z7 A' y- H3 c% v5 d: a
- <div id="app"> R5 T+ Y# q# t: e
- <runoob></runoob>: X! F: G' V- K/ @' \% J
- </div>. g0 Y8 @) l; c F0 Z
- 4 ~* ~- p) x( T+ F- e
- <script>
2 v! k& R! ?3 x* Z3 E - var Child = {1 K* h' k, m/ W7 F' J: e: e7 |
- template: '<h1>自定义组件!</h1>'7 ?6 J1 Z# w! \1 \$ Y2 I
- }
" E( d! U) x: F8 C: d - 4 h/ _2 A7 v: u2 a* q! s
- // 创建根实例. R- U, }. t1 s0 m
- new Vue({3 u9 U. c" Z+ o, a i, M h( d6 G
- el: '#app',
0 u( V8 m D5 r8 F - components: {
3 y% M5 ?# ?8 ] l - // <runoob> 将只在父模板可用
* h2 j1 s2 }* u4 k - 'runoob': Child
0 G0 n6 i4 ]2 }* | - }4 O! s4 G, k6 j2 ^
- })6 a+ m' A7 n |+ w' Z! S
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例: d5 E( A! g4 ?/ r
- <div id="app">
8 R1 `/ j8 \- k1 G# T - <child message="hello!"></child>
: T3 W. [0 f0 {( [2 ]! l& k - </div>% W' {. N) t1 c$ H' Y8 F6 {9 P$ N
- / s: l# n* G3 s+ ^+ Q# ~% b
- <script>1 k5 B) P4 e5 I9 O
- // 注册# h( F3 ]1 w' f% ?( T/ Y
- Vue.component('child', {
" [' ]! j7 \- I6 E' F+ J1 G* ?/ k - // 声明 props
+ l4 Q5 @7 Y/ Z9 |/ {8 m - props: ['message'],9 ?1 Y' {4 v, f, |" w
- // 同样也可以在 vm 实例中像 "this.message" 这样使用) w' T/ h8 T i0 m! M4 _
- template: '<span>{{ message }}</span>'
2 P3 m G1 B9 @9 \8 O. m, U - })
; Y) J4 g0 u$ i2 h - // 创建根实例
9 ]3 X/ q" P. i3 E+ X. t' { - new Vue({ V( d! W3 B% Z0 ]/ Q+ `; F
- el: '#app'
% T* {6 q. B: _9 ^3 [; f - })4 f$ i8 b9 ^: B4 w3 C; V9 L1 _
- </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
( P( l$ T7 D" r' t- Z/ x. m* T" d- <div id="app">1 x4 }1 _) M) c6 t8 a. H5 R
- <div>" y! H5 A$ l" j, P( d
- <input v-model="parentMsg">) B! W8 v, \1 U( p: c7 l. w
- <br># d* P2 B' V8 {7 I# ]* O
- <child v-bind:message="parentMsg"></child>
r+ ]- S* P6 m: ] - </div>
7 J- D0 }) L! ~# C8 M - </div>0 V( t! A+ f4 B% o$ m
- 7 V* n4 s3 d; D3 E0 s6 U% {
- <script>, r. N' n3 K3 X B
- // 注册! z: h8 H3 v; C' p- M- M0 U3 B6 ~
- Vue.component('child', {
' m9 y* D8 ?1 e7 I, M1 S9 t - // 声明 props$ A; D' V) l& E6 N7 ]
- props: ['message'],( H5 h2 e& s& Q7 ^, S& Q
- // 同样也可以在 vm 实例中像 "this.message" 这样使用9 b/ u+ x+ L0 K* E& d, L5 }
- template: '<span>{{ message }}</span>'9 I6 k5 f' p# O: L! s- x& ~
- })( _- N: Y2 V* K/ W! c" {
- // 创建根实例
7 z9 a) t. l2 }& W% | - new Vue({
3 \& d+ @4 x7 h7 b' \, X, f1 q - el: '#app',2 t( f' L+ j, j. x* G
- data: {3 a* v0 \5 p) c2 k
- parentMsg: '父组件内容'
( l0 c* F2 F7 [ n4 H" ` - }& x: F! m) F" J
- })
* ?9 D& i2 R! ?: J* L2 ~7 O - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例- g' T$ @- V: Z; O2 |0 K; M
- <div id="app">
! S- Q" t2 U4 ~8 v6 R% A - <ol>; a! F7 _: V0 y5 Q
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
) P7 v3 \ S- \8 U& w' Q - </ol>+ _0 j1 `" I) A7 G% l1 _' _% N
- </div>7 t. `! ~1 A) i9 X/ B
-
, T8 V: z7 k- Y; t& W1 \" | - <script>
; T9 C: k3 Z5 |+ L- J& ? - Vue.component('todo-item', {
1 d* n/ j! D. c# n6 \3 b - props: ['todo'],( }- t5 Z) E; M" p6 d/ ^8 L" ^: V
- template: '<li>{{ todo.text }}</li>'4 R! V$ @* y/ ?
- })
3 u' A# g. {7 f$ b- a - new Vue({
2 j8 W- D0 h* @, s2 n7 s - el: '#app',6 G5 F* V3 a7 s# _" E
- data: {. J8 M o3 q/ _) u) b
- sites: [* g) d! }2 D; a8 [8 d- M {# M( f
- { text: 'Runoob' },2 l7 N1 P* T1 @6 B% C' |8 h$ B8 a
- { text: 'Google' },4 }6 ]; k) S" [1 f' h
- { text: 'Taobao' }5 n6 C5 V6 M7 K% f2 J' H
- ]
; d3 f" S" s$ f, y4 a& o- \ - }( q, {: y6 O, w3 j( w
- })- H! j& S8 D& A: I
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
W' d: b3 p) f; J- |# P/ p% Z/ f - props: {
2 p3 ~* T. Y( L6 V, [: u6 g - // 基础类型检测 (`null` 意思是任何类型都可以)
* b5 v: D; Z: X" D' \, w - propA: Number,
6 p/ U5 t- r) ~: n/ ^$ O* Z - // 多种类型1 H# P g5 t- S K. g
- propB: [String, Number],$ h5 ^* F* H j6 @
- // 必传且是字符串9 S9 f& p/ D# U- \# K
- propC: {+ G+ w- x/ J. b% H' w9 f3 M: g) X
- type: String,3 ^* z2 |, z6 w) ?4 x. D
- required: true# h1 a' I$ |) |. t2 _5 g0 n
- },
+ d( o" |' P6 i* M$ T - // 数字,有默认值
8 f; J! b2 S4 \7 ] - propD: {, s% ?) X6 s' m6 [% C- h$ W
- type: Number,7 c7 h( q& d* O, F) t' f, e$ Z
- default: 100; v9 o, y/ O& b! z! U3 \. L
- },$ _0 ]7 V# P' @, T
- // 数组/对象的默认值应当由一个工厂函数返回
* H9 m$ ^. y' E7 D M* S6 D7 [ - propE: {
! o) h* I9 \8 T- j - type: Object,
5 {% ]1 w# `. V9 x# u$ a - default: function () {
1 W4 [$ \7 ]# v, [8 u1 O - return { message: 'hello' }
* q8 w, p+ l r - }
; X) y- \' S; ]2 V4 y& [/ g6 s' ] - },! {5 ~# v" R$ ?$ U, Z1 c
- // 自定义验证函数
5 A7 H9 N3 y- ] - propF: {
8 B, R1 V y3 o* A" C - validator: function (value) {
! K) X* r3 d, x% x* R( ^2 X - return value > 105 V" G2 `1 w9 A& G& Y! r
- }" a$ u5 m1 A9 K& Q& f; |( v( [3 i
- }2 b9 `- a' L6 h; l
- }
' G1 m2 R' M. f4 F f9 N& [4 G - })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
8 o z; `+ v# `8 `) ~1 W) Y
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件8 ?# B0 `) v" O5 b4 u+ M
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例3 c' i9 F( A- n3 t2 @* p: U& W
- <div id="app">
7 F. |( u. E- } - <div id="counter-event-example">
, A& B8 W1 O/ O. r9 D - <p>{{ total }}</p>1 b" S' v4 @8 |) D# N0 J1 L; y, O
- <button-counter v-on:increment="incrementTotal"></button-counter>- J, |9 z0 a. p1 S/ t& B3 J
- <button-counter v-on:increment="incrementTotal"></button-counter>/ Q$ L* |4 m+ m0 j& s
- </div>6 k% B" l6 g! S( r
- </div>
* k$ q& E2 I" {$ u9 A/ W3 Q - 7 O8 k" Q: g& |! W+ Q! M0 l
- <script>
9 A8 g5 M( g* q2 o7 V+ `! S: ? - Vue.component('button-counter', {
b& \0 [7 m2 p% Y4 l6 ^$ E - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',7 \4 @: G" ~& Q/ R( n5 z4 ~% K
- data: function () {
- [5 ?2 q, P% R( r8 a2 G ~# P - return {9 N% u: W7 e9 t/ ^8 e" _& t
- counter: 0
/ V( b0 T8 c6 @& A% F: K - }0 e2 h; M; I' f7 ?) z
- },
9 q* M: [; Q/ K9 `- A - methods: {, C) {* ? F, ~, H& E
- incrementHandler: function () {
7 Q/ h/ K- {9 A4 ~1 ]0 E2 o - this.counter += 1
. K$ B8 S7 ?; E% E" ]8 K8 t' k - this.$emit('increment')% \# j# R( g; _* f$ K
- }$ |" |0 S9 `9 }9 U0 ?7 c
- },
3 Z/ W+ ~+ {2 y h8 n# U! S' R - })9 W7 }3 r: T1 q* o$ b
- new Vue({
( K0 w3 F+ i6 a0 w6 B+ k0 E* N* b - el: '#counter-event-example',
, N$ K# f7 E1 ]$ \ - data: {4 `) O( Z; i1 L1 l- F/ R) Z, l* @5 I o
- total: 0
) F: P0 `8 _3 | - },* M4 ~& o" _9 E" d, E
- methods: {
' g5 i6 f d" f" C/ c J - incrementTotal: function () {8 N# n H6 z) k
- this.total += 17 @$ g$ V# j" {0 s/ H' W+ p
- }
1 D: H) `( ~' r6 B3 [( V/ \ - }
6 a0 s" I8 {1 E - })
. a- N& v9 C$ \; u# `3 R - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
9 B4 S W9 J4 H8 w - Vue.component('child', {$ U2 N+ r( E3 ?0 p4 S P
- // 声明 props/ m9 l: r5 L$ `5 X& Q7 l
- props: ['message'],
0 b8 _( L) K; ^" H# ?, _& N - // 同样也可以在 vm 实例中像 "this.message" 这样使用
" r+ K" k' q( k( l, ] - template: '<span>{{ message }}</span>'
) t3 M5 u2 U1 ?! u5 j - })
" V$ W% u% D+ G9 p! l - // 创建根实例
: C$ f7 J6 `& X - new Vue({) s* Z4 I! n1 i& o- n. y7 @
- el: '#app',# M) L8 ` q9 ~4 ^6 [ y
- data:{
* s* [5 |1 g' O4 M4 H - message:"hello",. p; L6 z. ]# }2 n
- }* o6 t: p9 r6 S& y0 v/ } {" e
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {, l' t' r( \/ ~, v
- incrementHandler: function (v) {. p! `- q8 x' u3 O
- if(v==1){
) i! O# `; C9 s/ z - this.counter -= 1
# I2 C* a, B, [' g( I% n. j/ u- Z' x3 A - this.$emit('increment',[1])
6 L( ^9 N T& F1 I - }else{
& g! }2 ~% {8 B. t, _& h - this.counter += 1
! H# Z) n, |7 O- A% p - this.$emit('increment',[2])* _- { v. ^0 K) z
- }
8 c, ?& _2 u& w. b8 I - }
- T6 E6 ^! ~3 K1 q6 J8 X5 T2 O, f - }
复制代码 8 M0 U ] ~ t4 t! k W( E
/ X( |3 g3 t' b7 E- c& x |