|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
. S) Q# @0 U8 v& b% K0 ]9 O- <div id="app">0 q4 V/ N' P, [2 V$ [5 B# U: P& l
- <runoob></runoob>
1 f ~! v* ?0 a" D+ Z: ? - </div>
8 F9 d9 }9 J6 r) Q- u8 v -
. C* l" I- p( W - <script>4 Z: j0 [8 C. W% U6 C4 [. N
- // 注册
6 g( J) Y6 Y) |! g2 p7 @% L - Vue.component('runoob', { F# y. K5 K8 L5 A4 L& Y* U
- template: '<h1>自定义组件!</h1>'
- k! O5 a$ J+ C* J - }), C2 t$ S" ?3 C# K# j1 L
- // 创建根实例
: K- v, c5 g8 P' w& ~+ d - new Vue({
! P% b5 F! L7 O v+ O6 N0 p" x3 p/ G - el: '#app'5 F1 \7 h& b1 R6 O% e
- })
5 I; ^: N$ M5 L6 ?1 ~ - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: ; o4 ?4 G; A6 |/ B
- <div id="app">
3 f( V- U- C$ B) d/ b3 p - <runoob></runoob>; _7 s, g6 r0 ~8 t- i
- </div>7 a) a2 y& x" x3 h
-
" a, b; i! T# W% k9 g - <script>
% ^. { j. ~! [& l! j8 v - var Child = {
) d( ~6 ~9 V( W6 R( j - template: '<h1>自定义组件!</h1>'
0 y: `( ^) q6 C! d) P - }
, X$ P0 E4 r+ I: v -
& |( f1 k. z2 _6 Z9 u - // 创建根实例
2 h$ X7 O- w) [( m# e' b8 \& I - new Vue({) q. v( ^* H6 m& @8 n; Y
- el: '#app',# I3 L. \0 B7 ~$ m4 J9 M! a* @
- components: {
: Y; Q3 C8 P. x( W7 q- Z - // <runoob> 将只在父模板可用5 v5 w V' s; g C6 \3 [' E2 h
- 'runoob': Child3 s k9 a0 K* Y& ^) f
- }
* Q& n; K1 Q- R+ [ Z - })$ C P! M/ ^3 a7 }
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例9 G& Q2 q! G6 X$ ^7 D$ o/ l* A
- <div id="app">
% J7 L |: A' F- n - <child message="hello!"></child>+ G" K7 D+ [- v) I
- </div>; P. b! \1 U6 M# ]& O
- 3 p( g0 Z* I5 @) @* R
- <script>
7 D: s7 N6 y ?& y2 V - // 注册
- ?" @' d$ q, ]9 s - Vue.component('child', {
$ D+ h+ Z, r- G. D - // 声明 props
- m' | a/ M7 o" x* ]+ q - props: ['message'],
% E7 Q W% x$ g9 k - // 同样也可以在 vm 实例中像 "this.message" 这样使用2 }7 h* h! c- H5 q3 y
- template: '<span>{{ message }}</span>'! e1 ^$ q+ I. A& x! L+ n
- })7 ]' L8 ~: W4 e% k) R( d# [4 v
- // 创建根实例$ {% P T2 l) m0 G) a3 j
- new Vue({
, ]" Y7 b/ k5 |& @9 U0 z1 a - el: '#app'$ s# K' k, q. _7 N- t F
- }), {" `. ~& f/ r5 [2 Y% f
- </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
. _# D. E9 B' ]/ Z- <div id="app">1 c* e$ p1 e* m) s# N: B
- <div>
) a( y$ B5 V( u- S6 U4 }# i2 f - <input v-model="parentMsg">2 ~$ j; f; A$ R
- <br>
+ k) }+ v1 O# s$ t+ }, h7 A3 u# l, \ - <child v-bind:message="parentMsg"></child>3 D: E2 F- {; ?5 u/ F5 ], s
- </div>
" J' r- _; r/ i0 K& _6 r/ D - </div>
/ q4 D, t7 G" S3 v( ^' z2 ~( b -
/ r2 Y' Y. I/ F - <script>
& M) O5 l q! c5 U( a$ b - // 注册
% P, [: h6 [* ` - Vue.component('child', {
1 g% j* z/ x6 }/ ^; U' l - // 声明 props
- t1 f! h3 a6 R. k2 e; n; T- j) v - props: ['message'],
0 \7 c! W9 @$ ~ O( ~ - // 同样也可以在 vm 实例中像 "this.message" 这样使用. }6 D' ~+ z4 L/ M
- template: '<span>{{ message }}</span>'( T4 |9 y, J: [3 v
- })
. m$ `8 q8 g; x y - // 创建根实例
0 s, p( P5 p) S) X! a% [ - new Vue({$ A7 A6 | N$ w8 e
- el: '#app',8 N& k2 p- w8 q
- data: {
3 D& `' R8 t- c" U) s1 X - parentMsg: '父组件内容'/ A4 T5 J; k o, G" c
- }& @* {4 i j3 G1 w
- })
) r. Z7 _$ i7 v5 N! a \ - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例5 |# t9 ~) b2 G! A8 C4 S
- <div id="app">% {# W( Z% u' i
- <ol>* i& Q( L* K+ ]' |. n' I
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>9 D4 _+ `9 y" f/ q0 R
- </ol>
& j- r4 d- v u% x# u/ m# y& y- i - </div>
6 i: b4 D, }& n - 6 `3 e! D& z c! X! C& X
- <script>/ Q. P& U, u; n2 j9 }
- Vue.component('todo-item', {; E) O* ]# m& @
- props: ['todo'],
: Q+ z' I3 q" }0 ]" t+ A - template: '<li>{{ todo.text }}</li>'
) h, B. D) A0 [- N - })
; Q# W* R& b& b' J0 l - new Vue({6 m! {, u0 }. ]3 w: j, T
- el: '#app',6 S! c. v) j1 u
- data: {
; A" V- y% ~; d6 J. Q - sites: [
7 t7 V- K6 a8 M - { text: 'Runoob' },
% @6 p- W8 D7 D* C. v' [ - { text: 'Google' },6 W/ U2 y* z4 a+ H
- { text: 'Taobao' }
: G( C9 g- K! |* N - ]2 c4 F( O' s- c, p6 F9 |, ^
- }( I# k9 S$ e0 K. i U# s1 S9 G' v
- })( y% q! h6 d( r' C1 m X% i H
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
( P& o( z+ `0 I8 G# d: g0 R! G2 h" B - props: {
5 [, f/ I! c" M7 F - // 基础类型检测 (`null` 意思是任何类型都可以)( K4 H: q. L s# q" k! o; f% n
- propA: Number,
+ ]3 t/ V6 y6 q - // 多种类型
$ n3 y: n0 P; r; R6 J+ C - propB: [String, Number],
, s# l7 V6 S& P/ |4 ?$ z - // 必传且是字符串
3 J$ U3 h. j! {5 R J" a. s - propC: {
. R6 w5 D1 O4 @( G; n# t6 c. M6 ~ - type: String,# E3 K& `0 Y% x1 w$ N
- required: true, q/ o, j$ U7 W
- },
) q# Y; {4 f% P% X; I _ - // 数字,有默认值+ ?' }9 e% S/ s6 _
- propD: {7 w$ e" U1 h' c. D/ k8 a
- type: Number,
2 _8 m# P& S4 C; B# u0 T, D - default: 100
/ S" V0 s- q7 V2 x* T3 y - },
1 m/ F" Z; `/ s8 n: V b - // 数组/对象的默认值应当由一个工厂函数返回3 R" O& |% \0 _% b2 Z
- propE: {
( Q& O q# P5 b# W - type: Object,
0 ~2 i( \) [, H) t+ I& d - default: function () {1 Z/ y& V: y; v* m- M& y4 s
- return { message: 'hello' }
: [+ i6 l+ c/ |! i0 x/ B - }
1 e. ~% U% v% I* G* s - },1 H# t b5 o3 E* I8 b
- // 自定义验证函数
, p6 ]: @1 A+ a& _ - propF: {
; N4 I, I6 i- ^8 t - validator: function (value) {
: H/ B6 [. N8 i; d( w - return value > 10! P/ d4 F y- v
- }
0 @+ S5 X5 y: c9 }$ Z8 v - }0 \5 g% u- m/ x
- }
4 J$ @; \& V- c, H! q5 K+ X0 } - })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
( K* B$ a2 E0 x8 a; b% T
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件0 B2 l+ O1 ?$ G% f4 ]' V; ?
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例
* G' k3 ^8 T2 ~- o. G- <div id="app">2 `6 ~. j- o9 p! M. V& {
- <div id="counter-event-example">0 _2 ~. K N$ c Z# o. i2 I0 E
- <p>{{ total }}</p>, M" T) s k: g. F: _
- <button-counter v-on:increment="incrementTotal"></button-counter>
1 U3 s& g! X& | - <button-counter v-on:increment="incrementTotal"></button-counter>
& [- O) ]8 s1 P6 ~5 f7 S* _ - </div>
% B! L, n6 D) A7 j) Y0 Z; | D - </div>
/ R) b- d: Y6 J% F( q u - u5 @. A' n: d/ `. f/ D, h$ W. d
- <script>2 n" k. i9 q$ w" i
- Vue.component('button-counter', {& @( ]- T- J2 q, b* o) f1 F/ F
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>',8 K1 J F4 o( Q: t
- data: function () {5 s& Y \5 v2 l' o/ n( j# l
- return {' j* r4 M# z& y7 F/ p' A! _6 e
- counter: 0, ~# a# N6 c( M- I
- }* N9 n& Z1 d9 X9 ]9 ~
- },
( \ p" T- c4 T( e0 E - methods: {
/ @6 _/ S8 [+ d5 Y: |1 s - incrementHandler: function () {
2 z+ L& G. `) F5 m4 ` - this.counter += 1% N( j1 m4 B: _* v# X0 `
- this.$emit('increment')
( s1 a1 N1 r- l' R5 L6 H - }1 a' y7 q8 `. m
- },- Z) T3 i5 V" Y/ V
- }) W, o) Z& E; |' D8 `
- new Vue({
. ]# J- @3 V! {# M) _ - el: '#counter-event-example',
0 D& K: O3 G# p+ G7 ]; q - data: {. S5 u) X# s" f2 @2 K
- total: 06 Q3 K' U4 \8 R
- },
: @' d; ^% f! _. a8 B4 e - methods: {
! ?9 r% L X+ P: d \3 t0 J3 Y - incrementTotal: function () {8 f" l& f4 Y! x% u5 }
- this.total += 1
" s" Q$ Z# g1 e* _( a. D - }) m) n8 L1 M7 K! o% x
- }5 h! a; y1 E+ x7 q$ g
- })
1 U8 w; Y* r' {, B/ h; c - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册2 _: Q+ D* V3 }2 |1 {
- Vue.component('child', {" s4 j, Z/ |9 D. p' ]) O
- // 声明 props8 M9 k% A) Q" ]& P: }
- props: ['message'],
$ P% {" i1 q3 @4 o/ Q: Z r" z - // 同样也可以在 vm 实例中像 "this.message" 这样使用
1 s3 X! ^$ E( p2 T g% C8 E4 k, q - template: '<span>{{ message }}</span>'3 X' ]) ^! v" Q! _! I) N
- })3 o6 |' S2 x# S: G- y/ w
- // 创建根实例
9 l: |, \" m; P - new Vue({
5 v/ c" N$ ^& a. f - el: '#app',
; b$ [8 C/ I$ ?/ ?0 O+ v - data:{
+ c7 N! J" R8 c u - message:"hello",
+ R0 L9 ?, w" m6 G2 v, @( z$ ^" Z - }, J) v: ~3 E2 c& `# J) }
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
3 E9 S* y1 l g - incrementHandler: function (v) { i. Y9 v( }! i
- if(v==1){) x5 g3 X- ~1 J$ P% \5 G- `; o/ N" a
- this.counter -= 1$ d- O' l* w: C& c8 [, w2 z; a
- this.$emit('increment',[1])
/ n# g5 n% R$ l4 Q - }else{
$ w& |; g; d c- n - this.counter += 1
- C7 P j8 d L# F9 \7 T% P8 [- l - this.$emit('increment',[2])7 g/ x1 R+ v+ w: q0 k9 a
- }
2 I# a O7 N2 {0 T& g! U - }
) S5 _7 S. Z& t. [) l. b - }
复制代码
" O B& B5 m* O: A* @+ g) x, {7 o, B1 [& j
|