组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它: 4 j! G& B# A1 m% U, E+ l$ U
- <div id="app">
4 m3 f4 J! i) }& [+ A4 E - <runoob></runoob>/ U4 C; A, b2 w% _
- </div>0 a0 Y$ Y$ {. G- D
- 1 R; o: [. I- j3 W- |7 u+ D
- <script>! A' y! u6 g. Y3 Y
- // 注册
9 F! x& q; A" J N# } - Vue.component('runoob', {
% W1 S" n/ N) Q2 C - template: '<h1>自定义组件!</h1>'. x& w, k" Z2 p0 u1 b# s
- })
+ ^4 h2 C; X. k/ T - // 创建根实例8 B/ ^( t4 l* m- j( u: M1 @! n& |
- new Vue({
, }2 r* d& z3 x" r8 M" t - el: '#app'
/ Q2 `$ M9 ]8 D4 W& U. n1 x - })
+ [) ^$ q$ T0 B) t: g' m" N) n - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: 3 i7 H: ?" t' | i" U; l
- <div id="app">3 e" x0 K3 @* D% r; `$ [
- <runoob></runoob>' d' f | j# l: e/ ]
- </div>9 ]7 ^+ |( x6 v3 l- d
- . d$ ^ ~0 k' O
- <script>+ j& f5 Y' b6 b0 N: p; Z
- var Child = {
# L5 z2 K/ Q! q- M4 D - template: '<h1>自定义组件!</h1>'
5 V' K# G' U$ Y7 a& p6 O - }
5 ^# M2 }( L3 C. E+ q) N' U - $ j; l4 S9 O! S
- // 创建根实例, ^4 w# e4 j3 ]- M' F. b2 V
- new Vue({
7 b+ X9 ~ e# Q9 g# T' ^ - el: '#app',; D: \2 J; \- Z( H, h8 T
- components: {$ l! ]$ R1 K5 S, v% D6 z A( _
- // <runoob> 将只在父模板可用8 l! _9 s! a0 \/ f
- 'runoob': Child4 D; y' o0 f& M3 c
- }
& J# F1 Y: n% J# l( r - })
" ~. P4 S- d! g- ~$ T2 M9 P - </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例, I0 }+ z! ]3 d4 T
- <div id="app">% I* s1 h0 v! b- g
- <child message="hello!"></child>
+ l: ?8 T/ ^$ J. l0 u - </div>$ q2 n' L7 L1 x
- ) l6 u {1 ^2 V5 @
- <script>0 O0 B+ m, l3 C9 {
- // 注册
( W9 G) t; A4 }5 z$ Y - Vue.component('child', { W. h5 c S& h/ Z+ c
- // 声明 props
0 F) I7 ~( {( E. h& @& O( g7 T1 j - props: ['message'],* @/ i5 Y/ m0 t P
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
1 z) i+ T6 l( R) b - template: '<span>{{ message }}</span>'' Q0 q) |3 ^: X0 _ V
- })# z/ [0 V( M) D& {
- // 创建根实例" q* w7 H8 r. a6 f* X
- new Vue({( C' ]5 y* t2 X2 p
- el: '#app'# j+ F3 w- k G; _$ V* q# s) v
- })- o5 B# o4 K/ d/ c( w9 U+ Q
- </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例, `' c. N2 Q3 y3 _8 O6 y
- <div id="app">
# o- g6 b( Y$ ]3 u - <div>
. Y J; ]+ m5 ~+ w! _$ t9 l - <input v-model="parentMsg">
, D) u) X* C$ p& p7 F8 z; z - <br>2 }2 r- D+ @: W# b" L
- <child v-bind:message="parentMsg"></child>/ \' H4 J7 a8 r3 F" j
- </div>8 k7 J) X. ^. {) b
- </div>
' w0 ]+ O4 Q6 h - 5 @/ K1 s7 Z; k. ?6 ]0 r
- <script>
7 X% z- J& a3 ?9 _: c( ? - // 注册( y9 _+ p, f) D7 Z; Q7 U3 x( a
- Vue.component('child', {+ Z7 h; w' R4 K+ F4 f o5 f. n
- // 声明 props
# v' a7 p4 r/ _/ } - props: ['message'],5 U( i( w0 w. Z: L: @: O
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
: Q% u1 u+ Y# \6 e7 U - template: '<span>{{ message }}</span>'
: i5 Y* r* K4 Q* n9 _- |* }" _/ M - })/ c+ \; |" i8 {. [2 C( }
- // 创建根实例
4 \4 j X7 U+ J5 j - new Vue({
7 U5 f2 ]# q: [( ^- v( ~4 v - el: '#app',
* D) ?) N* m1 n& S% x7 N! Z - data: {
/ b1 s9 {) N- w - parentMsg: '父组件内容'
5 G' ~5 ~6 l8 o& g% V0 P - }5 T* R" b$ q1 E+ Z" P- G) e
- })% Q' A" D3 G' x) m, p- ~
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
& e- c# O# \, K' y* ~- <div id="app">9 F# b T( n0 a4 z; c/ }
- <ol>; u% z, j& W3 N, H: H' g8 {
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
! O0 t G* ?8 h5 K) u: t3 t; e# ^ - </ol>
# ?/ y4 S7 S; e0 _ - </div>
1 d& J. n' S$ Y) `2 \ - # } v p1 ^5 B7 Y% D+ i
- <script>' z( v+ A4 y* W0 `2 N, ^
- Vue.component('todo-item', {
% W9 `" u# {1 Z7 `! E0 @. E1 i - props: ['todo'],7 V |+ S1 y- f1 a
- template: '<li>{{ todo.text }}</li>'
2 s @; q! Z6 C! e5 p2 [ - })
( j. g4 M+ R6 g& ?- N - new Vue({
/ p6 {4 b/ u9 u" k2 p6 B, R' D9 ? - el: '#app',6 b, h6 v# v' F. z4 f9 d+ j
- data: {! @: X U5 Y3 z% m( t1 g2 M
- sites: [
5 K+ M9 d) F- @$ [/ E# t - { text: 'Runoob' },
_4 _+ U7 P3 D- {5 K; B - { text: 'Google' },# g/ {* c3 i5 v) x
- { text: 'Taobao' }6 c* ]* X4 A& V# B
- ]
: ^9 ~9 ? d5 S6 h - }- w9 e) |( M" r7 O
- })+ v' a$ m& q3 w: ?& o' |$ i2 c
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {, c# l+ a) s4 e& r
- props: { i5 N5 h1 x1 A& X
- // 基础类型检测 (`null` 意思是任何类型都可以): S* J; s" M0 F$ q: v/ a
- propA: Number,1 ^$ ~) N5 }4 @& b
- // 多种类型
' \ b6 A' l Q* {4 { - propB: [String, Number],# L( z' i' K8 B/ H7 X9 r6 T
- // 必传且是字符串/ f) e1 r5 @/ g- g8 N7 A
- propC: {* |' K# @7 M; j
- type: String, ~# v. E- y- Y4 G* _2 q4 j
- required: true
/ a z/ A' f5 u& e: u" n - },
& L7 _1 ~4 S( e - // 数字,有默认值7 A' E! O; [3 N
- propD: {# \& F1 P" f8 g4 [
- type: Number,
2 k$ a( ?0 l) J# h - default: 1008 r9 _4 t6 K7 h& v3 u
- },
A1 P5 `( j. q& t9 T, a - // 数组/对象的默认值应当由一个工厂函数返回( g* t7 k( ]# l8 s4 b
- propE: {- Z1 Z" R) S3 k( c& ^3 B
- type: Object,
) N, n- y* i; F& t; ^ - default: function () {- U5 i. }- i3 h! O. s# M; q; k
- return { message: 'hello' }
! b$ l; x& y1 J - }7 \: B+ H" d) U Z7 X$ U! w3 ]
- },
, Z+ N' Q8 m0 U6 x - // 自定义验证函数2 j4 _9 x4 i+ ]! @) }; J
- propF: {4 Z8 t# h' S8 R4 ]
- validator: function (value) {
. j& q+ I' p6 E, l6 M, l) O, M' p - return value > 103 N- U* { u7 s' p% `& g. t8 B, g
- }
; m2 U0 a& x: V$ q L+ _. ~9 X - }9 `3 d. v6 m; K* a8 q
- }
) N+ v3 S* ^+ Z - })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
8 O& ?7 r& Z$ ]9 G! `( S" }* e( i
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
% C8 i* J' v- r( @
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例, K3 Q: C9 I2 l( Z6 r
- <div id="app">
( q/ I) f) H; ^/ e! D% ] - <div id="counter-event-example">
; r* f3 K7 n! J0 l- \9 F - <p>{{ total }}</p>
" U7 z6 r7 n$ G/ o6 f r9 _- o; C( Q( c - <button-counter v-on:increment="incrementTotal"></button-counter># O& Z! m0 Q' V+ j& m' h' K; w
- <button-counter v-on:increment="incrementTotal"></button-counter>
0 J" [% s& g# ]/ k) V5 e* V F - </div>
* D. E8 ~& g) R" N1 A- o% u/ d J - </div>
6 D( w, R3 G {6 r: ~ - . T9 T: c: y% w/ @' h4 P' ^
- <script>
6 {9 @, m/ b) L+ X) X) O/ S0 { - Vue.component('button-counter', {" `9 N" H' u- Y3 Q1 d
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
, |, `' b$ ~3 g J/ q$ q$ c - data: function () {# X- A% J# F2 Y+ U& L
- return {
: D: p8 P$ Z$ d) ~3 ` S1 V - counter: 0
- K0 B( P& B3 f w - }
5 W! p1 @- R9 R. `6 q+ N - },* j3 e2 a/ D- B# ?0 l' g) u4 V) Y
- methods: {
7 U" M h) Z# i% m2 _ - incrementHandler: function () { Z- ~9 C9 h* v5 a) W
- this.counter += 1
+ J' O- p8 F S" ~6 u - this.$emit('increment')
5 G8 b' e% Y+ a: P9 o - }: L) T& |9 L! h K# A1 w" I
- },9 w: c! a7 ^8 Y6 l' V G( C' |' i
- })7 [9 @( ?8 L" \6 P2 o5 G/ _
- new Vue({0 L0 O% z0 q+ G
- el: '#counter-event-example',- r% I1 c, }/ J/ H: J) J
- data: {% @# F9 O( }9 `
- total: 0
; K; ~# N) C- @# l9 I7 u0 h - },
* H3 ]' O$ {7 x& w9 I - methods: {( c) s B; @6 w0 W# p% _8 i, d
- incrementTotal: function () {
* T# A# \! K8 U - this.total += 1. q0 }9 _ ]$ c$ ]
- }! q# B3 z/ b9 b
- }5 u4 c+ v) L4 B, C3 O+ r
- })# |: |% M8 s) j/ C8 O Z
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册 O: h0 I- c/ I9 U+ E- w
- Vue.component('child', {
* Z1 Q& K3 O+ V2 p3 r - // 声明 props9 l* j' U) z( N$ o% k0 K
- props: ['message'],- c1 l" ?1 i7 N) `
- // 同样也可以在 vm 实例中像 "this.message" 这样使用$ j* e/ n$ v4 `. r0 @' J7 g
- template: '<span>{{ message }}</span>'
1 ]% o5 r7 F3 n+ w - })9 O' `+ V0 h0 |2 O$ }) h
- // 创建根实例# r6 x4 v. z1 w2 W
- new Vue({
1 h% r6 P% E( m. W2 h/ G0 o - el: '#app',8 i$ q' R3 D- A& N3 T, R, ^
- data:{5 v7 \6 ?! s* [1 l: C. I
- message:"hello",
2 [7 z7 k6 V- J- w - }
. q6 v# S" T: g% ~+ a7 r - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: { F# I7 _" [7 }1 d$ u" l$ t, l
- incrementHandler: function (v) {) C- x& F7 `8 P% ?, c& h2 U' v
- if(v==1){
) l9 q% _4 B5 h- x! @* P - this.counter -= 1( `9 z1 o/ B+ ~5 x# H
- this.$emit('increment',[1])
6 B( s# A0 p# B; K" t# Y& M" o1 f* `4 y - }else{
/ ^% L+ o% L5 Z6 }6 I - this.counter += 1
9 H/ D. F) T' A# u' N - this.$emit('increment',[2])
& u$ l6 y' j5 m' z" r# [3 _% j - }! X" D( u8 X+ o
- }3 f8 c4 ]( b! t& h7 H
- }
复制代码
8 Q! o( V% D ]/ N9 J6 @
! q; T* [. p/ D$ H) }$ D3 M* d, F |