|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
E* T0 M: R6 {9 }# I- <div id="app">
& p9 q' u* P% V' r5 w2 l9 O$ [ - <runoob></runoob>- x+ F, ^$ H: J9 g9 P! x* ?
- </div>2 D- A j/ t: {9 T" {1 O
-
- u# k* q" G- s, X( e: A- O4 i, L - <script>3 l. p+ |1 Y7 t: L% z( z/ g3 @
- // 注册, V4 B( N/ H, E- c! S# O- S2 \* }8 f5 k9 q
- Vue.component('runoob', {
2 v5 j2 ^9 a; m' B! H - template: '<h1>自定义组件!</h1>'
6 v7 |' I! Q: [! K' `/ }6 h - })2 m- @3 ]8 y8 K$ `
- // 创建根实例; d1 P( A. }9 B4 }* ?, l" l$ X9 W' K
- new Vue({
! m0 o r: ]: \ - el: '#app'
5 ^$ y' }- T# X: G( ? - })3 |7 p, i8 `5 `
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: * }' c: h4 o+ ^) [# p6 _
- <div id="app">
- o0 O3 j: h$ Q% o- @: D4 g - <runoob></runoob>
' f7 A! m! o/ q# k+ v- W! o - </div>* H8 B* r2 v4 h1 @4 q* s
- / T; v' N3 I% U9 H
- <script>
! Q# C; Q* l' G. j - var Child = {
' b) ^" y1 H; A: f - template: '<h1>自定义组件!</h1>'4 G7 Y4 E- W3 [7 @& J
- }7 G: m! h- P2 l0 s
- : e9 t3 ?5 Q1 v: F5 e% E. e* u
- // 创建根实例
. n' l$ R: M. N7 U - new Vue({
4 k' W5 c' j. W! k8 m - el: '#app',/ f L r( ?8 m$ h
- components: {
0 _: ~9 @0 r5 W$ p. }" \ - // <runoob> 将只在父模板可用; S) [2 u2 @2 j4 A! m! c! P
- 'runoob': Child9 X- A$ z( K; C- a$ z& i$ O8 A9 {
- }
. Y5 q+ w8 Z4 j - })
9 L6 \: @+ z: A# v& h4 X1 ~ - </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例 w3 w& H/ Q# U# w ~: O$ Y% `5 e
- <div id="app">
: T& w# Z S2 o) w( \, o - <child message="hello!"></child>2 A, U' V# x& l9 L% P7 F2 k1 a
- </div>
* ]0 _; w$ }7 c/ O4 ]2 N/ w8 F# W -
3 E* e; I" Y9 N" l3 Q3 ~/ t4 Z0 B; E - <script>
7 |' G9 q; L' T% Y4 |& ?. a o' [ - // 注册
. F8 ~: \" T- A* |, U - Vue.component('child', {% K+ P) t/ ]* ?' T4 p8 X
- // 声明 props
$ ~6 w. q" m2 P$ g2 h - props: ['message'],: E: z# u2 z7 @% h, j5 f( N7 n
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
+ z. ^ v5 a u - template: '<span>{{ message }}</span>'
; u3 M. @/ l& W( L - })- x- L) ~" T; y4 \( J# d
- // 创建根实例
, ~, b l: ]# @" k5 W9 P - new Vue({
1 \1 t8 V' Q" q2 A+ {- E' b - el: '#app'
) }, U/ u& ]8 e - })" S9 `8 N8 w, h; I& r
- </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例
- J+ X, {8 R, a3 m, A9 x- <div id="app">
9 u* e, Y2 y! ^ - <div>
# I4 ]% y4 j( i6 F - <input v-model="parentMsg">! \1 Z1 O6 C/ Y( k: {7 I( x9 L$ [
- <br>4 w( m* j+ n# s( g3 O! _
- <child v-bind:message="parentMsg"></child>
9 L e3 g. j9 b* f! b& J' u - </div># V4 j0 N2 j& P$ s- z- h6 k
- </div>1 z9 n, Y/ e) L0 B9 Z3 v( N
- 6 t+ H3 H3 E( S' q, O! s# u
- <script>) U/ X' C% \ F8 o) b6 E6 s
- // 注册
& `7 Y5 s+ |' x- l" c* W( h - Vue.component('child', {
9 j; D( J9 u5 E8 p9 ~4 m - // 声明 props2 ~$ d6 g. Z1 ~' p
- props: ['message'],- C5 V" q9 E+ Y5 M; n+ ~7 B* k4 y
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
$ A0 O, V# [# L2 d4 o - template: '<span>{{ message }}</span>'
" b# N1 z. H( G3 l$ ?( R s - })7 j' I) m F6 R% g5 g# j* B9 Z) U
- // 创建根实例
6 l. m$ B3 f' j+ Q* Z - new Vue({
3 v% ]/ O- y* L6 v - el: '#app',. j+ S$ c1 ^+ C5 s F
- data: {
' g8 z r1 P( b - parentMsg: '父组件内容'
# X4 R0 U' I2 b' N7 \ - }
; |# Q @# X0 b# n0 V - })
( n# |8 S9 T4 u - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例4 v0 }* L5 Z8 }1 m6 V% f Z4 n
- <div id="app">
1 s% |! A5 W- b5 s$ ]# p# s$ j - <ol>
! @, k6 U$ @6 `1 z - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
% I! B2 ^) h8 y# k% V- e - </ol> J* \' \& i! J9 N) s: h
- </div>
, S: a1 j, A" a0 M/ y1 Q7 \0 X - % [; h4 d! {1 Q& g3 `5 j# n) ]* ^
- <script>0 z4 `2 X5 O. l# ~
- Vue.component('todo-item', {; @, r% K0 W4 r; P+ p; B3 F
- props: ['todo'],% _/ c* e4 U9 b/ r7 B& J3 T
- template: '<li>{{ todo.text }}</li>'; C% n9 F3 c5 _
- })
% e1 E( _9 y8 P% Z) t - new Vue({
- e" U2 }# s6 ~# F/ b7 C - el: '#app',8 \% ^/ b5 v3 F1 H/ s
- data: {
& o9 V7 s0 t" y, D# u, O - sites: [
9 O# m0 Z5 K8 Q3 D! ~$ }4 O/ { - { text: 'Runoob' },
3 n& `7 M! B1 i - { text: 'Google' },) g! c" k$ s0 U. B p
- { text: 'Taobao' }( p6 v! ?2 X( M& N/ [
- ]
: `" O1 \: J' R4 M* } - }
% G F8 C1 ]. U, R/ h0 `5 i* E - })" | _% |8 Z' D$ r$ e
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {
' t( S9 `: ?, N" L2 A( e! `7 H9 U - props: { _) v; @, e8 m5 |
- // 基础类型检测 (`null` 意思是任何类型都可以)8 I0 T7 K( [+ Q' p9 S# |8 L5 ?
- propA: Number,( ^& J/ m! x/ W$ ?
- // 多种类型0 o' z! i* i- \) V2 P3 J3 t
- propB: [String, Number],( Z8 X9 x- g0 q5 B% ~/ y: [
- // 必传且是字符串) R! s* H0 D4 i x" G8 u
- propC: {
9 P! }, P" k1 v* S4 [ D. P - type: String,
1 b) P* q# ?( C - required: true
3 _8 V7 `3 S* Y0 C) g - },/ L6 G1 ~2 L0 N9 w
- // 数字,有默认值
: C3 H- [5 O4 s F$ G' n4 a6 ` - propD: {
* A+ d& N9 n a0 l - type: Number,$ j6 d& Z) _/ L4 B$ f9 O
- default: 100
. y, w+ l& H- t5 e( z) X @ - },; }2 j; H, G$ O
- // 数组/对象的默认值应当由一个工厂函数返回
: T" z Y- u* z4 L2 @ - propE: {, s& |0 W$ g$ y s
- type: Object,2 C2 O5 ^7 Y: K& ]9 Z a6 n5 ]
- default: function () {& H7 M0 E0 E0 Y! Y6 Z! T
- return { message: 'hello' }
5 n6 D- c+ e2 j) ~6 \5 H2 Y - }( V1 M6 \( ]0 M2 v
- }," S, Q% ~3 l6 J9 [7 H. l4 t( ?
- // 自定义验证函数) j: ] E) e7 m& b
- propF: {
3 v* H/ Q. U7 m3 @( G7 z - validator: function (value) {& C3 ?0 Y: X1 N1 u1 S# F* `: P
- return value > 10
, i$ L d7 S- E, ]- u! C - }. z$ y/ t/ g% @8 p1 S/ ^
- }
5 U: M- Z/ x! F - }
q* G- q0 j2 [8 r( ^' P - })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
: ^! {$ f. |0 X6 G6 o$ v
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件' L. G- ?' j" ^3 l0 a: \) D( P
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例' [ H% ^9 Q: _' G! O
- <div id="app">
1 f. R# V0 B6 y: E, v, k. m - <div id="counter-event-example">
; _% U" V! z* h) B; J - <p>{{ total }}</p>% F. e7 l# ^" `* i% Z' J
- <button-counter v-on:increment="incrementTotal"></button-counter>" A1 v9 \6 ]( m2 ?* c2 E# e4 |) ~
- <button-counter v-on:increment="incrementTotal"></button-counter>; ?& j/ V8 O- e. r* ?1 N9 v
- </div>9 u# w! K! f% N# w. E6 I1 d2 \0 a+ }
- </div>
5 A: W1 F6 \- b- D2 s -
2 H; K- u1 u3 S* _' M - <script>
2 d5 g& b9 r. v2 V& J% u$ X - Vue.component('button-counter', {
5 G0 S4 d8 A6 _( _ g5 R- G% U - template: '<button v-on:click="incrementHandler">{{ counter }}</button>',' k4 p# V9 d1 p9 a9 o% W) Y
- data: function () {$ D: Y; T0 ?5 u: H- K
- return {
0 w) d9 |8 H( S" a3 { - counter: 0
# Q u: W) Z) `1 a, c7 |: u - }
5 Q( ^! f( F2 A# i. q - },
4 C9 p; q; O9 @) W& x* r - methods: {
3 x9 F% }: I! J5 w! C; w - incrementHandler: function () {
2 g( j/ x6 p" n' e - this.counter += 1( y, g' }9 k' O6 |
- this.$emit('increment')
0 f5 P: D6 O3 W' }) P - }
9 x! D/ B4 M* N0 Q" [4 e% G - },% N4 ]+ c, G5 S
- })8 S# w8 F) T- j7 y
- new Vue({8 d' H) ?, X: x1 I* r( V$ S
- el: '#counter-event-example',
: {' p5 f0 S1 ^5 T - data: {* J+ b) @1 N# H7 G
- total: 0
0 y" H, {) Y) e - }, k2 z/ ]1 U" m/ j/ Z3 g9 ?" ^% l: M
- methods: {
3 W# Q3 n: S" R# d5 ^ L3 E& k% s( P6 f( q - incrementTotal: function () {
- C' e. {9 z$ U& I: w+ \, z - this.total += 1
# E% O# |5 k. e) q8 ~ - }( E7 p) c6 {& h T! P
- }; m3 ^: ?( L( W1 q* ?* m
- })
; g5 R- P1 q: T C - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册' \/ n( s8 y# C8 T: K. ^% i z
- Vue.component('child', {
9 f, |+ O1 E/ ~" e, L; g: [ - // 声明 props
8 N: |, U* D) g/ B% S0 @& S - props: ['message'],
0 S3 U% Y* F1 a) i! h% F1 @ - // 同样也可以在 vm 实例中像 "this.message" 这样使用
( u$ n4 E. w* |" w0 a: J9 {* V - template: '<span>{{ message }}</span>'1 x8 [6 o5 q9 x* P6 E& i) n% x- u
- })& N* ^* i4 F9 F. n% q% f
- // 创建根实例
- c- n4 A: l% V1 ^& _, h - new Vue({
; E' q5 ^( @; F - el: '#app',
" d. \3 }1 f$ L$ t - data:{" C Q+ a8 q6 f1 c! _3 |9 `
- message:"hello",
5 v9 O" T( _) T0 M0 A+ ? - }
3 e, N+ F2 f. I) p2 H; C - })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {6 Y% A, |+ c" N8 T+ V
- incrementHandler: function (v) {
d/ l1 u' r) P- c* A1 l' a5 u - if(v==1){
# \$ |, I/ S2 T4 Z - this.counter -= 1
$ F$ N" v8 i) y2 `! Y- r1 U - this.$emit('increment',[1])
9 O' n5 I% N4 y4 ^, k2 U - }else{" f: G3 |6 T( G' C, Z
- this.counter += 1) N) f- S2 D+ {5 }5 I# _
- this.$emit('increment',[2])0 P; X% A9 T" T
- }2 k$ o7 h7 y2 _1 N5 Q
- }
3 u# z5 z* ^( v( |- x - }
复制代码
9 i. g$ C" X+ W' E: R$ _1 l- H1 U3 u$ L
|