组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
. j8 M& H, T* m0 R1 P" Y1 {- <div id="app">; Q( j) K# ]$ ~6 h3 a$ Q3 W
- <runoob></runoob>
: t/ u1 E2 H: j' ~: ` - </div>
/ ~1 c# `# G9 N, I* B; m/ N' `! ^, M -
8 z: `, W2 }6 @1 [ - <script>* p5 Q+ U5 y# q4 R
- // 注册
4 Q. X6 Z; ^- W5 C - Vue.component('runoob', {
* a: O: V& l/ k - template: '<h1>自定义组件!</h1>'
+ }9 E9 Q9 b" Y( K* n; t - })
o$ H7 S9 B( c7 r ]; f - // 创建根实例" U/ `. c+ I0 _) X
- new Vue({
/ @: `2 U' b# Q- O - el: '#app'
e+ `- e+ t9 d0 r9 f - })) m3 U9 T @ h* M _# S
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它:
! V ~) N( ~( v: Z& f- <div id="app">
# L& {9 ]: Q4 i1 d) I( @ - <runoob></runoob>, u6 O* x7 ]( P7 y9 O- N
- </div>
0 }) U( t: W* }( E* @9 _; C - - X; A5 p* G4 Y g# h
- <script># L6 c7 p' s- w! }3 N
- var Child = {6 g% C; s9 K+ D6 g% l& l
- template: '<h1>自定义组件!</h1>'0 V1 d0 ~+ a9 D4 |& U
- }4 o3 r: ?5 f7 _% Q5 B5 H, U
- H/ s& ]9 E0 q* b9 S
- // 创建根实例) H) [. u: }( x% p! |) B) Y7 u; @
- new Vue({& V& d% ^, r# n2 l
- el: '#app',' @9 t; ~3 O1 C) a; l
- components: {% t$ E R, k) P/ I6 x
- // <runoob> 将只在父模板可用
8 _2 o7 Z; V% L6 l" B7 |5 K - 'runoob': Child
# U5 a6 X/ t1 K- { - }4 c6 h; P4 x6 R0 h+ ^* z# y
- })% N" g J0 ]/ Q
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例+ F! f+ m( t/ ~& ~6 g3 S, `1 v9 l, g
- <div id="app">
, e3 Z$ p, G" m9 H0 ] - <child message="hello!"></child>
8 {+ U6 Q4 E" F+ B - </div>
7 i8 J) Q! K& A$ U0 U -
' T: Q0 j9 {- `7 m8 z, s# s - <script>
; a; p% I- \& i# V6 X - // 注册+ L. o9 u1 y6 I6 v1 P0 k
- Vue.component('child', {; h$ t8 c% I+ f$ F
- // 声明 props V9 g* y. K* b$ _
- props: ['message'],( W3 p d4 u! g; {1 p- z# Z4 ]
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
3 m( y4 t) @6 e: @ - template: '<span>{{ message }}</span>'! i" n: q) ]5 d+ o) q; l
- }), m Y; u; u4 y1 s
- // 创建根实例$ g/ y* {0 |3 w: {( O+ ~
- new Vue({3 U5 z" l: O/ H0 x7 ]. C
- el: '#app'+ F( s0 x7 I6 t9 |/ j! B' e" {
- })- e1 [2 Y# P8 S/ @
- </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例( q/ [- I( J7 g1 r: G7 D' i
- <div id="app">) x% w5 y( V0 M. Y
- <div>
) n% S% w- `8 e5 u) x. q. g8 @ - <input v-model="parentMsg">
- m" ?+ O& \+ a( E7 d0 n - <br>
) g9 y. E* P& `/ |+ J. D( R - <child v-bind:message="parentMsg"></child>; x9 K; L& u) q' z9 i; d
- </div>
5 \& T7 g. k& |4 M6 { - </div>2 s% |: t' Z; z
-
. c( c+ G0 \$ X5 v' F; h. V - <script>
4 n |/ `1 q7 s3 a6 C- Q8 P - // 注册
5 T/ }! P. p& ?$ T. ]! ` - Vue.component('child', {; x6 O+ e. Y3 R
- // 声明 props' V# g; Z/ L/ @- W: N: m) W
- props: ['message']," W; k; \2 o' d
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
}$ X3 u. b% i! A/ X' E - template: '<span>{{ message }}</span>'' s7 u* e$ x: m: O7 s
- })
& Y$ o1 E9 [! m4 N - // 创建根实例& X6 z ? j) [
- new Vue({
( X, u# a/ c! f# m5 x: U4 E5 S, I - el: '#app',
8 `. ]0 D+ l" t( q. ^' V$ h- K - data: {6 M2 E) f1 }, T8 S8 s
- parentMsg: '父组件内容'3 o% y* b2 ?2 d- o7 f' b
- }* q. V+ m4 g9 A0 w' e
- }), a# h i2 N5 {! N; R, x5 [9 O
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例/ {6 l4 a5 k' J8 ]( b
- <div id="app">0 H9 M, i& {: [+ O1 I
- <ol>
+ s: v' M5 x- w+ W! F v - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
, M. h+ v) j# d& }& _ - </ol>
) y3 y( |4 }# V9 l! g, o - </div>
8 _/ D( ]9 Z6 B. x; n2 y - V9 E$ X, y. E; {' }6 ~6 x' s
- <script>" E0 x, h2 G$ I3 K" k# O6 C( r, |
- Vue.component('todo-item', {
4 U8 ]; ~# A6 V' w7 J3 {9 E - props: ['todo'],
- m6 H2 Z8 W" K F5 \ - template: '<li>{{ todo.text }}</li>'% {" b; W4 U8 M% y1 k) K
- }); L% T) w6 f' V4 i" {2 Q
- new Vue({* {& w$ G/ e8 u, z
- el: '#app'," Q* S Y u. Z1 a" k g- {
- data: {
) h5 e' M. E t( f9 U0 t - sites: [; X( ?: _+ e: a* z, I+ C* X
- { text: 'Runoob' },
: y3 \1 u4 K" D" S - { text: 'Google' },/ Q5 @- W) n+ A3 w
- { text: 'Taobao' }- t9 [. ?% k9 L" F
- ]
6 D7 J% _. ^" Q6 c5 P' U6 t0 D - }
4 K3 v% P9 b9 d - })
L1 I" [: i) t2 j1 u$ U - </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {% `- v( B/ i8 ?7 Z
- props: {
, @. ~9 \. z @ - // 基础类型检测 (`null` 意思是任何类型都可以)
' B% M7 U; { ^' \# Q+ C3 ` - propA: Number,3 e; n) U9 b3 U+ q
- // 多种类型! }' h* E) @, T& l
- propB: [String, Number],* c- W" ^( K: _& {2 d2 V1 V$ N
- // 必传且是字符串
7 ~, G, {) Y) D - propC: {, G4 B# V% d) [) G0 f& q3 k- D$ `
- type: String,. }' \4 \# ]# b. i
- required: true. a) x) Y2 f7 I& a+ a8 M P; S
- },
+ f5 p- b5 z, i1 K& p/ q6 {/ Q - // 数字,有默认值) s& K0 J5 N1 X+ z
- propD: {
) ^0 V- J& G4 S' `8 ^) P" T - type: Number,
' v9 F8 r3 a6 Y! K. W: Q - default: 1009 v. D3 K+ w; b E
- },7 a% e+ e! |' o; j. ?8 `/ Y6 ?
- // 数组/对象的默认值应当由一个工厂函数返回5 r9 ~! Q. p% w3 W: g; i& J5 D
- propE: {
. A# x, r1 O+ f& F6 P - type: Object,
- G8 \) @8 d# y* U) Y) ~* [ - default: function () {
+ ~3 a. f. ~6 H1 [1 _! x: F2 C# |0 e - return { message: 'hello' }6 T! |, y2 o" f [0 ?( X) j+ B- e
- }
3 U- I# d1 q+ h, v, b - },% {* l3 I2 {9 D( ?1 p4 V1 o
- // 自定义验证函数- {/ ~4 @' B0 F" w7 J) [$ o
- propF: {
& T5 O. h) m; \3 t$ }( W) F" F& t - validator: function (value) {$ l8 N3 ? w: L$ f1 ?
- return value > 10 i7 P0 f) H$ j. E2 J
- }
* f* G& i- l- t+ w/ W! M - }
" w Q0 u% X2 B% {3 b2 H" g( K3 K8 l0 ] - } Y! @/ W# z' q0 R" _
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array) n' Y: k- h# q1 q9 `2 I/ s1 e- z
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
( s: G0 U' ^8 X6 v# K y& G3 J( q
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例: ^ v k3 B/ H! Z- v) g! o
- <div id="app">
$ x. W' l2 m9 k$ c% ], Q - <div id="counter-event-example">& {& `7 L0 Q8 I9 d4 j6 m
- <p>{{ total }}</p>, ^ k; E, h, j0 |: T1 Y, }& o# S
- <button-counter v-on:increment="incrementTotal"></button-counter>; g! U2 U" c( y7 D4 n, r& _! B
- <button-counter v-on:increment="incrementTotal"></button-counter>
7 b1 q: C4 M! q6 i; G; v - </div>* \9 Y$ r; T7 @4 y' u3 v1 F2 M; J
- </div>8 t$ A6 P2 \- h. |* h
-
* h! k- q& t/ i. [/ V7 @3 N - <script>
! N. H m) D1 k" H/ w - Vue.component('button-counter', {6 t( l2 ?- y* [5 q* @5 p3 h; w
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>',: q2 x, w7 `* c
- data: function () {# ^; Z/ L5 b f1 S+ s; q" @
- return {8 Y3 \* T$ }9 f( Y# X: \+ v+ |5 E
- counter: 0
' a5 K. @' I; I" W9 E' y - }
6 E# n3 V4 k; @7 j - },$ V6 E5 e% i3 j# i# c! S) j
- methods: {& c; a& U2 w( j; n" k; {' v# P
- incrementHandler: function () {
) e% S$ N2 M, f( J- A) a# x- D+ @ - this.counter += 1
- A+ M0 C7 @! J! O) h) u - this.$emit('increment')& k; F6 A- M: w
- }+ n' S! a) R5 R' R& g
- },
) W3 F; O, r0 `5 J9 a8 B% s - })+ C6 y4 x8 y6 X; R( B( p
- new Vue({ I) N$ Z) G" p+ P" w; @
- el: '#counter-event-example',2 r, }5 Z4 x4 M7 x2 H. Z( \, Y
- data: {
5 K: |- N( N9 o( ]5 z* e3 t - total: 0+ e9 c. H" d% D0 i$ S# h3 z
- },
4 g5 {- n- l4 t* Y9 @. V - methods: {
* P) ?; k9 v' Y7 L; l, p$ ^ - incrementTotal: function () {! I6 n0 j% E5 V1 F+ ]
- this.total += 15 J6 @1 f4 v9 R
- }
2 i9 R3 c; n5 \- H9 Y' f- M - }
3 @. J3 [/ [# d* _8 | - })
7 \: z0 p7 G y! U+ L+ ^+ S - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
3 \5 K0 N6 ?. }! f - Vue.component('child', {
# [) ^% Z& ]2 F; p - // 声明 props
. e2 A$ V6 A5 D' e# i7 a Z+ _3 F - props: ['message']," Z# i4 ~- o5 w2 T& o9 E' b/ X, @8 Q) J
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
( w" R6 }) A( T) ~ - template: '<span>{{ message }}</span>'
/ E$ p! Q- C5 h# O$ D E - })7 A/ G0 ~) g" x q- V$ y" Z4 L
- // 创建根实例
) z9 u" k4 H- s8 w - new Vue({
8 ?1 C5 y- c( C" F% U5 b+ _ - el: '#app',* h- R: F3 k, c L. B! ]# p0 h
- data:{
1 c' M* C+ H- y6 |7 } - message:"hello",+ m& ~" T m- g6 c. A. \' g
- }8 d' i' C& w- H* G- X" @
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
1 `! S7 h1 L" t5 S - incrementHandler: function (v) {' u b$ p) P& Q% Q( S: E
- if(v==1){
3 A" L6 [4 }% ?/ s1 U - this.counter -= 1
9 l% q) c5 i+ }" l$ _: `9 R - this.$emit('increment',[1])3 v9 j( F5 ~/ h6 g
- }else{5 [, J1 d9 |. w- D1 E) @
- this.counter += 1
, t- M7 B( t c - this.$emit('increment',[2])- g; k( X1 [7 s' m+ |
- }, M- ?5 o1 a! Y O1 c8 J7 s, }
- }+ {" j4 M0 P1 V; t G- y1 @1 e4 Z
- }
复制代码 # v. F3 M- ^! P5 T
' t# R( P) q( R+ f6 @
|