|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它: 0 B8 q8 h* E+ t9 t' |
- <div id="app">% R$ z( M% r" n4 H
- <runoob></runoob>8 {4 _. c7 X }) Z
- </div>
7 G/ F3 H9 o3 \1 A- ~! { - 8 U8 Q: w9 L+ [+ ~1 D* ~
- <script>: {$ E3 Q# a- u9 Q* y8 X5 F; d
- // 注册
, p+ j, }4 p9 q- C - Vue.component('runoob', {, K b* t0 o+ N6 T7 b" n
- template: '<h1>自定义组件!</h1>'
+ n& m& H0 U; Q5 P4 f- e - })9 P# ~5 {; z+ z* o
- // 创建根实例
5 w! M: t7 c9 x - new Vue({
. p9 E( F: d7 M5 X' R) c& d6 m# m - el: '#app'
* u7 p( m1 i1 T. G: M* S& B - }) ]4 C' z) d+ @+ y& R% h& Z9 z3 X
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: $ {0 x% F3 U. k/ I. |0 o
- <div id="app">+ r( U0 o) y) B$ `) N+ r7 B
- <runoob></runoob>: N' ~ n4 n* @; j- D1 `
- </div>
6 f1 s/ }1 h3 Z8 q/ [4 q$ v -
+ b: }: [3 X. ~: ~8 n0 Y" D, k( K - <script>% O- S% v; }/ ]/ B+ j
- var Child = {
& \8 T+ D8 H0 E* N7 C' W - template: '<h1>自定义组件!</h1>'
# ~( K. ^/ k6 y, }0 R7 R - }
+ C+ f1 {! H' k -
) `. k& H0 X8 H. x+ W- t - // 创建根实例# t, \; D4 f; S- k
- new Vue({3 W6 Y2 v6 F7 \6 u7 p y# m L
- el: '#app',6 n8 a, R: ~0 S4 c
- components: {
( L, {5 [0 M& n/ L! h/ M' M: e; s - // <runoob> 将只在父模板可用
; o, ~# c" f/ M# M4 A4 \3 p/ { - 'runoob': Child
+ o( R$ r+ L( w* ~" l5 q$ e0 {2 i - }
) v$ O9 i, E2 U' v4 R( c& X - })
" x" V# Z8 w! s" x: k9 W - </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例( B3 D r; e! h; [
- <div id="app">; [4 _% @3 h" A
- <child message="hello!"></child>* o( x# [* d; l
- </div>
, B0 t. l, e7 S3 n# O) M2 U; F - ( F: C+ p5 P( P ?
- <script>+ c- u7 B! {8 i9 j% H, j
- // 注册4 ?4 W/ l4 U. d- |2 b$ D( l
- Vue.component('child', {& C+ r4 c* e! a" o% \
- // 声明 props; ~+ U" p) p: q% {
- props: ['message'],
1 G! i: q5 V, A% }$ I& C - // 同样也可以在 vm 实例中像 "this.message" 这样使用) G& X& F; S M: l' C0 z
- template: '<span>{{ message }}</span>'
; e1 Z; w0 {- ?# W - })5 |: S- ]' J* Z4 ~1 P( r
- // 创建根实例
6 R: G5 H7 A; e% e# i. d7 T# C8 Z- q# v - new Vue({: {5 k7 C& @& r0 S+ A; I1 F
- el: '#app'# s+ D# _' h8 ]' r
- })
8 U6 J+ M2 @# C7 Y( }9 X3 j - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例/ g O' C8 Y# I
- <div id="app">
( L3 X A; `& X" u( _2 L) C - <div>
$ A7 U+ e* n. Z" ^, |3 f3 i - <input v-model="parentMsg"> `1 a" `* C- p
- <br>
+ F- }8 D% `7 L; x. s; u" ] - <child v-bind:message="parentMsg"></child> N4 A& ~0 n" g& g P8 Y
- </div>" R6 P6 E! s: x( V
- </div>
0 V( C! S' \* J -
. U3 t" M6 F' a( b9 }6 T" l - <script>0 g! |3 G9 L+ N' S- R) R5 b" i7 j
- // 注册. x* u( |/ _8 T, M3 L0 X
- Vue.component('child', {3 V J7 ~3 y2 u% r
- // 声明 props/ B0 j) W. t. N0 }% B, v
- props: ['message'],7 M& N' V4 Z0 O5 j2 F( Z
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
3 |7 ^, ]6 U1 G* H2 C/ v - template: '<span>{{ message }}</span>'
1 O8 |- F. F" ?- T' @$ E - })
, r6 s9 h! u# c - // 创建根实例* l& B& W, }' |5 \/ K2 \. l# x6 q
- new Vue({: O' } w$ `8 E9 i- e4 @
- el: '#app',
# l3 C. I: F' Z l1 {( O - data: {4 D/ L; p9 ]; w# [5 b
- parentMsg: '父组件内容'- U1 G+ S" m' J) ?( K7 Y1 B
- }% v% H& q; F9 z) Q9 w( _
- })% P, e+ a1 j. G$ k Y$ ~
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例) a: ^' G S6 [* T* T
- <div id="app">2 N: w4 w/ p/ H- Z4 X
- <ol>
% @2 Q; w" M4 {5 l; q - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>+ F0 A: i2 L, p8 x
- </ol>0 ^- j0 |& T. d4 N6 [' Z
- </div>9 X# |* k+ h6 ~7 p/ p; c' H8 \
-
0 l% f' z/ t U/ H - <script>2 b$ a7 N- M; g/ k! B
- Vue.component('todo-item', {
9 ]7 a& e# _& P) w4 w% O - props: ['todo'],
% }* T5 y$ Q! D7 U' s- m( z - template: '<li>{{ todo.text }}</li>'
- m# p, X2 ?8 j - })
# ^. e, b1 z4 ?$ l- H - new Vue({
8 w j: K/ m1 Y. ?+ J - el: '#app',
. m8 v z/ m. I9 p( N; l; P1 w$ i - data: {
" e0 A _' E& O) C - sites: [, j+ ]* H" N( C3 q. D$ u
- { text: 'Runoob' },
& u' p6 g$ Q2 z- O; F! \/ Z - { text: 'Google' },( J; p# k% \$ _# K, a$ @* h5 B0 _, K: }1 v
- { text: 'Taobao' }
1 A6 E, `8 J- j$ `; m5 e - ]+ u0 t& U L$ q% d! E
- }
5 B! v; z5 m1 n2 n$ M - })+ r. I( D2 H' v ?) Z( b; Q
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
) o* b8 k6 o* p5 a - props: {
' ~# g7 U9 L9 J+ y' o" e$ e - // 基础类型检测 (`null` 意思是任何类型都可以)
$ U' v% {2 l$ U* s - propA: Number,- Y, } F3 I4 h z, W) G* K$ f ?
- // 多种类型
' a. \) B+ J1 [ - propB: [String, Number],
8 Y- f8 Z) w% o, s3 Y. F - // 必传且是字符串
/ e C, s% X7 J# V0 c9 L9 U - propC: {
( X* q9 ?% H' q4 V0 {! j - type: String,: y! ]; @2 c _* o: k
- required: true! K a$ q! M: Z7 a8 O
- },
3 s1 T4 Y' B: m, X8 |3 b - // 数字,有默认值8 E: r$ `- T$ z9 [( X
- propD: {7 V$ L& [& g1 p0 P9 @
- type: Number,
, U2 M# ^ N ]" A1 _ - default: 100# A4 R' P. y) F
- },/ i4 S- F5 W9 E$ V0 z% h' r& c
- // 数组/对象的默认值应当由一个工厂函数返回
7 b6 j) d* s. s% F; p5 i" J - propE: {
8 {2 F( u4 l$ ~ O - type: Object,
5 f+ J& f7 H& |% T; _1 X - default: function () {
( C+ {* a& o) \9 d: ]$ `( j - return { message: 'hello' }
3 z) {: Q( S- z - }
$ l9 L8 e8 S) \# r1 u8 ?3 G - },! t& U3 M( x* B. G% s
- // 自定义验证函数
& w$ ^' G' b/ L - propF: {- @5 u# O* t+ B% u
- validator: function (value) {
8 p, [5 o$ P" k - return value > 107 C8 {2 v8 o8 V
- }2 I' d: l# ?# d. n% h+ [, v- |
- }- R# {+ S/ e! I( D& ?! s) f, n4 `* _
- }
* M- U. ?) c, Y+ B; O8 J4 @ - })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array; x* q/ `: J8 L
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件& w, i, B/ A" `$ Q1 n
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例# p2 f& k# Y; u1 u# ?# [
- <div id="app"> h, ^* E6 d. ~, n# t3 X
- <div id="counter-event-example">
2 w6 o# j2 y1 m- k( M: I - <p>{{ total }}</p>
4 h: f0 j9 r6 ]8 i0 V - <button-counter v-on:increment="incrementTotal"></button-counter>" _ ]9 y3 k3 @8 j0 c9 j# N, w
- <button-counter v-on:increment="incrementTotal"></button-counter>4 }. e8 H, J. g2 t( O
- </div>" U' H4 A2 v1 Q( |" F
- </div>3 Z1 }; C1 i( y# N; V9 [2 c" `
-
$ w( T4 f) O$ F3 ^, J; E" q, r+ t - <script>
" o, l! S# k8 F! V5 d& z) u$ Z( Z' d - Vue.component('button-counter', {
5 U, v! E1 I6 L" B - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',) Q! {$ J0 z9 [ s
- data: function () {* C: Q% c D* [/ V1 B
- return {
: j- M5 a& k) T - counter: 0- @3 u, Z5 z @1 _! K7 l+ ^) w
- }1 x$ n- Q& g: B2 r3 |7 x
- },
( |* A* q" U, {/ l( B - methods: {
1 {" z3 v. w [* q - incrementHandler: function () {
9 K3 n# I. Y( b9 b - this.counter += 1
0 g/ B: H( D" L8 A# l& C - this.$emit('increment')% M# V0 e+ p7 j
- }
, ]8 _# ]. q6 R' ]3 _& ] - },0 `+ K9 _/ j* W$ @
- })
8 w# I! `& |- ^2 n. c - new Vue({
% C4 I$ m; e6 h, d, b; {9 _ - el: '#counter-event-example',
. u) F; m1 y) r# g% U0 p - data: {8 \4 k; Z. h# ^3 n( V( Y) `
- total: 0
# f. R& a+ t V6 |" m0 l$ l6 c+ I4 S+ h - },
1 Q/ N; g. C$ N7 w4 f% Z8 Y - methods: {
3 A4 P$ w M) _9 ] - incrementTotal: function () {
$ B( j1 g: u2 A6 y O - this.total += 1
P+ ?8 R! E/ ~3 N+ s" h - }
' @. s5 M( p* \8 B6 E - }9 Y" [& _, Q q- x
- })
b" ]& A& J7 `: n. a! K - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册2 v4 x1 M" ]' K V+ Z
- Vue.component('child', {
$ c( n$ t0 @( @: h$ G6 _8 r! G - // 声明 props, D* D) }1 E# r0 w K6 W
- props: ['message'],# B0 Q$ C% ]# }0 k5 {4 W
- // 同样也可以在 vm 实例中像 "this.message" 这样使用" X. J: L# |. @' r
- template: '<span>{{ message }}</span>': H" f# Z' `) q
- })
' D, s1 F% e( J8 \5 p: f3 ^ - // 创建根实例
- S* l, |, f. H/ m - new Vue({
' K: D9 a6 v6 c( c' Q" @' y - el: '#app',( i& y/ _* W# D( }* i" t
- data:{
& x" K! D; d* Y' k - message:"hello",
% }& Q9 o3 {; _7 N, x - }- U+ j& J, Z' F( b
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {. r; q. z& r% I+ N
- incrementHandler: function (v) {
7 e: d# \: p- {7 x. @! g - if(v==1){2 Q/ _% M. _5 B$ R
- this.counter -= 15 M; _9 I/ @0 h8 {6 M* [& a
- this.$emit('increment',[1])- y9 @4 p2 h' P- G& Z+ Q& [6 X3 b
- }else{5 X* n" F: \; v9 ^+ u. U( N9 P9 E
- this.counter += 10 k2 S& H/ r+ s: Z/ R6 w
- this.$emit('increment',[2])
9 t; r9 c9 a9 {( Q8 @( {9 g! f. u5 Z - }5 B, V& e, N; E/ @4 p
- }9 J+ V3 n+ |' l, E! N
- }
复制代码
( {* |; k$ u6 Q: ~: V. f8 m: ?. z, p9 |+ `) L
|