组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它: " C7 g" d9 z! h: S8 A- ~
- <div id="app">
0 E+ H$ i: y* G5 k, z: U2 q - <runoob></runoob>
. p5 }) n S: d6 j( F - </div>% H: y2 L0 a9 a, F8 _. u. [
- ! l; f! d$ I2 R# K& C/ ?# Q. h
- <script>
9 H+ H. w5 {3 x$ u - // 注册
" B; I( x, }1 [$ y. j - Vue.component('runoob', {) c% Z/ J2 L8 H0 y* [6 r3 `' v
- template: '<h1>自定义组件!</h1>' E/ n. o$ {# R# P8 Q/ c1 G: [
- })
$ o, F4 e4 Q( t* i9 ^4 u3 H+ T - // 创建根实例
6 J! t) N6 U8 i( ~ - new Vue({, E8 D. o8 M4 X# ^- @8 }
- el: '#app'
7 v1 t4 e% k& y - })4 F/ g# L! z$ o0 ^' }
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: * \. V0 w; W/ B4 k7 d, T: ?& X- V
- <div id="app"> j3 Z4 T0 p9 E- x9 W
- <runoob></runoob>! j* Q# i5 O; D3 l& ?+ q0 h
- </div>
( s1 B: w- s5 h/ y6 @) l4 R -
& u2 f6 @8 f3 p# o; \7 e1 \ - <script>
% j8 W8 G* n; M4 r0 } - var Child = {5 z" |0 U+ ]0 |0 h0 E% U
- template: '<h1>自定义组件!</h1>'
9 x# g. h7 X. N - } Y- j1 K9 u6 w; [& `2 a6 ?
-
+ A$ ~# u8 l+ @) G t - // 创建根实例
) j" Z% t) ]) s D7 H" x7 H9 F, ~ - new Vue({6 Z- `" C4 C! u o- f4 @
- el: '#app',7 ?9 F/ H( C$ ]$ w: L
- components: {
4 Y" d/ z8 E* b& z8 ~. l - // <runoob> 将只在父模板可用
+ g" n) B! b& p! e - 'runoob': Child+ C0 ?) @ X$ N( E) ]
- }- I, |, W6 u7 N, _! l) }
- })1 w6 ]8 r/ U. l
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例
! x C. m& c8 b3 T% x- <div id="app"># d# p4 r9 S# O( [! P: s
- <child message="hello!"></child>
. n3 b& j$ x( W+ e' V1 Y5 l9 Y - </div>. X& b/ f5 _1 n# l& G
-
3 q" j) o) q# r, B - <script># n a. n3 y1 W& W9 _
- // 注册' W& H0 D/ N3 {; i$ y" v
- Vue.component('child', {
! ~% h8 J. R$ C! ? - // 声明 props
& k" M% x* O1 g - props: ['message'],
# a6 f: f- |9 f b* O6 n0 V1 W* Q - // 同样也可以在 vm 实例中像 "this.message" 这样使用9 ?3 K( p2 I9 f6 X
- template: '<span>{{ message }}</span>'! |0 X( h/ K3 c% e5 C0 ]% f2 l" |
- })
; B3 ^3 o" T' [6 v - // 创建根实例) T2 Y) b" h$ @( ~7 w
- new Vue({
- [# v7 t; p! Y - el: '#app'. q: v$ ^, ]- S1 p
- })
1 F2 r2 L/ r" T - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
3 }$ I8 c1 }6 r9 T- <div id="app">
5 g' L5 f' ]# b( n, M; J* ~ - <div>4 q; d! b( p6 l, E2 W0 c0 V
- <input v-model="parentMsg">
) y8 h! C9 F3 @ \8 e& y. W! b - <br>7 W1 T2 S v+ |! j' y- }
- <child v-bind:message="parentMsg"></child>
( @! ?6 Q z% O ? - </div> r$ u- j: B% R* A4 ]7 y
- </div>5 Q7 u3 p6 y0 r5 E4 R# m# h
- ; n# Z, o1 e9 C; D
- <script>; p/ ^7 `) J' p
- // 注册
' r- F/ f! ?' V* `# X" d - Vue.component('child', {
. n" R3 F) k- T+ a1 ^ - // 声明 props5 h( i% d% v" ^$ }9 u. o
- props: ['message'],
( t1 z; K5 L, {- a2 n' _ - // 同样也可以在 vm 实例中像 "this.message" 这样使用! z5 t/ Y1 Z% ~$ ~& w1 S4 V5 R
- template: '<span>{{ message }}</span>'. q! K& ?1 F4 z# o
- })
3 v6 N% p6 x$ H% P4 ^ - // 创建根实例! E6 |4 @3 B+ d
- new Vue({
2 z A6 [( T4 |, l - el: '#app',- ?% a5 \) ]: ]: R
- data: {
H4 Z% c8 m) ] \7 s2 c - parentMsg: '父组件内容'
( z/ b+ z; U, D2 Y7 q/ n - }$ ], n6 H: X( l. t0 O/ Q
- })4 @' ^! ~& g/ H W, j! D- ^
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
# A) w' H/ ~- v$ O( s) f- <div id="app">
& e2 A( C+ m/ J" }3 H; a* ^ f% ~. P - <ol>3 P$ c6 P4 t: S/ s+ G+ `8 Q7 G" f
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
" h/ `, x8 y3 _- [0 f - </ol>
$ b( y i! r' W0 g - </div>6 B0 U1 m* M3 O: l; }) B! y- Q
- 7 b' ]3 L7 E5 M. S) c, ~ }
- <script> P" t2 s- R( p7 Q0 [/ V1 E
- Vue.component('todo-item', {
; c4 Y7 c5 u' A) |4 i - props: ['todo'],
# s% s4 D7 y0 }7 m - template: '<li>{{ todo.text }}</li>'; i* N' r9 w% v0 z
- })
! t6 I* U* H. v5 Z: s - new Vue({
- A, i% K* a# }: ?5 Y0 h, E - el: '#app',
- Y# @' U" ^! Q+ ?( T8 y) z1 m - data: {# f3 k4 @* J) c. C' v2 J4 X q/ R
- sites: [* N& T% |& ^2 Q& s# o% M F" q
- { text: 'Runoob' },
) q0 N2 C' r' ~ - { text: 'Google' },7 }6 w' y. [0 X3 O2 K3 o3 G6 b( w
- { text: 'Taobao' }
( R* g% C' c4 ^$ u - ]2 N) g0 N# v' G; C q
- }1 G4 H+ [$ K1 i) ]/ S, J
- })
3 v6 I% ]3 C4 k/ h) _4 f8 n - </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
, x2 P# O1 t D2 B - props: {3 |, y7 e) j) P
- // 基础类型检测 (`null` 意思是任何类型都可以)
# K1 C0 b2 t7 _- {- r4 Q - propA: Number,
* V. p% A- Q( T& ^+ K9 J, ? - // 多种类型
+ ?, i: u. }) h- T# a - propB: [String, Number],/ y0 v O% ?3 e B# O' B# W
- // 必传且是字符串* F) o" c1 j) p% n
- propC: {
% f) A4 a4 t/ e - type: String, U2 j4 R1 y8 z5 L
- required: true
8 ?$ E5 f, Q( b y7 n& `4 d - },
6 b& ^. W! J8 C% i) ^7 I( Z4 X - // 数字,有默认值
G" y1 _$ { U' V: k2 |; A8 I - propD: { H9 W* f) x6 ?6 d6 X5 ?
- type: Number,# p6 W m/ @7 }, \) N
- default: 100
6 A2 G! ~- d- j: }1 f: q% X - },
5 l0 a1 o6 _6 J+ z - // 数组/对象的默认值应当由一个工厂函数返回
, m& t7 x% N8 |' t ~ - propE: {
+ m. R" d% K, y' P" U3 {3 Z# Q3 ~ - type: Object,
1 S" r# `" x3 |. p$ S - default: function () {
- r9 I2 ~8 b' _! d6 e @- P- _ - return { message: 'hello' }
/ r% G; x8 Q* E) D* N - }: Q4 C( w1 ]1 f# m+ W: t
- },# l3 F+ j2 H0 g8 b7 \9 D- j) S# v
- // 自定义验证函数
" ~; O' M& w7 R2 G* @: u - propF: {
0 x0 L# m, o, V. [ - validator: function (value) {
" B8 b4 o/ {2 f# i7 n' {. w - return value > 10, D6 W/ G0 @: y5 o1 W* x# r# a. |
- }5 ~, y+ i x: t/ q3 H0 ]
- }: w5 _ A, `4 x$ h0 U( Q; u' b
- }
% I. Q i) ]1 ~ - })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array. ?) n' j6 P; r( k3 [; @
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件8 P8 c; R% O% E& U7 z
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例3 D+ X4 E* `2 d3 _8 S+ f/ d
- <div id="app">
3 u( h/ ?! R1 V3 u o+ t - <div id="counter-event-example">' M4 Q0 F3 S) V
- <p>{{ total }}</p>( V0 m7 ^# `+ F5 j/ |- L) ]/ \
- <button-counter v-on:increment="incrementTotal"></button-counter>
7 s6 m( \7 X; |. b: J& B( k - <button-counter v-on:increment="incrementTotal"></button-counter>
" G' H+ e0 U- h7 w) o8 x - </div>! R9 c+ z3 t0 g7 D* B$ }
- </div>
8 ^$ y* x1 O' Y5 W% Q8 [, g -
' l9 L/ {8 u: u$ j2 o - <script>
+ M9 E+ A4 k: H [% \+ b4 Y - Vue.component('button-counter', {
N* d/ J4 J4 F - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',8 q2 y" S% R# J" l1 T& N" V- M. k! L
- data: function () {& c7 b d' Z' L3 N8 U
- return {$ t: _1 }0 [9 g
- counter: 0
6 C0 L) q; c# z2 d - }
1 ?3 z. s9 k0 ] [8 C& C - },! @; ^8 x0 f; [* r6 c
- methods: {
8 p Q1 N! {, L3 H1 l1 X - incrementHandler: function () {
, S% e. T2 `( Z; N+ V - this.counter += 1
4 P7 p- i0 q1 k4 w4 U - this.$emit('increment')( M# c2 \- w- X4 n9 V% N2 I( `0 J
- }6 q( R' y% W3 q; Z8 w8 i* e ~
- },' L* E4 _& ~0 p3 [) l
- })
5 s0 U2 s2 Z0 ] - new Vue({
, }# L0 s4 b4 L; f) t, D2 a3 y - el: '#counter-event-example',
. y3 n# h7 T H+ I: ?4 X0 A( H% K - data: {
% P; n6 @( L6 b- O - total: 0
: a5 r! E7 q/ h( Q - },
& [/ b) @# W7 R - methods: {
* ?* Q3 ~. B: p - incrementTotal: function () {
* p. \. k; y- [* h5 A - this.total += 15 h6 V5 ?9 L: v$ J) O5 q) L
- }
+ k8 z U1 ]2 L# o, ^4 @4 J - }
8 g4 C: Y7 E; H, x: I - }), s/ S3 b4 Q& j. f. b: Q7 |
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册% b4 M% O$ S1 E$ H. K- p. H
- Vue.component('child', {7 [& X( A2 J/ h- `
- // 声明 props& w y5 j' v; M! J
- props: ['message'],
7 M ^0 `) B4 S1 M# X& z) ?1 A4 k( x9 ? - // 同样也可以在 vm 实例中像 "this.message" 这样使用
1 O+ M3 o0 B5 j1 H1 y - template: '<span>{{ message }}</span>'8 S/ [3 C5 j: \) C/ N
- })& [6 d" N% m# G" y* Y7 a) u/ ^/ T
- // 创建根实例
& |. W% I: h# m& l - new Vue({8 `( X+ T+ O# [4 w% e) @2 {
- el: '#app',2 X* P9 I0 q$ I$ D3 u
- data:{" B: u) B$ v Y
- message:"hello",5 a! C+ @2 U# n2 G- v5 w0 Q. Q3 ~/ z5 y
- }* C P4 ^1 P9 C1 d9 F( h2 O% p# p3 ~
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
7 X; D8 v% P! V; T+ a - incrementHandler: function (v) {& r, ~ u7 ^5 t. q+ ^ C( d
- if(v==1){
: d+ r' m% y1 W U& Z - this.counter -= 1- Z7 o4 W2 K" w( _& f: \
- this.$emit('increment',[1])
! U4 a e# R( k$ q# S - }else{- o) W* M4 Q5 q( N7 ^
- this.counter += 1
1 [( |& j7 P" P$ Z - this.$emit('increment',[2]): Z Y4 v1 }) S- b6 q
- }
+ }5 g B% v ]- \ - }
! D( y8 P3 @: k% }" |- x/ o* g - }
复制代码 0 b) ?7 G0 P! @/ m
1 T+ E, h# z& i4 [) f2 X |