|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它:
0 r, x8 m3 h5 o& R4 t, Z- <div id="app">
' @3 t* M3 O% k( T1 ? - <runoob></runoob>
% H: @# d) V B7 L - </div>
0 o, \) i) [( y% B+ L0 C - 8 E2 U7 U5 O9 D
- <script>! u1 e5 g3 ]2 R9 }6 \" E, w- v3 {
- // 注册7 b( g0 S7 h3 ?
- Vue.component('runoob', {
- G5 t7 z5 ~: U) `1 J$ h, [ - template: '<h1>自定义组件!</h1>': N& [9 h$ }. C; ^; h" z
- })
6 Y, Q ~9 }; }# h+ o! N0 w - // 创建根实例& B, z* s/ b' @% z5 S2 J
- new Vue({
) U$ f7 ` \/ l1 g" T) ]1 Y - el: '#app'
8 ?1 k- O9 l: N - })6 ~; p( K1 K# \$ T; }% r, E
- </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: " q# Z! g" t0 I" p
- <div id="app">
8 C; U3 S% X- ?" Y# V, r- O - <runoob></runoob>3 S: `- E" x* p. \
- </div>
. r% D( i5 J8 S* m" V6 A7 X, A8 L - - r# u6 M0 l6 i* p* I- H# T
- <script>
/ S! S1 N1 d$ U* M5 {: i - var Child = {
! X4 N* A: M8 }" t6 k2 J - template: '<h1>自定义组件!</h1>'9 F" {! h) g0 N& v- B
- }
$ r$ \& v, s" u$ e8 P$ J+ W: \ -
5 z+ b+ L& o0 P0 t& B4 w( c - // 创建根实例
! O. e, b$ u, j* c+ t - new Vue({
; A& r& S s4 f6 q0 j - el: '#app',. _* ?4 o, C& V- o. Q
- components: {
& e" y$ t* c6 }) a1 p6 o. o) N - // <runoob> 将只在父模板可用. y! K6 U( }* `' i( p
- 'runoob': Child/ y0 { b) m5 j7 w5 i7 W% W
- }
0 ^) O& N$ I8 j - }); T5 F* I+ U* ~; \1 z9 Z# E
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例
0 v" B" } k* O* x \3 p' K- <div id="app">$ `3 j6 s2 O! h1 c" z
- <child message="hello!"></child>
7 e9 J8 r% {, G2 } - </div>
) j$ [" ]/ I. ~% R! g# M) e" _ - ' ^, c) q. K4 @+ b
- <script>7 G! t7 T( ]: f' ^, C
- // 注册6 e; b, L! x; e* E' H& U+ k0 W5 n
- Vue.component('child', {6 Y" F2 S$ p2 |8 G
- // 声明 props
* @# M; Q6 K9 i* B6 Y% T1 G - props: ['message'],6 a% b' u3 p5 C
- // 同样也可以在 vm 实例中像 "this.message" 这样使用3 {" t- s0 N* e; z, r" ~
- template: '<span>{{ message }}</span>'5 H; C8 W4 m& y, {4 u
- })
4 [# h& S1 l- P( L1 k* }$ w - // 创建根实例9 F8 b4 G1 @7 J, ~! W
- new Vue({% [) t; d1 w( S/ \6 k8 Z: m$ @0 M
- el: '#app'
' n0 n5 x% L) T9 w( f - })5 _! K: N& y) [! Y$ H+ Z/ Y
- </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例- N1 r, S( L; W* B1 K# d
- <div id="app">4 i+ i' |" ~6 I
- <div>
/ l% F- L2 Y' ]( l/ d - <input v-model="parentMsg">
- t8 ?: ~# X; V; r; t - <br>
+ l7 Y. {' ]2 V8 V' @ - <child v-bind:message="parentMsg"></child>3 X, ~9 `( r! Q3 V
- </div>
8 l0 Y4 a( K$ F7 ~- F8 D - </div>
) a- @3 I" o" r - * Z& E4 X* J9 Q6 Q# G, Y
- <script>
7 c* a' N' @' A. H. J - // 注册
' N* X+ h. e/ N( {( u4 ]- N: E - Vue.component('child', {
+ ]0 M" F6 {' n$ T5 q0 c- g - // 声明 props
4 h% w# R$ e3 I; n ] - props: ['message'],
9 ~9 u* f$ b, z - // 同样也可以在 vm 实例中像 "this.message" 这样使用
& D# a3 E) a& l5 |# `9 Y$ E - template: '<span>{{ message }}</span>'
. @1 O6 A9 C& ~/ k2 j' ?* x - })
* N, E' y8 t1 F$ k3 a2 \2 E - // 创建根实例' H, @ c! z# {% x
- new Vue({1 {3 `7 f2 T, C2 g1 w+ l! w8 q2 M
- el: '#app',
0 W2 J9 c: D6 N* T& e1 d: U w - data: {
% z! E: ]/ }$ O5 h, N3 R - parentMsg: '父组件内容'$ u. |+ B! v$ T& j9 \
- }
7 d" I2 u5 b4 J ~* Y - })
" R+ |6 H" L% u/ R* [ - </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例
& I# a' Y4 Q" V4 a7 H- <div id="app">
L$ o" @) C: K6 H8 \+ r - <ol>
& z- T& y) W# T5 B7 o2 C( S - <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
4 a0 j6 H4 S* S- c$ k. f2 K - </ol>& L% d% r6 X4 I; ^
- </div>0 [+ s( O" _# O+ F- k
-
4 L6 d5 O: f, c2 q9 D - <script>
7 ]% b. B( H H+ W - Vue.component('todo-item', {6 E. \) v9 U- b3 j1 H' v
- props: ['todo'],
- n, |3 [3 M/ [. s L - template: '<li>{{ todo.text }}</li>'% |% ]( S2 q, |
- })5 |- _2 B! f5 ?4 ^. R
- new Vue({
( o8 H3 p. w% I. L+ s- L - el: '#app',) m1 r/ b9 N) q) s4 j" z
- data: {
# y3 x' ]0 I) b4 F/ v5 }: x - sites: [; x( s2 {# X/ r( D5 T4 K
- { text: 'Runoob' },5 w5 S: l$ G3 }
- { text: 'Google' }," Q) S* v# k! Q0 s$ T7 x0 o8 U
- { text: 'Taobao' }
9 C' [ Y- D3 Q8 r9 J* [) d - ]
8 X0 G& h. f: H4 z& ]/ z3 s - }, F7 B4 }/ b7 u) i' k- o
- })
5 Z3 }, ?& q2 a# E/ E - </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {$ {. `% `% _8 |$ g: ]+ X; c9 z; W
- props: {2 `: { h; C! a& M5 n
- // 基础类型检测 (`null` 意思是任何类型都可以)) `' c5 V& j, U9 Y! y
- propA: Number,/ J4 y* `" W$ _5 l
- // 多种类型5 T* Q# H$ h+ k
- propB: [String, Number],
9 \* _! w8 h2 w8 w. [" i" a - // 必传且是字符串" `: d" w. r% }: \0 t* |
- propC: {. k% F( X U: l
- type: String,
1 ^0 g( X3 W0 \. T& t( y d - required: true6 }# W4 b1 J' _) _6 B! n+ W! K
- },
( X4 s7 N |' C% K' W2 J- A0 ?/ z - // 数字,有默认值
! w9 m$ d* a& U1 U& i- |( s) B7 k# v - propD: {: U6 W4 f" c9 \- h Y9 p: L
- type: Number, f" v7 z+ ~* u. O" N: \$ p
- default: 100
, C1 x9 p8 w: L. e - },
, `: r" \2 }' k - // 数组/对象的默认值应当由一个工厂函数返回
4 ?" Q S! w) {9 {$ O6 g - propE: {7 x& @* q$ k. W9 ^% F
- type: Object,8 N/ d: e# r+ n6 B% _
- default: function () {- o z& |4 Z+ p! `" u
- return { message: 'hello' }
( K* \1 |3 S- }& A) ]" f - }% |+ `- s5 B# D; f% o7 X
- },4 w( f1 O, r( X: ~( Q2 N' D
- // 自定义验证函数
+ q6 A y9 c: J% l3 [$ d - propF: {
4 H" ~6 R, H! ~1 G - validator: function (value) {
: i% g! r% V9 d+ M/ M: t: ~+ m - return value > 10
& s1 P$ ^$ Q/ V" F; d/ ? - }3 @$ ]& j* T/ S) a' W( A, H2 n/ ^
- }' K' W/ x: ~1 W1 V% S. V( k- `: y
- }
' ]7 _5 \$ v7 ?, i& u! ?$ J3 H - })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array: Z, W9 W7 l, ^0 j+ j
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
4 g- R& q7 |& h) T. u( p
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例
2 `/ b0 s! B1 ^9 Z7 z! I6 c) _- <div id="app">
; x' B$ ?, d2 T) ]% l: Y - <div id="counter-event-example">
' v7 m" k5 l% g2 X4 t5 ^+ I - <p>{{ total }}</p>- ~* u0 @' c4 p6 h/ Y( ^+ G
- <button-counter v-on:increment="incrementTotal"></button-counter>2 F$ s( O& H4 i# s& y( x
- <button-counter v-on:increment="incrementTotal"></button-counter>
- R3 E4 L& N4 Y' W5 x/ f - </div>. ^( ]7 o" G1 w2 [
- </div>
6 x" w3 o" j p5 ^ - $ J W* `9 @5 N5 u+ n5 u& m
- <script>% ^( P, K' m9 S2 S' c
- Vue.component('button-counter', {+ {& l5 P: [/ G" Y# V$ J! V0 e/ B
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
& R2 e1 B# x" ? - data: function () {* I, z2 t7 ?0 c1 ^
- return {+ _$ U# P4 h1 e3 f- S7 K- C+ k- T/ `
- counter: 0
# }+ {, l. E" D4 p - }; U2 t8 Z m. n7 v; [! l, Y1 n7 X
- },
& r, H& g1 |) j4 {8 p - methods: {9 R5 g4 Y& i3 A8 m, v1 `3 X3 o5 [8 y7 f
- incrementHandler: function () {
; Q+ l! _2 o# ?0 R' u. f- S - this.counter += 1
( g9 m7 J8 u6 h5 r1 j2 {! R - this.$emit('increment')
5 q4 H+ v! [. z; E+ H - }- C, p% {9 l/ W- t" c, _, J- }
- },
( @2 N/ |+ {* T2 w$ \( n - })# A: x9 b) B X% u5 M" ~
- new Vue({
- j1 |; h5 C/ j - el: '#counter-event-example',7 b/ U7 h# j9 t; [
- data: {- g7 ]. \8 `- E! L& {
- total: 04 o2 L/ n1 @1 B$ o
- },6 V5 b, C: w+ I5 m1 \% {( H
- methods: {
7 |; S5 K: e1 G, p - incrementTotal: function () {
% u @5 h8 U& S" u - this.total += 13 s* Y1 a7 P# `* v6 K
- }5 D2 C! M$ z5 f- O
- }
3 B% Z0 N* ~5 E" x$ O - })
9 `/ G* S3 h/ D) d. Z - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册9 T; J0 G. K; m7 l
- Vue.component('child', {8 Y x9 j/ X/ n2 i7 b
- // 声明 props# o: F4 w9 Z( \" C3 J8 A7 q8 L( j$ Z
- props: ['message'],
8 ~; Q* R( u! |6 U' x5 ] - // 同样也可以在 vm 实例中像 "this.message" 这样使用
4 w! w' M, x) g$ R- Y& m - template: '<span>{{ message }}</span>'
6 Q# [/ q% T8 G+ M' z( U; {* r - })# ^8 _) p1 G+ t7 X+ v) x3 u; q
- // 创建根实例1 I3 a5 S' z! y0 L6 w) m8 E- D
- new Vue({7 f2 D/ \, r( P# D3 N- r- C
- el: '#app',2 y2 K- I, a+ q3 E
- data:{
5 F, L5 d1 X3 [ - message:"hello",* H, S# N& |# e# N
- } |5 v$ y! ^% Q/ v% {. a
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {% O9 [8 f% V8 b, K+ W
- incrementHandler: function (v) {
7 s3 V8 G& _3 X# V) r& f" W - if(v==1){- u0 c$ ~5 x: f1 |8 Q4 P
- this.counter -= 1
4 g4 ?: G# Q6 a- h, A O - this.$emit('increment',[1])
2 Z* e7 `* y; g5 @3 V% ~ M( A - }else{+ q* Q8 e( W# B5 _( |
- this.counter += 1
8 o$ c+ D Q7 q9 C/ S; C& S9 G: N - this.$emit('increment',[2])( C$ S, i, L) m6 i' T3 Q8 [
- }* q: j0 D6 i# T) z2 h
- }
; p( I" M' B9 r4 F - }
复制代码
5 ^- l& w9 D' q8 \( {
" G- F' a3 g8 \ R- V6 K |