组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
) M! |2 [8 v0 ?2 p7 T, r, t$ X- <div id="app">" k% R1 J" z3 n
- <runoob></runoob>/ l$ i! D* a" E( g
- </div>& O( \9 P w% h, K2 N, b2 N
- 1 M% r9 V' L' r: N5 U6 {0 X
- <script>7 T% s6 I5 Y; y
- // 注册2 Y+ ?* A' _7 M* D
- Vue.component('runoob', {9 V9 y+ K( t& q4 O9 Q! C q3 P
- template: '<h1>自定义组件!</h1>'
- |7 e8 l4 u( y3 N s' j - })7 q$ r& T; q9 ~; N
- // 创建根实例 g8 }0 }) D& ^0 f" C
- new Vue({5 M! {# T. b' {
- el: '#app'
" l6 k9 z0 o- o& o1 e, O - })5 X- u9 q7 I1 t1 Z6 \6 O' W
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它:
' d; S. d1 x, ?+ A* {- <div id="app">
8 n0 j4 J% p! V - <runoob></runoob>$ q7 t0 Q W( M9 }9 E( b
- </div> j! `1 v+ n/ j5 h2 S' G
-
8 C) @* g( ?8 D; n: h' B - <script>6 w! }1 N3 q2 N* y' o
- var Child = {$ N7 C3 ^. g) |
- template: '<h1>自定义组件!</h1>'
0 s1 r. Y. \ \. I2 K - }, h' \/ }. ?* T
- + t$ A B. I, a
- // 创建根实例
! ^* f$ L$ K" S- g% k - new Vue({
8 V/ K( S0 B0 c2 l, B& V - el: '#app',
0 T- @4 o0 e5 Z* Y9 y- H0 z - components: {4 W4 V2 t& C2 V! T* a" s/ ~4 _
- // <runoob> 将只在父模板可用7 D. |2 l! }2 U" K, B
- 'runoob': Child
, U" K5 {' [7 ^) _! G$ ?) h7 U - }
6 x( M/ L( N V5 N) e - })- D( U( n' Q% u" @3 Q* y
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例9 h P6 [7 \3 g8 [6 a/ j. Q; o
- <div id="app">+ U2 B, A$ V( A$ C" l9 ]
- <child message="hello!"></child>0 z2 ^1 N; f2 s1 g3 e. ?3 O
- </div>/ x$ t1 [7 G' w3 q. a
-
4 ~8 l$ m/ Z# F$ c; s, ~ - <script>
; c, {* w. @; Y! @: N7 M* x) g- g - // 注册4 z- n$ V3 U7 L% w, t
- Vue.component('child', {9 N Q& W8 N- X. U
- // 声明 props i4 r5 w0 H p
- props: ['message'],8 M1 j$ i- ?/ _
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
4 X. [7 o2 j2 v2 ?5 N1 A" a - template: '<span>{{ message }}</span>'
* k9 t& f4 P& e+ E. M - }), `3 E( V; ?0 p* w
- // 创建根实例
5 x# z1 ?; V& _; _+ U$ f& r- I T - new Vue({; A5 d4 v" d7 y |3 c, H+ J3 z
- el: '#app'2 w$ z9 L& I9 Q
- })8 s$ p$ l; ?8 b4 T# N, y& `0 {
- </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例' P$ _& `9 e2 h# U0 a
- <div id="app">
" ~: m" ^: a( |9 q7 f3 |3 A - <div>: y* \' {% g" |, h7 f! m1 S) `0 T
- <input v-model="parentMsg">
9 P$ @6 s" ]4 K* I) p0 t - <br>3 F/ R& l: }% h" ^8 Z# X* v" d
- <child v-bind:message="parentMsg"></child>
$ S" f& I$ ?1 i- ]$ K - </div>; N2 y/ O1 f8 G6 z8 @& J
- </div>
- R- Y Z4 V# a* Y3 _0 `, E - 1 g9 O6 c4 t/ E5 N& \7 U3 r
- <script>
/ R! H L# e% v4 I3 [! l. n2 P - // 注册
- e, \, a; v7 `7 ~9 k - Vue.component('child', {
! h) j4 Q. e! S% m# Y/ O$ b6 x - // 声明 props
9 I: V' [) U* u/ g# j - props: ['message'],' j# ^" J* @ S; E
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
+ l* L8 l. h; O z - template: '<span>{{ message }}</span>'
0 g' c0 n! n0 b - })9 J" m8 }! G3 S: }
- // 创建根实例& K" G" M' Y; g- l9 R
- new Vue({# P- n2 }7 n5 G' ?' ?6 p3 \7 A
- el: '#app',- D% E6 ~8 I) b. m
- data: {
, |- A1 K! D$ [8 X3 e - parentMsg: '父组件内容'
# ]0 w9 X- [$ g& \ - }6 R8 n/ K* d* E5 m, D4 l( E
- })
6 q; b7 {9 b4 W6 O - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例+ @: J, A) V$ m9 R# a: _
- <div id="app">
' d/ e9 s3 U' D! _) H# _ - <ol>
% ?. u, a }8 G& d4 G9 P- U C" | - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>5 y. S5 Y' G8 N2 E% L# `! Q5 u
- </ol>
7 S$ {: R: o2 c' A. T4 R5 r" G - </div>/ ^6 R, P! s# u
-
; D$ q. ]- R1 H$ e3 N z0 L - <script>. C @( y( e Z% T* W
- Vue.component('todo-item', {9 K' N4 E1 t* P2 C8 h- Q/ j
- props: ['todo'],
- e! A2 D2 l& {7 t8 } - template: '<li>{{ todo.text }}</li>'
; A! y4 D w+ o8 g - })7 b% M+ l5 ]' z g) \
- new Vue({
' a; x$ r* S$ F( B/ D4 D - el: '#app',
, k# p# b$ K! C- V3 s8 T/ c+ G& m - data: {
) A6 J) F0 d4 g* L, U' N0 e - sites: [6 n0 _/ Y6 q6 t% f+ ^$ f
- { text: 'Runoob' },
# M; Y3 O9 S) z2 ?( H# g - { text: 'Google' },4 n: d5 _; Q; f; O
- { text: 'Taobao' }
; I% Z+ i' \, G - ]; U! b9 g. A6 ]/ X% I" ~
- }: y6 }! o! |! K* V9 H- l0 Q
- })& F3 L" p" C" x+ H
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {" Q/ l5 c3 h$ Z
- props: { W7 g+ {. O0 T" H! E# b( ~
- // 基础类型检测 (`null` 意思是任何类型都可以)
" \1 O9 a3 }3 G, V/ t - propA: Number,
3 q. p3 l& G3 f+ b+ s3 n - // 多种类型
$ A8 d" H- z9 y+ p5 x - propB: [String, Number],% J# H$ E7 l3 ^9 [' T/ y
- // 必传且是字符串
# J S* P+ a5 I) {8 k8 `9 n5 A# P% u) b - propC: { K- V; L* O% N0 T7 Y6 \
- type: String,
9 Q' N& g( l- ~3 P! E - required: true$ X: `$ |' s! A& \- s, s6 M
- },# w, b7 q% A( _+ z& ]
- // 数字,有默认值
6 n2 Q) D, i9 e6 F' g+ N - propD: {
/ k: ^' P# T/ ]! l8 c4 R - type: Number,
, F" i- g( X1 k1 p - default: 100- y6 s+ S7 p# Q& }
- },; \9 O3 k# b! {2 W+ W% _* _
- // 数组/对象的默认值应当由一个工厂函数返回
6 r: ~' z' O' P; F# n - propE: {2 r& Y6 E- b) {+ ?' [ x
- type: Object,
6 A5 t2 m" y4 \ - default: function () {
' m. s5 R6 `$ c3 m - return { message: 'hello' }
& I: | W' D9 w* D4 d% ]+ Y - }
( v( s5 u# R+ k y( O - },+ h9 r: h' F. f9 k: T8 O; E
- // 自定义验证函数
# n" _* ?! @5 }# w, v1 [* Z% p$ R - propF: {
; G8 `4 P8 g" y4 U - validator: function (value) {* _; Z2 K, c" N3 x& d
- return value > 10
8 J. X0 X5 E2 k6 X8 Y R& S4 t - }5 [) f+ I. _6 X( L9 k
- }$ `2 e/ ?# y* P/ V
- } `. E! D3 B# Z' ]" h8 M) u
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array2 U) A% D# N/ ^: b% |4 `
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
$ [' B1 p$ t: }" z7 O/ y9 Z
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例
7 o4 q5 o( `% P, P- <div id="app">! t+ e6 w0 p# D9 S$ O( n
- <div id="counter-event-example">
# O+ E! \- o; j) W# H5 P - <p>{{ total }}</p>
! A. X' }9 a) E+ h- p8 A' ~# k7 y - <button-counter v-on:increment="incrementTotal"></button-counter>1 O. d# {2 a- R" P% F8 I8 E q
- <button-counter v-on:increment="incrementTotal"></button-counter>, {* j: g ^$ I& [7 z, R/ g* q6 [
- </div>
' a. n" O8 H8 o" r2 c - </div>
& v4 o2 m$ E% @" T -
- E. f4 H4 j- U) f8 L; ]0 E - <script>2 D) J4 g% a" v" V8 S4 F
- Vue.component('button-counter', {6 G% ?' r2 r& ^' [
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>',6 G2 b' Y/ ~/ K5 w3 O: U- z% T
- data: function () {$ d( Y ?" C* E# L2 P0 l8 ~0 T
- return {
) c1 J- X: @8 X W6 @: i x - counter: 0# X% j* b3 n( s& Q
- }# v! f3 t: S$ A1 g- Q
- },
$ X( I: ], ?3 G7 a" {' T, | - methods: {% w! N1 y! X8 W( G8 ^
- incrementHandler: function () {
7 G6 h( x+ U! i* s* {! s - this.counter += 1
8 o' K7 g1 h# C - this.$emit('increment')7 ?- ]! h7 [4 }; N! |5 E K
- } N. |! b7 ~( g- k& F7 t: y
- },! B& z) y+ O6 _4 Y$ m
- })) V2 x& ] E! r) t
- new Vue({; y7 i; U) a8 E8 [2 D; Q
- el: '#counter-event-example',2 l" y b, t$ D! N8 Y$ G
- data: {
( R! r6 e R3 P# z" N: D/ y0 | - total: 0
8 r) a7 X9 i3 `. I - },
. O8 U F4 p) c1 p( J5 E( k - methods: { V3 c' `+ U5 {) \5 R- ~
- incrementTotal: function () {) _8 C! L" q, @/ m. d3 v
- this.total += 1
& N& y+ k y1 Q3 O4 q* D - }
, j! \6 F' A' a: d - }" h; `" E$ R5 p5 L7 M
- })
* h( }1 ^9 x) ^$ }- y - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
$ e: x% \6 m/ [/ H- Q; h! O/ D" n - Vue.component('child', {. {/ X3 y, q$ {
- // 声明 props
- _2 }6 u& k5 B4 D) W' Q# ~ - props: ['message'],/ X3 F6 P6 `; r( x# m0 s" \% d
- // 同样也可以在 vm 实例中像 "this.message" 这样使用; }) |$ q a0 a2 J. w% L V2 R
- template: '<span>{{ message }}</span>'3 {8 z4 s4 B- g- Q7 C. z
- })
5 i6 n. Q' q+ U! K) T- [ - // 创建根实例
" _) m. U- T( l; l& m" C& ^2 Y - new Vue({
' _5 h9 ^9 e$ n/ e2 V - el: '#app',
( g5 `. p" k3 ] - data:{
) u7 E: q. C& y3 u& G6 q; Q# P, F - message:"hello",
! V# ^2 X2 Y- g! S - }6 t8 t2 @+ ?* x
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {
/ Q& o5 s, \9 N3 _0 g2 | - incrementHandler: function (v) {9 _2 [$ Q- |: G* w: v% w- ^& @" F
- if(v==1){
( ^( r, Z" i8 y! K0 R _ - this.counter -= 1
! @5 D4 _( ]' B+ N4 Z U& f - this.$emit('increment',[1])
8 p5 H5 T% e3 F* e) D - }else{
6 ^5 [: U: o! b% d: K. Z - this.counter += 1
9 d D2 @$ W& x - this.$emit('increment',[2])
% ?* o) U$ p# ]4 S& I& r6 f - }
# O: D4 Z9 d2 T - }
7 m' {0 ~/ T% Y - }
复制代码
0 }( C4 @( O7 Y: i' s5 h& e+ t8 _1 o1 A* o& J
|