|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
$ u+ v9 p* M! T8 B& G- <div id="app">
+ y# `" G: }+ y. P3 p8 J9 j7 M - <runoob></runoob>
" a* Q8 a; z: ]1 n - </div>
4 y0 u" e% o5 P" w& p8 D, u -
. \! S I1 f( V: c5 Z; I7 k" ] - <script>% ]* v/ H. a, Z0 ~0 [2 ]
- // 注册
8 o3 M2 K" H( f - Vue.component('runoob', {
( M" f$ ^, N/ s$ C2 L( [! M2 J - template: '<h1>自定义组件!</h1>' k7 ?7 ]8 k2 d* G& ]" M
- })( {) I9 X1 A0 A1 d+ w& c
- // 创建根实例7 w f& U6 a3 c. C1 F( C; F9 b
- new Vue({6 l* W$ G- D) T" t, r. q" ]
- el: '#app'
2 T% x _: H2 n: t- l* t0 s8 c - })
6 _8 Z/ j+ m3 q8 g - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它:
6 l7 Y. t1 M) O- <div id="app">2 t {+ n8 @) S% t( V( ^' V9 v
- <runoob></runoob>
7 p# W6 n9 {0 d" `; v6 z' o$ ] p - </div>
3 j( A" S# Y+ G1 P; M, z" i- d - 9 S% h Q' R7 m' t& m) h0 ?
- <script>. |7 Q* G/ i: h2 G6 J
- var Child = {
+ Z! `) v: x0 _9 e' c# w - template: '<h1>自定义组件!</h1>'
% p4 v* A! O8 b( S K8 M - }5 d0 p+ W9 g' ?" B5 _
- + w( i h" |6 W$ `2 N# c
- // 创建根实例
8 ^% v( X# H `& \$ b - new Vue({
% q/ O5 b3 g+ o6 _) |: P - el: '#app', r5 ]" d# d# ?1 O! E, Y9 v
- components: {" y" |6 h% Z* L, p
- // <runoob> 将只在父模板可用5 F3 W) T2 P0 d$ P
- 'runoob': Child
8 k7 r" d1 G. d - }
0 ]8 q5 j) V6 P8 R% W$ D" E' W - })$ [3 ~4 n1 \7 Z) S$ @/ U3 r6 p0 |: E
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例
* X/ t H) m0 B( U- <div id="app">; j7 b4 D' \( a p5 J5 k8 g
- <child message="hello!"></child>
* ?# z1 L8 @* |9 k2 i/ U3 J - </div>
$ ]' g8 \. u; I -
0 X, L2 i7 W) h I) [( U$ } - <script>
7 W |( E; I5 Z - // 注册
7 Y) V5 k4 O% l; O9 G/ d - Vue.component('child', {
2 F7 ?1 q. H3 o" \+ f+ D - // 声明 props) x7 K" h1 T: E9 _" @3 s" ~/ _) L
- props: ['message'],
: ^* T3 ?8 I0 L; G* G7 f; d - // 同样也可以在 vm 实例中像 "this.message" 这样使用
: W2 a' b7 G' a0 |7 y - template: '<span>{{ message }}</span>'' ^/ G0 Y$ ?- H: G! p" h' R
- })/ O# P: d" O! n1 p3 J7 \( ` Z' |$ o
- // 创建根实例
% h; k' \6 A3 T& J- ?7 u4 c - new Vue({/ ]( h. O5 _( `3 J `
- el: '#app'. f3 T8 X3 [0 P. R B
- })
- X, `. @& R3 k, ] - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
% y8 M5 i* x1 B+ V9 i" A; L- <div id="app">; g9 I1 t. g& T8 F# Y
- <div>
5 m$ O6 D3 y* B* { - <input v-model="parentMsg">
i) f" n8 @( k& O9 i } - <br> Z2 g: Q& E2 Y
- <child v-bind:message="parentMsg"></child>
" o8 i, D' c- `* M" j - </div>! b. S. N6 E8 B0 z' W: o8 v1 D
- </div>
' ^1 h1 ^: E1 n& Y# B - 0 h" ?+ ]6 N R& p
- <script>
! S+ P% p/ `1 h5 E3 H! ^ H' e - // 注册
. q6 i% ]- c0 G& L - Vue.component('child', {4 ~+ I# K" e* x, Y) Z3 B9 g# v
- // 声明 props3 f2 \1 ]. ]& u+ j9 Q$ K @
- props: ['message'],' d, ~* a/ C, t1 ?9 V5 _- ]0 H
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
6 _8 n; l: O" S - template: '<span>{{ message }}</span>'
6 x& n, E) M" j1 D - })
7 `- P, A, \% d& M* Z+ b5 f - // 创建根实例: S2 K6 r8 r" ^
- new Vue({7 |0 r. L2 N$ r4 _" ~8 s: ?* P- a
- el: '#app',
4 U' R/ D; x0 }8 } - data: {
: b7 n! x# O1 S( ^% X - parentMsg: '父组件内容'7 d4 E3 P+ {5 s3 T- V+ [' D: I" @4 Z
- }* T R! P$ ^9 [; I1 m9 D
- })2 v& \; C$ a4 W+ y; a% M: i7 z
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
0 W' K. u9 C# F4 {- <div id="app">
2 M0 D; L- t/ @ - <ol>
% _4 g z ~' K - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
# R& F" n$ y# k3 k0 |6 a - </ol>
7 V! f; U6 _7 k2 c - </div>
- o5 S. R* r# F& r/ d* N -
& M1 p2 U- Z; Q4 R9 W - <script>
c; b, g% ]1 Y; C. @$ w6 W - Vue.component('todo-item', {0 T$ G1 F @. x; i& ]0 H; c
- props: ['todo'],
# j4 s, {. b0 U1 @4 G3 X - template: '<li>{{ todo.text }}</li>'4 }7 l# X3 u- n3 ~ [( ]
- })
- G! u3 @' o4 b - new Vue({
& | X/ |* C: A" U) Q - el: '#app',- v- f9 C( U' r7 x5 g
- data: {$ j0 T) O+ K" M" k+ Q
- sites: [
9 k2 M- D+ d2 ^, A2 Q9 @ c - { text: 'Runoob' },: D+ k" `' v& t
- { text: 'Google' },2 r# M3 ^7 ~0 f6 D
- { text: 'Taobao' }
; f( |% r" q! e! A) t. r; y - ]
# E6 `9 m$ h* E0 T ]2 ~& ?; Z3 P - }
' M- ?, v, k# W4 Q- K8 y/ p - })2 A' Z* [# R( u" M9 G* H2 W
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
8 q- s: W, b2 P7 H$ R - props: {
5 |4 f9 X6 e) L- f6 \2 l: e - // 基础类型检测 (`null` 意思是任何类型都可以)
3 K+ j1 v" @* `* M' [6 a - propA: Number,
4 F9 @% V- z- E+ Q W - // 多种类型
5 Y1 @6 t/ `& l9 d# n0 E - propB: [String, Number],7 a$ A; n' o/ }4 K0 J m
- // 必传且是字符串6 e, Y* I3 F0 t6 Y8 [
- propC: {
2 p- N' a( D# s B4 y. F - type: String,. Y" b! Z& t4 b3 a
- required: true
5 j* n2 W6 G6 V - },8 ^. v& K0 D+ d
- // 数字,有默认值! B# ~# S8 m( Y) Q: i/ P$ e
- propD: {
9 s" M# P$ D* k - type: Number,3 y3 r. ^1 R4 k
- default: 1002 j6 z. B( D+ `
- },8 s. b9 ^# _. T# \3 j
- // 数组/对象的默认值应当由一个工厂函数返回/ ^% W' B: [: g1 q! c% \3 n
- propE: {
: G# \* ]0 Z6 k2 i - type: Object,& T5 t0 O, ~/ ^# G# T
- default: function () {
& H5 ?6 {. j( s; K) _ - return { message: 'hello' }2 R. M& l, |5 V3 F7 T
- }# c$ H& `7 v5 {1 S5 y# j
- },
5 \ c* p! i) x3 R2 I+ g - // 自定义验证函数
N0 I+ e! y# f4 c - propF: {
8 x7 X/ N0 h# ^7 Q1 H; ~# `4 l - validator: function (value) {5 {. a- a) h! Q6 O
- return value > 10, S4 w" D" r* C! o$ a3 B8 H) x9 ]
- }& r, J9 D0 u9 s4 C: }; D4 c- O1 `) l, B8 @
- }
: ?. j, d5 j; {3 {6 A/ @9 ~& ~ - }+ d1 x; ]5 e/ a( Q( u! i5 I( b- Z
- })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
; V6 g8 z' N" H! C) g% t U+ s8 v1 w
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件- o6 x9 i# X! {% O9 S
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例4 E7 X; v! U: [2 ?6 K
- <div id="app">( r- `3 F1 s0 R. a3 I- V0 T% y
- <div id="counter-event-example">
+ }4 L( O# ~. c$ P! C - <p>{{ total }}</p>
- q7 ? L) f9 ? - <button-counter v-on:increment="incrementTotal"></button-counter>
+ o: b% v* d3 j b$ j, G5 ` - <button-counter v-on:increment="incrementTotal"></button-counter>
$ _- }0 S b" l' Z0 S - </div>
8 m# c$ W4 k% C+ d - </div>) p8 [# [* ~ q. D& ]6 b
- * T" D& S$ n5 B$ j( J- H
- <script>+ \- T; S' _$ J6 W8 y+ N
- Vue.component('button-counter', {. h& q, D7 g0 S" t1 r# v' C" i
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
- q4 g2 Z' {, Q: o - data: function () {
/ ^; p7 `, @0 |2 q6 A' n+ L/ { - return {# c* ~: k9 c8 a% i. ~% O; O
- counter: 0 w8 f0 U. Q* W) ^& {
- }5 \0 T) m- i: F$ {
- },
! A. a+ t5 O* M' | - methods: {9 {1 y2 Q% ]( F
- incrementHandler: function () {
+ B$ a# W2 L" A - this.counter += 1& T, v2 Y, j# b
- this.$emit('increment')- {1 ~2 A+ Q3 f4 w/ r# O3 l3 c
- }
+ y `$ P7 P6 X" @& x% ?/ U - },! H3 `$ k% R6 j, c: P" T) j
- })$ r3 `% C; A8 z$ G
- new Vue({( ~- v+ z5 P9 e5 l# N- _* g2 F
- el: '#counter-event-example',/ h3 Y: j3 }; C6 l' x
- data: {4 L ~$ Z- `1 v7 ~" D
- total: 0
% t4 Q; k' b. u; h. n - },
2 k" p+ J( X4 Z' r, b, \' B - methods: {- l0 L- {: X; }8 A$ k- r$ ^) A* U
- incrementTotal: function () {& ^- V1 L. [4 k, c0 C
- this.total += 1* L& f# {0 ?# E" Y2 g
- }, H }& [' X4 O0 s
- }
4 o$ c' A3 u* k5 @7 r0 E' R, |- G - })7 Z, z1 w( Y3 d1 j7 k- u q, W
- </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册5 @7 Q3 C/ e. y0 a
- Vue.component('child', {( h$ J" Y; Q7 R0 Q. q6 l# L$ j0 k
- // 声明 props/ c0 O/ [0 \* P# q, V9 b5 X! o/ Z
- props: ['message'],4 I, s' { G2 A( Y% M9 x! k
- // 同样也可以在 vm 实例中像 "this.message" 这样使用! N. Q% u6 j( e7 |+ n
- template: '<span>{{ message }}</span>'
) X* u6 @4 w' L2 d - }); a# y: N, F' W+ P. z
- // 创建根实例. a9 `4 V: z9 _1 c+ ^
- new Vue({4 f1 N- K$ n7 a1 j& T* B* }' [
- el: '#app',
, Y& M: M1 O0 t$ x$ z/ o: z - data:{
4 y2 ~2 C4 Q2 Y' B0 J3 {: |. M/ r - message:"hello",
/ X/ n' w% e/ e9 h t1 Z - }
8 H& u* O- V0 a% V( P4 X" N# K% Y - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {% T! z* V. J! M: Y5 }
- incrementHandler: function (v) {
2 e, J3 f2 I' x - if(v==1){/ T% q/ ]: T' }# _3 ]
- this.counter -= 1% H6 n! U8 N/ a4 B9 @
- this.$emit('increment',[1])
; B, ~; j3 l4 F( a$ d% o - }else{
) M" ]7 S& z# @8 @ Q( s* q: i - this.counter += 1
' J) ?$ j. n2 l# v! V - this.$emit('increment',[2])5 Z# G4 x4 t6 B
- }$ E$ ~- k. K0 `. p$ i( I
- }
8 }6 V& ~* `4 }' M* [ - }
复制代码 ) J0 H5 A9 d% {$ @4 S
/ t% M, H1 [4 S0 n3 e2 f/ J5 W |