|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
- h' ^. ^! E7 O9 ^% h1 L8 b- <div id="app">
( g3 ~: {$ |2 ]& C - <runoob></runoob>% N9 W% ]1 O m/ F8 X& Z2 x: k, l
- </div>. i& O3 q; X$ E2 E& b
-
2 C2 }; n& X% {7 B3 h" y# W - <script>
0 M0 u( c8 }: h8 y% C: ~4 u( q - // 注册" W$ I$ {0 d/ h7 z- k
- Vue.component('runoob', {
/ C' _& D. Y: ~* y0 [ - template: '<h1>自定义组件!</h1>'
% S% z( C& u/ S( e5 z P* F - })/ d; c+ R! G V' h; L* G# ?
- // 创建根实例
( B& u: E2 H# T% b+ { - new Vue({
; |( K& Y! b7 G4 k# S/ l Y" m - el: '#app'
B/ X0 B0 q5 D+ x' f - })% [) i) x' t5 p! q: D+ Y
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: / C+ N3 C: o/ d& t
- <div id="app">8 @; A9 G f$ f
- <runoob></runoob>
+ d6 S: w; L- ~6 a) }/ U - </div>
/ }$ s( Y% R* j2 J% U% r I% ~ - * u4 H4 Y) d1 M! E3 e4 Z
- <script>
. G9 i* [; B/ _ - var Child = {1 J& B- a* Z! Q: ~ C( m
- template: '<h1>自定义组件!</h1>'
/ @# s: g( {. i1 L - }
- `1 q- k' d* w/ b -
& k9 C! r5 n4 D4 B3 v$ u - // 创建根实例5 i N. K, D3 H+ F- z, T
- new Vue({7 I) y$ u3 ^9 Z* C4 U
- el: '#app',/ |$ C1 ]2 w6 w( a2 F
- components: {
0 S" ?" w! ? \$ [ M - // <runoob> 将只在父模板可用
4 _4 L8 _3 E- A - 'runoob': Child S$ a& h6 Y8 v x, o+ g p
- }
2 {, S v5 C2 l$ ?( @# Y3 y - })
/ G9 W W' q, ]$ x: | - </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例& D$ G/ i9 x4 M7 `6 ]8 p
- <div id="app">. n; |+ i A$ A
- <child message="hello!"></child>
2 G0 }% p0 V8 r2 ~+ V2 a - </div>
U9 B& Q: _% o& G O/ \; v - ' O3 ~+ ?4 {: h, M- d2 @
- <script>
/ O! W8 A# n2 I - // 注册3 H7 q [ x- U( R, f" N5 o4 U
- Vue.component('child', {& w2 K. F& ~( U! J
- // 声明 props4 x# j7 A' a9 p, S
- props: ['message'],: Z, l1 r% ]. i( m
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
5 }, Z* w. q! e+ x. A$ t" s8 M - template: '<span>{{ message }}</span>'' k4 S" E# `1 L$ `& ?
- })
5 M+ _# i6 [& L' F" f0 I5 r! H - // 创建根实例
# h! \9 D1 N- z - new Vue({1 ~# b ?( F( S1 B5 F; B
- el: '#app'# p, l x3 H7 I' T) m. K W
- })
+ c& U3 u1 H" e7 I4 N - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例6 Z: j7 q8 w) ]. q! M/ y5 x
- <div id="app">& g+ w: g- [( [' M* e5 _* s1 ~ m
- <div>% {7 S; P3 C1 Q8 {. L- `8 t
- <input v-model="parentMsg">
$ k3 [4 C. I7 ~8 u) I - <br>( ~( M( d9 t6 H
- <child v-bind:message="parentMsg"></child>/ w* V" y' W6 O
- </div>! l" |) j, o' k0 N
- </div>1 ^ F; t2 b3 A0 H) r9 h$ B x2 p
- ; n* b8 U* [, M
- <script>
2 r4 _! j" _. L - // 注册4 J5 }" }9 K" R
- Vue.component('child', {
2 F+ {. [" {8 T# X - // 声明 props
$ L1 ]2 Y3 Q1 z& u/ F# [; u - props: ['message'],
: @- ~( p$ N6 N! w# ? - // 同样也可以在 vm 实例中像 "this.message" 这样使用
% S1 ^- I/ x, B* K5 |" S - template: '<span>{{ message }}</span>'
# R6 i% X: m# o/ e. R - })& k r2 m0 q. p# z. K* X
- // 创建根实例
5 I$ v, F; a! \2 \8 w. O - new Vue({" n1 M/ c+ c) l# w8 k
- el: '#app',5 o' }5 U1 j1 \% `2 O
- data: {; H) W' e( S0 ?2 h; n
- parentMsg: '父组件内容'
+ s9 n0 i: g9 ^+ y - }
- ?. B2 c4 N k - })3 K+ W$ C- f& K$ `: }
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例) A. c6 Y1 V4 G2 \3 g3 j. n }6 e
- <div id="app">
9 R9 z. A) \" j/ X" @6 x6 h - <ol># g6 ?, l4 E$ g- y( D* {0 q
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
7 g; Z- {/ A u - </ol>) M& i5 z9 w& n8 B- P
- </div>
# e9 C0 w; {4 \& [0 T( V -
( u( s# i' ?: U/ W6 x - <script>0 x% y5 P4 ^& P+ Y9 Y2 U7 x5 \2 Z! u
- Vue.component('todo-item', {
) F$ F5 S4 T" h- Q- I; J+ O) ] - props: ['todo'],8 A* _5 r# O! N1 i0 _: Z% g
- template: '<li>{{ todo.text }}</li>'+ h3 Z8 K, m" k; z6 w0 S0 H
- })
$ Z# |+ K0 o/ P0 H: k( V) z - new Vue({
Z; O& X% _* }2 s. h' N2 Y1 g - el: '#app',( `. z# L' V- e6 C' L
- data: {9 [, G! f6 q9 U6 v
- sites: [
. O1 B$ K2 H' g) r - { text: 'Runoob' },
! Z7 f e& e Q4 s9 U: P1 g- Z - { text: 'Google' },% W1 G( H& V) \2 Y8 U9 {
- { text: 'Taobao' }: b6 I: t. [$ A- m" i
- ]
" `- M* f C" r# ^0 m9 b - }) _( E/ q1 \% d# b
- }), c7 T& \' ]0 b8 s$ ^$ o. b. I
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
* ^7 e. f0 I5 M" z - props: {" e# @( W+ f+ k* n5 B9 f
- // 基础类型检测 (`null` 意思是任何类型都可以)- D2 P4 `# c# k
- propA: Number,
1 D' I( y. A# V) x - // 多种类型
' p6 I1 V* @" M! m - propB: [String, Number],
0 n7 K8 ?* B8 y& R9 J - // 必传且是字符串8 R* j: ?! [4 v5 w" ?1 x ^ [# F
- propC: {6 g! l7 H4 j, c- z3 e( B' O
- type: String,
( J& G- a6 J2 i8 B! |+ P+ l - required: true. r" O$ N) w8 N0 H! e/ t- u( }) C
- },
7 [5 [2 H( A4 Z9 A# Q& W& Y - // 数字,有默认值
8 ~9 J) [3 i0 V2 n - propD: {3 B' ?1 @( l- O% c% Z) X$ G5 C
- type: Number,8 |4 p F9 T9 P- T! @% g
- default: 100% d [% h# ]. T! p$ T; m/ u
- },
# L) S; }, W" | - // 数组/对象的默认值应当由一个工厂函数返回5 h" Q- R- }8 J8 Z8 q$ y9 e3 D
- propE: {5 O ]. s/ z, s4 B3 B1 T
- type: Object,1 ]8 Y: q9 T5 d* x# S" K2 `2 A( p
- default: function () {6 v7 y J7 o" r" m
- return { message: 'hello' }+ I- N+ \1 \/ Q2 H
- } W. d2 b* v& ^
- },! K; i' r5 W* X% |
- // 自定义验证函数6 u8 }5 {8 y4 ]8 e6 F) H
- propF: {7 Y7 z, H$ \( e
- validator: function (value) {5 Q9 J6 W/ x" j
- return value > 107 _; o" K ]( o, u, o
- }
) ^- W" b! k3 `- k+ z9 p - }
) S5 A* |4 Y# f. C) Z% R - }
: E& F- G1 _$ I' K2 _6 H - })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
% L$ f% F' j+ C$ F) P( _
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件; T+ g$ T8 g$ O& _4 H: W2 a
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例
3 I$ q" f6 Q" c# p4 E1 V- <div id="app">& W) I3 T- a, k7 O! `
- <div id="counter-event-example">
' c- z' R% ^$ p9 k - <p>{{ total }}</p>+ {" k2 j9 Y2 P- I/ p% U8 z. r
- <button-counter v-on:increment="incrementTotal"></button-counter>
8 T, g! @# l% p/ F - <button-counter v-on:increment="incrementTotal"></button-counter>
! I) W! y6 |( {% ]8 M) m - </div>
9 P8 c- y) ]; N$ r8 e: C - </div>
( o" _, Q3 }) A3 G- y - - T% A P3 X+ c) ]- l" G
- <script>3 g% b8 [- {; A2 `0 m$ ^ X
- Vue.component('button-counter', {- t7 c! g0 I2 w* I A
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
: x# m# ^/ w" x7 O - data: function () {
8 ~7 A# l( D$ a* U1 K3 \$ q - return {( m2 ~. P5 T# M
- counter: 0
O# d, d6 r k5 q - }
. c! a4 o' }( Y' g - },7 S- p: E# ~; H# ^% t9 _. |$ l4 \
- methods: {1 e7 n9 v6 ? N3 J8 W
- incrementHandler: function () {
: H% o* X. p s1 X: P# N% E6 J - this.counter += 1
x. t. x& r0 H7 G/ p% l/ v - this.$emit('increment')) S2 d% Z3 G7 w$ U) \' Q' O6 ]
- }
7 y( p/ V! i2 I, c% H2 ^ - },
3 X9 ^( v" @( M3 u# k$ C; w - })9 T+ s6 c# y+ Y4 Y g
- new Vue({# ?. w; N& L% H
- el: '#counter-event-example',
1 S' N; t* c" E; |7 T+ J+ E3 X - data: {7 ?' J! ~- w$ \
- total: 0: f! d( S2 P' F/ l
- },
- x, G! k3 t" `, a/ ? - methods: {
# U9 {, E! Z6 s) c3 c - incrementTotal: function () {
_9 w6 g( o% n2 T - this.total += 10 @; n7 D/ O$ n2 j
- }
* Z1 c( w. y: G - }& E! L( T4 J- a* R3 z( o
- })- `+ b6 K' p* f& d K* ` i
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
% d# {4 S0 K% F. O) G! _1 A6 Y - Vue.component('child', {
. i, a! i+ N5 e7 H3 O8 z - // 声明 props5 J) Y/ v6 f; ]. L
- props: ['message'],
; E5 m1 O# ~) ]2 U ]. _ - // 同样也可以在 vm 实例中像 "this.message" 这样使用6 R8 q5 b& J: E0 _/ p. C/ b7 L
- template: '<span>{{ message }}</span>'9 B) p; y) s) q( Y' c( O% p
- })6 {+ u9 E, F; u- {
- // 创建根实例
8 F E% U, t1 M" F' X# C7 v - new Vue({4 X0 v- r3 v% o% N
- el: '#app',$ K/ r* R* g3 b4 h4 d# P. t, i
- data:{; N B4 g: Y- [ k$ C6 G2 X6 ^1 _6 d
- message:"hello",* |5 F2 Q; e" Z# \4 A1 z4 [
- }
7 ?4 h( h( x% M, K4 f - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {0 k" Z/ v3 B7 o; J7 s: q7 Z& B
- incrementHandler: function (v) {8 X% P6 V) O' k8 A2 C
- if(v==1){! p3 j. G5 t: k: E
- this.counter -= 10 [6 |- h( q0 `, W6 @. J5 Z
- this.$emit('increment',[1])0 `) h7 l3 F1 j3 d5 |) e7 b
- }else{
( r1 \/ }8 | S) t2 } - this.counter += 10 w2 f$ Q) K: g
- this.$emit('increment',[2])
& y* }8 L# S( F& Y4 s - }! J5 s* |' h" |
- }
2 d* ]$ T% r3 y4 B p - }
复制代码
6 Z! @2 P2 J7 j4 V- Y
( [ a }9 h' [: C& ?7 K |