|
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 注册一个全局组件语法格式如下: - Vue.component(tagName, options)
复制代码tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件: 全局组件所有实例都能用全局组件。 全局组件实例注册一个简单的全局组件 runoob,并使用它: . E6 t6 R( R. l# K" \
- <div id="app">
. R2 K2 _+ [( s, [6 G" W' x2 ^ - <runoob></runoob>
7 `/ I3 ~6 u0 W5 O - </div>
* L. F# |" t( q: t, j - 6 [& B1 z/ o9 E; t6 b7 R
- <script>1 Y5 h8 T0 o6 r* H4 v i; K: r
- // 注册% J$ L4 O- d0 v6 V( H- `
- Vue.component('runoob', {
/ v$ b- _& G: V+ I - template: '<h1>自定义组件!</h1>'
0 R1 j* w7 w( r - })
. o9 |2 g3 @: p - // 创建根实例
9 S3 K- r' }2 @6 V: F% D4 X1 q( p - new Vue({8 S* {0 Q7 N5 \* O
- el: '#app'
$ v# n* e/ X- | - })
" z5 m! i4 i7 h - </script>
复制代码 局部组件我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用: 局部组件实例注册一个简单的局部组件 runoob,并使用它: , S" L9 e8 V6 T
- <div id="app">; ~; ~. Z7 I% k2 ]5 {2 Q
- <runoob></runoob>
% m$ b# J1 R c! ?, I" C2 n - </div>
3 R8 [: l3 R- h! t* C -
% w: O# F# X8 ^* k* J/ }" ` - <script>- Z1 Z" E9 @" [. c2 O& F
- var Child = {: p" S2 x) q' F2 n# m- l! U
- template: '<h1>自定义组件!</h1>'4 K1 J2 b( z6 F* D2 ?% C! F5 n+ ~
- }" o2 `8 w1 @: z T
-
8 N. A1 t1 D" N- q. y4 \* y! K; e7 b - // 创建根实例; L8 K, a A; Y( L* Z+ _/ M4 U/ p
- new Vue({
0 Y; G0 Q! O7 }9 v3 \' i+ H- e - el: '#app',4 ]$ u( z' a4 h) A H
- components: {
3 X( ~9 g+ y( P: g3 h. q) i( _% ^ - // <runoob> 将只在父模板可用9 C& a5 W( l$ @) [! [0 v$ {
- 'runoob': Child7 E& G8 Y9 V' V. R# F( X0 p V
- }
; Q' p; ]* E4 `6 s/ o - })6 Z) T3 z6 ]) M6 o$ V% x
- </script>
复制代码 Propprop 是父组件用来传递数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": Prop 实例8 D5 b5 g R2 @, c$ }9 g
- <div id="app">& z. C0 T; ]3 [' j! D$ ~9 c; T
- <child message="hello!"></child>
- X# s0 v3 F4 B9 B2 { - </div>
9 G9 I* d- G$ b- P -
( l$ N" i$ G; _# F - <script>
+ o0 f1 O2 K9 s - // 注册' K+ G) a& |* X8 T1 a
- Vue.component('child', {
9 F9 Z i) F8 f |2 g - // 声明 props1 Z Z5 O. {) s, P. s6 ^0 T; y
- props: ['message'],8 d8 _6 j' c1 z9 l
- // 同样也可以在 vm 实例中像 "this.message" 这样使用
/ ~! j: u+ G4 |6 ? - template: '<span>{{ message }}</span>'
2 m4 ]2 q2 Y; c - })8 ^4 Y8 P# N9 I4 S; ~
- // 创建根实例
, W- x9 s4 e9 n: w( q& P - new Vue({; {1 z9 d- Y6 r& E5 x8 m. j
- el: '#app'2 ^0 J/ W" M+ f" [; Z8 U
- })
5 b- ~) E- _$ P6 ^( m - </script>
复制代码 动态 Prop类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件: Prop 实例( R! W1 C) K, R5 x& [( i, A
- <div id="app">
! Q# g0 ^5 N9 ?; G1 a- c - <div>
2 A# @0 P. _" w - <input v-model="parentMsg">
3 T% h' r; i' K - <br>3 J! S2 J$ A, i
- <child v-bind:message="parentMsg"></child>
: i. d+ j6 K( }) L - </div>
+ \/ E2 _7 k4 D: |0 ]) n% } - </div>+ W. A& @( b0 r3 U- H' r
-
9 o5 w. t4 D( \5 N9 d* ] - <script>
5 {* u, N( }# O1 {% L | - // 注册9 v3 @. |# K0 f3 c
- Vue.component('child', {
: [2 w( l+ y' a j, H5 w1 r - // 声明 props5 M# A) u7 ^0 Z* `0 Y; R
- props: ['message'],
# C0 U3 o! P5 |: p$ h - // 同样也可以在 vm 实例中像 "this.message" 这样使用
' a4 s% L9 A" \ - template: '<span>{{ message }}</span>'8 I! L) \3 K3 D j' L2 y
- })* B* n/ O7 o6 N( y
- // 创建根实例
- n2 V5 H) v3 ?+ ?' u - new Vue({+ l2 D6 v) ]! x R& B6 l- ^
- el: '#app',
( o& s$ K! w. e, D. P - data: {: u5 h$ `8 x" y$ @
- parentMsg: '父组件内容'; Q# d" X8 C( W; S2 E3 X9 J7 G
- }
7 t$ f( _4 ?) Z8 v% n - })$ ~* h3 K6 b9 ~1 R* v' T
- </script>
复制代码以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中: Prop 实例- J; L+ ^* ?8 S) p
- <div id="app">
g% |2 z: m; I - <ol>3 H+ a# ?3 |! }5 Z D5 m2 V9 W1 l/ A
- <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
( b/ l' Y- V3 q1 I* J# k4 {( s - </ol>/ e9 j& j. A8 s4 T' r Y
- </div> j% f5 E- R" s8 I7 g+ j# m1 B' i# K
- + W4 I* L. q/ |& X/ O& \1 K& Z
- <script>
! l% |5 a; l3 N. f - Vue.component('todo-item', {2 X, E" D2 p V( |/ v9 g
- props: ['todo'],) [, [ s& l9 n+ W
- template: '<li>{{ todo.text }}</li>'* L! Q+ e' K$ ?) n; f; x
- })
# c* N) u* X h, F. s - new Vue({
9 e4 P7 j& B% P! P - el: '#app',
4 \4 G0 Q. W8 R' f( } - data: {4 W5 |1 g! `' F
- sites: [9 A8 o* s6 ]2 v& C
- { text: 'Runoob' },# {+ O1 e* A+ ?7 }: {
- { text: 'Google' },; _) n# T4 u" w
- { text: 'Taobao' }
5 |+ ~( L; d+ Z9 D+ G% s* _ - ]4 t* X$ a; z9 p6 w. k1 X
- }: v1 I |; B* k1 b$ b6 E5 D
- })9 ?5 U, ^4 f( d5 i$ S s1 z4 `
- </script>
复制代码注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。 Prop 验证组件可以为 props 指定验证要求。 prop 是一个对象而不是字符串数组时,它包含验证要求: - Vue.component('example', {' H4 S t# D/ n
- props: {: i9 d- c' g# O
- // 基础类型检测 (`null` 意思是任何类型都可以)* E% S4 Y$ G! y- V6 T/ a3 m
- propA: Number,
$ q' H: ]: O* w - // 多种类型2 h* D1 F4 p+ E; I0 o
- propB: [String, Number],
2 [5 ^6 B" c( B0 _ - // 必传且是字符串
v9 N G& n* l" k5 _8 } - propC: {3 u( ^+ J5 A* F4 [, ]' ]9 F" d+ u7 }
- type: String,9 r9 ]& I. W$ h
- required: true! q% ^5 M {/ v8 n1 o! V" r2 W
- },9 F7 J; g6 ?9 K! P" ^/ S) a8 y
- // 数字,有默认值6 P5 |; A! A. H0 Q2 S6 Q) j
- propD: {
& y0 q* Q7 X' o0 F0 n - type: Number,# R4 E5 m! \* V: y6 S! P: Q$ u. V
- default: 100
! g+ s# ]3 w4 a/ {8 b! L! ? - },
, M+ X7 u, C( ^ d4 k7 Y - // 数组/对象的默认值应当由一个工厂函数返回. R4 g: a& @0 C) f
- propE: {2 s! m& x2 O7 [' U# c8 G
- type: Object,
0 v% M4 }8 r% {( b - default: function () {; N, [' d& G% {9 O2 g6 i
- return { message: 'hello' }
0 v6 w1 }/ a0 k# @4 d - }7 w2 r* Z3 X3 C5 B& j4 z" h/ m. o9 v
- },9 x* c0 v3 t: }! U$ G3 x x* f
- // 自定义验证函数! a) B* E' s7 W! i! y) n8 J
- propF: {. i- ]7 y% l$ d7 [
- validator: function (value) {
. m& ]! A; i7 V# i - return value > 10
+ o& Q1 V, M# p3 u( } - }
4 Y6 O# q; [4 i: F$ G& A/ m) } - }) j; ^' i1 L" P5 c/ z. P' e, K
- }
6 p$ k& t9 V/ Q6 y9 W( ]/ F - })
复制代码type 可以是下面原生构造器: - String
- Number
- Boolean
- Function
- Object
- Array
, p8 M% ?3 _7 S5 i- F" d
type 也可以是一个自定义构造器,使用 instanceof 检测。 自定义事件父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件! 我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即: - 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
1 s9 X' X- X$ T, ~# H3 z
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。 实例
8 O& k3 m3 g/ i( F3 l' D/ x- <div id="app">) V6 H- o6 n/ X0 W9 q$ q0 S
- <div id="counter-event-example">
( c: N0 I5 K: J- g) O# @# P - <p>{{ total }}</p>- l! q* c: C5 K
- <button-counter v-on:increment="incrementTotal"></button-counter># [2 q" X! z4 c$ i1 F0 H9 f7 E
- <button-counter v-on:increment="incrementTotal"></button-counter>" @2 d* e5 X0 [$ o& |- A0 {3 F/ x1 l
- </div>
* c8 R1 ]" W' a [1 j( o - </div>' A) D' N: @& z( A V
-
& ~5 d r' ~1 s% E - <script>! r) [* b' `4 _" V
- Vue.component('button-counter', {7 q, u9 I9 O& L! J/ X$ z! |3 F' m
- template: '<button v-on:click="incrementHandler">{{ counter }}</button>',. O1 x8 J, e" F, D! }) M
- data: function () {: k1 U: H6 y$ x' m
- return {. K/ J3 l l/ z9 \. W
- counter: 0
' G) r* A) Y1 `' e2 e - }2 ~3 C! m, ~; T, \: w" K
- },
" x B, k5 `) V - methods: {3 @( E m# L5 U7 m* S- }- f6 `
- incrementHandler: function () {' S. A/ W) Z" P! x8 l* P! c
- this.counter += 1- d5 E9 W' H7 \+ H! d, q, O! j
- this.$emit('increment')
. j! _; U& W8 E' Q. `6 R& H9 N5 e - }* y; ^6 m9 Z* M0 ?5 b, X$ X
- },
8 s3 C! L: ^* V) P+ C - })
/ `" r' s2 F: e* Y0 G3 a1 b - new Vue({
0 u M1 r$ ?! a5 _8 p - el: '#counter-event-example',
* o# `' e! R: C% m) \; T - data: {
6 a8 w! S& X! P, I - total: 0
) f2 n6 [; G: u6 ?( d* d: ^ - },
# k- ^7 a' a( g: d8 }1 b, a8 D5 O - methods: {) e5 Y3 v6 v& _1 o' Y8 e W# l( p* I; l
- incrementTotal: function () {% N7 c) W1 P* Z# N# E- l. n
- this.total += 13 ?% l8 U0 q( s# K+ s
- }
5 q1 Y0 [. E% D - }
8 W& \# {: k. t) q. Q - })
7 J+ `8 q. w; q* B - </script>
复制代码如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如: - <my-component v-on:click.native="doTheThing"></my-component>
复制代码父组件给子组件传值的时候,如果想传入一个变量,写法如下: - // 注册
- Y2 _2 P; R* Q1 _* ?5 r1 M - Vue.component('child', {7 R; V. d8 m" {+ l
- // 声明 props
6 O; A$ W. }; Q$ G( c' U - props: ['message'],
5 G4 m, M. z& I2 _/ S - // 同样也可以在 vm 实例中像 "this.message" 这样使用
2 \( M1 y5 a: P7 c - template: '<span>{{ message }}</span>'
4 {2 I' q/ E% }1 e& c - })
8 k" @% y. ~& E - // 创建根实例
) ^+ s8 U+ B' g/ r - new Vue({
# l$ k9 t e- Q9 k - el: '#app',, Q' F9 V0 ], ?3 |$ h, a2 o
- data:{
, h/ g( s4 _- F9 ?- H7 I - message:"hello",
2 I; b# p7 \1 J! }0 _8 @ - }# F, R- F+ f) B4 j1 G; [, ~$ `
- })
复制代码子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。 比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。 - methods: {- ~3 g: A" ?6 l- H3 U. w% B
- incrementHandler: function (v) {
. Q9 I( p) o3 A8 k - if(v==1){
- f$ K! Y h" C* @ - this.counter -= 1
* H! {, T0 }) ^! p' [- ^2 g4 } - this.$emit('increment',[1])& G* H' ~6 S* |0 H
- }else{, B! X" |7 K- L; F
- this.counter += 10 w2 N( r- m- j8 R% ^
- this.$emit('increment',[2])# B0 c8 j7 u- V' }
- }
& I) \: n# E/ z$ N' { - }
. l/ z! ^+ V# m6 P, I% ` - }
复制代码
/ L2 {$ B( m# o- ?
+ k# J8 |9 ?$ t4 E6 ]) v( Q1 O |