您尚未登录,请登录后浏览更多内容! 登录 | 立即注册

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15208|回复: 0
打印 上一主题 下一主题

[Vue.js] Vue.js 组件

[复制链接]
跳转到指定楼层
楼主
发表于 2018-7-4 11:28:06 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
组件(Component)是 Vue.js 最强大的功能之一。
组件可以扩展 HTML 元素,封装可重用的代码。
组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树:
注册一个全局组件语法格式如下:
  1. Vue.component(tagName, options)
复制代码
tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件:
  1. <tagName></tagName>
复制代码
全局组件
所有实例都能用全局组件。
全局组件实例
注册一个简单的全局组件 runoob,并使用它:

2 s) }  p3 s5 I! P6 @3 \
  1. <div id="app">
    ( ~2 Y6 E1 D+ S5 _
  2.     <runoob></runoob>7 E7 v) _$ G7 M& Y3 Z# R! @1 h$ d
  3. </div>
    1 c6 }: P4 s& m* W, c

  4. $ a2 v  ^% h" `7 g  j4 f
  5. <script>
    " ]5 r: G4 M/ `+ N6 I+ `( x8 x" o
  6. // 注册. M* n: U# T- S5 H- I
  7. Vue.component('runoob', {+ u) F8 ^+ D8 W$ a1 A! Y3 G& {$ Y- l
  8.   template: '<h1>自定义组件!</h1>'. U" o* c: z8 u( W0 K
  9. })
    / i& ~$ y: R( y, M5 t' t' d
  10. // 创建根实例
    1 q6 }1 z3 ^. \3 k- ?6 i, l; g
  11. new Vue({+ I7 U9 c! v' p: \' }' G2 E
  12.   el: '#app'
    6 K8 w; S$ M2 g) R0 ^: n+ |
  13. }); P: X& f: q5 [! P* G
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

* |. ^2 I" p4 L" k6 w' Z
  1. <div id="app">
    $ r+ k9 E% d: C. [
  2.     <runoob></runoob>+ d( U! B0 `* P2 Z' d; \+ F7 w
  3. </div>
    % ]% T* z) M2 V- P! E

  4. ! b& }8 g* g- n  v/ J
  5. <script>" Q; F( n. F1 D
  6. var Child = {
    . P+ k7 `' Q; S( o# |+ X6 h4 w
  7.   template: '<h1>自定义组件!</h1>'
    ) o; V- K4 S& o, v
  8. }" A0 |' i. R* ?$ ]7 u
  9. & t. ^4 h2 {% o2 |
  10. // 创建根实例
    ; }# n" ]- s' ~) J3 l' G
  11. new Vue({
      k0 O. @! V5 r( T, @0 X, L& R
  12.   el: '#app',0 C- y, {# K2 \: N+ r1 y/ U
  13.   components: {+ q$ k* X# d9 y' A+ k7 l' X2 h
  14.     // <runoob> 将只在父模板可用- D; G* K/ E+ C& k5 Q( Z2 q/ g
  15.     'runoob': Child* J3 R3 [1 A) G3 g# B
  16.   }
      v" W. k& T5 y* O- c
  17. })( J$ ^) ]  _! m% ~1 ~4 C; P5 }# M
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例; j/ e. y, h* Q3 g7 |* Q( Z
  1. <div id="app">
    1 Q1 F# P5 ^" D, ?; U7 f
  2.     <child message="hello!"></child>
    9 N8 `! r3 n1 u
  3. </div>
    , W$ a3 u* Z+ \: r3 m6 M! V$ ]
  4. : W9 r8 n- K, I6 k* ^
  5. <script>4 G2 L2 r. h, p8 G
  6. // 注册
    , ?) r/ t! @. ~' t1 k+ g
  7. Vue.component('child', {
    8 H) s3 ~5 }# D$ t: m+ P' v
  8.   // 声明 props( t) O9 t, k6 k/ _, ~
  9.   props: ['message'],0 ]. O( E: b4 L/ g* s" p
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ! {& t, }& ~$ x3 }! [; H) p
  11.   template: '<span>{{ message }}</span>'
    1 z, D( \4 M  Z2 d
  12. })& a- `7 X/ I" u. V  {! y2 v3 `. D
  13. // 创建根实例: s$ T; C5 T) b
  14. new Vue({) n* @+ C/ X" m1 u/ H, e
  15.   el: '#app'% C& B8 B; T. q6 x. A& A
  16. })
    & s9 p2 H7 q: ~- Y) u
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
$ K$ e/ X) |8 |/ W! r# G. [. x/ |7 X
  1. <div id="app">
    $ ?  J' b* d! l4 N- Y" R
  2.     <div>5 j# v/ ?$ ]" x7 [  z. }4 R
  3.       <input v-model="parentMsg">8 D9 {* v; m) Q! q1 f' ~. Q% b7 S+ g
  4.       <br>/ ?" @* o' C/ O8 o/ d! \6 q) ~0 o$ X
  5.       <child v-bind:message="parentMsg"></child>$ J; X, Y  j% }
  6.     </div>' `- M, a( ?5 X8 g9 z6 C
  7. </div>
    & y4 v, `! r4 k/ Y, w

  8. 9 ~! N# @2 P6 M2 \, r
  9. <script>
    5 Y0 Q3 @) _/ K- i0 N( U) n9 J  S
  10. // 注册
    + r: x5 @# ~- D8 Q$ y: w/ j7 B- O
  11. Vue.component('child', {( u- @; c' a) E6 L+ z1 x" f- a
  12.   // 声明 props
    2 w+ ?! S- n( b# G
  13.   props: ['message'],1 `$ i. C! I5 H0 i+ I" A+ q1 P
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    7 a/ a1 Q) g  R
  15.   template: '<span>{{ message }}</span>'8 _4 t7 F7 P7 Q
  16. })) y3 t, b2 u1 ~% `' Z
  17. // 创建根实例
    & K/ S* V* [" K- o/ M! z
  18. new Vue({
    + ?: C3 I+ o1 Y) `& F
  19.   el: '#app',
    % f6 j1 C3 v8 |7 S: l1 p
  20.   data: {. t/ D' k9 Z; T* K$ |
  21.     parentMsg: '父组件内容'2 q1 @1 H& i$ u; X$ o! g( v' x
  22.   }
      ]* p3 o( Z) h# @+ k8 B# F
  23. })5 }! U2 n5 |& T- U& k' U8 I
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例" ]( t, w$ N$ a6 d% e) ^
  1. <div id="app">; u: b- J* `' F9 v
  2.     <ol>  g9 H% e! a0 n: M; t) E' z# D
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>/ q4 g* {/ }9 W
  4.       </ol>) o( I4 E* C# Z- ]9 w
  5. </div>
    6 I, K9 h9 a9 J9 `" T) q2 ~0 h: w
  6. : W/ S+ M7 H& q0 ^
  7. <script>3 `6 W5 M) l9 U' [% m( J% q7 t
  8. Vue.component('todo-item', {
    4 t1 Q3 N; x2 x  f; g
  9.   props: ['todo'],- L8 a" Q! f( s5 P4 ]4 n  Y
  10.   template: '<li>{{ todo.text }}</li>': l  Z) I! L) [3 R- v3 U6 n
  11. })
    5 _& ~4 r7 k3 Q) V" S
  12. new Vue({: M; _8 W6 o8 j% @: l
  13.   el: '#app',# s2 j0 {& G4 ~$ f
  14.   data: {
    9 ~; y3 S4 T2 k- j! S9 n" X/ F( u
  15.     sites: [/ o1 J( q! }# S0 I/ @" q% D
  16.       { text: 'Runoob' },
    6 @9 ~5 B9 l( c, ~
  17.       { text: 'Google' },( W/ _) b$ G* t4 m
  18.       { text: 'Taobao' }
    1 Y$ }$ j, t5 T' f, O
  19.     ]
    # c7 k5 T( F, l. B7 B
  20.   }' L& ^& E7 c0 v! q$ L
  21. })( J  M' Z3 U1 a- p& F
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {; ?, E% W, l  B3 Y' H. F( G
  2.   props: {
    1 f2 w! t5 V3 {! @
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)" ~' ~$ o. {2 d
  4.     propA: Number,
    $ G  u  w7 z4 }3 i# Y
  5.     // 多种类型: [# h$ Y3 p1 K3 _' {( |8 a9 ^
  6.     propB: [String, Number],1 f/ j( U$ c! w7 t) s
  7.     // 必传且是字符串
    - |+ ~+ }* h& T5 L" c- j
  8.     propC: {
    % h7 a" D$ b( `* j- _
  9.       type: String,2 d) v, d7 X! i
  10.       required: true
    2 ^: h$ W( Y$ M2 w! |0 \, p2 @1 u
  11.     },
    1 A- j2 h5 r+ Y: [
  12.     // 数字,有默认值2 i" h  x+ E6 T. q
  13.     propD: {; W1 L; P- r2 [; H. @
  14.       type: Number,. g# s9 ?% E" ^) h; [8 @
  15.       default: 100; f2 ~- J: b% S# e  A/ Y
  16.     },) G% D7 n6 W8 {$ W; C) n
  17.     // 数组/对象的默认值应当由一个工厂函数返回2 R+ s4 q# p4 U! }1 H! v: o
  18.     propE: {
    $ Y9 z- C( z5 F! A5 }% q7 z
  19.       type: Object,$ }2 I) `6 E9 Z
  20.       default: function () {
    ) b2 Y4 U1 D& d% p( G0 y6 K& J2 ]
  21.         return { message: 'hello' }% E7 t7 U6 J' k- o3 R+ G* @; O8 r$ B
  22.       }" n4 k% P* f, W$ A& V8 u. V4 U
  23.     },$ X0 p; f+ G! D9 c5 H; L- J" n
  24.     // 自定义验证函数; z7 V, c; \& p8 P+ c! C
  25.     propF: {
    0 Y1 S6 j9 S& R8 U6 T' {
  26.       validator: function (value) {
    : ?  V- q7 h8 E6 S- \+ \8 [9 W
  27.         return value > 10
    : y8 x; y6 @9 }2 i, m; D7 x7 \% l
  28.       }
    : u- l: N9 K  L: U8 G
  29.     }+ \: \0 I9 {5 _0 M
  30.   }  z4 e* L9 e" h0 P: _
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    9 e. G6 |5 R, B& \9 f% ^5 }# V
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件1 A7 i2 D+ P5 R2 u& ^! @& ]8 v( E6 A
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例: b6 X. O! q: F+ l
  1. <div id="app">
    # G. F! Q! q4 P  b- O3 o1 t
  2.     <div id="counter-event-example">
    3 _" w7 F7 O% T
  3.       <p>{{ total }}</p>
    # s+ c. m- L% _3 s3 c
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>% Z! ?" S& R0 W
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    - A5 T+ M" I5 \
  6.     </div>
    8 l" L) Z# z. K7 M
  7. </div>) E, B  v% h9 w$ u% n) z
  8. / |) H2 J) E) j4 \5 B- j- V' l  j
  9. <script>
    - L" j' y- Q9 O1 ?9 ~+ D
  10. Vue.component('button-counter', {
    : E! K8 A, f# K+ |' s+ E1 K
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    8 t% g: Q# j, i. e  m
  12.   data: function () {6 ^- E. S! V8 O" g3 p
  13.     return {2 n7 `( w' e3 h$ T4 g
  14.       counter: 0  f7 ]- g2 G! m/ j0 |6 @% S
  15.     }8 p( ~: Q& T1 y  d0 z
  16.   },# |, R) d% p0 ]. ^/ W$ H; S5 F
  17.   methods: {  S) h& Y6 n2 N; A
  18.     incrementHandler: function () {
    2 }0 @1 y& W' _6 m$ S
  19.       this.counter += 1! E4 D# Q; Z! z4 M# A4 E) x# l
  20.       this.$emit('increment')( h8 B3 j6 ?2 M# w* E; O
  21.     }
    0 h7 m% r: B/ I+ W
  22.   },
    + g# @8 a- V' @. Q) K% `. R
  23. })
    ) ~) Y7 }' r# {7 {/ Q& B
  24. new Vue({1 Q6 w3 {$ j) l! [% N1 y. c: L; S
  25.   el: '#counter-event-example',
    . {. g; i# V. c# E
  26.   data: {
    ' R4 f3 ~& v$ e4 P8 M# |! u. s
  27.     total: 0
    ( _. F/ }) f! P5 F' Z2 \- e
  28.   },
    . [9 g5 _+ d% f
  29.   methods: {
    ; F6 e4 k* W2 G9 T% n
  30.     incrementTotal: function () {) S" R; X4 A& Q- x, e8 W
  31.       this.total += 1+ v* C4 n' h  Q! u& a; q
  32.     }7 e- T  e/ N: g/ p( F  p0 o3 \
  33.   }
    6 ^6 p' ?" [1 f0 L1 G7 S% g
  34. })8 o& d) V- S6 y/ k+ G
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册8 p5 R' C& a. R* W6 q2 P$ Z4 N- B
  2. Vue.component('child', {6 S7 x; x$ ]$ q0 E' A; e& s, F% R
  3.   // 声明 props+ n4 l- s2 r; @8 v. e9 @7 g2 o
  4.   props: ['message'],
    ( n6 J' ?$ ]/ `9 O1 F' }
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    9 J! {& Z- g9 s$ O) d% r
  6.   template: '<span>{{ message }}</span>'; `, j: F7 B) {% c& ^8 h0 M2 f
  7. })
    5 P) C# @2 Z; [8 v7 o: r
  8. // 创建根实例
    ) U$ K/ h2 u  s- k: F
  9. new Vue({
    0 V& _3 d$ e7 O5 ]9 J. C  {+ S
  10.   el: '#app',& _7 E: B; [, L, u) D8 X6 e4 `
  11.   data:{/ N& x2 ?8 E' D; O* @
  12.     message:"hello",8 c3 I" k  m, o' ~0 t
  13.   }
    , G) m/ j2 z2 H' i' h* H! T. ~- Y
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {- d% r; u9 b  t+ B# u0 K
  2.     incrementHandler: function (v) {/ J9 s$ o0 w9 h8 O
  3.         if(v==1){7 N& K( x8 ]+ t* ?' |, v2 d
  4.             this.counter -= 1
    6 b8 I9 n" @* q2 h+ K1 C
  5.             this.$emit('increment',[1])" ~& O7 ^0 ~7 `. U. ?$ Z" ~3 c0 t
  6.         }else{5 ~5 j( x; H/ s! [# t4 l+ N6 j
  7.             this.counter += 1
    2 u7 ?2 v1 M+ ]2 S
  8.             this.$emit('increment',[2])
    ( h" w& C( H  ?; Y% D* o; n
  9.         }
    - ?- B/ g. x; }7 ^  N8 F+ w* y7 P
  10.     }, G8 j/ i& r. b: i, E
  11. }
复制代码

6 [1 d/ _. {' Y* M8 {6 z9 p
% k  p' `  R# @8 `! @2 L
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 15:55 , Processed in 0.085023 second(s), 23 queries .

Copyright © 2001-2026 Powered by cncml! X3.2. Theme By cncml!