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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 16306|回复: 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,并使用它:
! a2 @" q; z! ]/ }' K0 R
  1. <div id="app">
    / c  v7 o9 [! N' k: S% w
  2.     <runoob></runoob>% Z1 P- n$ P& _3 \* o
  3. </div>
    6 e8 C- n2 R% |, u% O- t1 s7 h  W

  4. & E" D  i* A$ P9 D' d
  5. <script>
    / z3 z6 W% r7 G5 N3 _8 G- Z) o+ s+ w
  6. // 注册
    - Z7 q7 W) P' W  }6 p; q$ T
  7. Vue.component('runoob', {
    . {7 Z$ x, s) K4 c. e* @
  8.   template: '<h1>自定义组件!</h1>'" b' r  S# y1 _
  9. })
    $ p% n& R3 u4 |0 w$ a
  10. // 创建根实例
    & ^, X) n6 ]. f0 G" x# c5 N
  11. new Vue({6 C4 _! j" J% ]& T) u+ e
  12.   el: '#app'
    , I- A4 t' d& g
  13. })
    7 r9 \8 U% ^- L! F6 q: ]* \
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
5 ?/ A* j  p, n( f6 U. T. W
  1. <div id="app">
    8 o& [! I' Z. y  x. W
  2.     <runoob></runoob>
    2 F( f" R' |1 m  a9 M; u
  3. </div>% m: R2 K+ N* w
  4. . B- P9 g$ X7 i0 V5 j
  5. <script>
    & s: f  O) W& c6 ]6 N/ @
  6. var Child = {
    / S0 ]: y& N( X- L" @- O
  7.   template: '<h1>自定义组件!</h1>'
    2 x2 @# U/ |+ f+ \, F
  8. }+ D* E6 i0 l4 {' ?# P; W0 C/ [$ l
  9.   t8 p4 v4 g) |5 c
  10. // 创建根实例
    6 f) ?* g% t% V
  11. new Vue({( C' O: _7 d% o1 {
  12.   el: '#app',
    " j. R* s; P  c/ ~$ a! }% {
  13.   components: {4 D+ R# w8 G# Y+ k2 e3 @4 U6 O7 z* `; R; c
  14.     // <runoob> 将只在父模板可用: G, \+ }2 c: W
  15.     'runoob': Child
    ! G* u  V( ?. n! W
  16.   }- i3 E# x2 s, v; g' {5 F
  17. })
    1 r; Z& u. J- F
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例8 m; y! m7 X/ }* ^0 n
  1. <div id="app">
    3 J; H. @" B1 V% D/ s
  2.     <child message="hello!"></child>! n0 w3 C3 V8 z& V4 ]7 \" T
  3. </div>
    - S2 l4 d+ h$ r3 v% f$ @
  4. 5 @  ~/ G- ~# Z8 v2 n4 g% J
  5. <script>
    + r% L' @0 ]. F( b7 o2 G
  6. // 注册/ p+ h" F6 r, `% K  n- I% [
  7. Vue.component('child', {
    - T* |' o3 T2 J: [
  8.   // 声明 props
    ' s# j- e9 \3 }+ j% ~
  9.   props: ['message'],
    ( I% i+ G) O! _0 F
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用/ d3 D3 Q5 l* L1 R4 w. r
  11.   template: '<span>{{ message }}</span>'
    5 z- `% @* `& |5 i" u
  12. })+ ^9 K' i" g. @9 [5 Q
  13. // 创建根实例( _0 o* O* E- u  x
  14. new Vue({8 C8 T! c$ r1 d; |7 r; M, p
  15.   el: '#app'
    - j5 r' L) A, V0 ^
  16. })1 X6 A* ]; X; X2 `; W4 ~
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例* a; g6 x" H7 y, f
  1. <div id="app">
    3 c0 u3 n1 j: T/ i# l' r- p; W
  2.     <div>; _$ g2 j6 z# F+ S' v/ L8 r0 h8 b8 @
  3.       <input v-model="parentMsg">
    6 W, b/ V( }: J' G/ T2 ~
  4.       <br>% y$ B& n/ p, I# l) T
  5.       <child v-bind:message="parentMsg"></child>- ~/ V: I' M% E* X
  6.     </div>) P- I' G$ e$ W1 \: N
  7. </div>
    * r- o  w6 P! q& |
  8. $ h6 g. @2 a$ \% Z' p" M
  9. <script>
    1 a7 T5 p7 o7 e+ V
  10. // 注册
    7 I* c  I. d$ R7 F1 u' s  J) F9 Z
  11. Vue.component('child', {1 [0 x  G* c0 U
  12.   // 声明 props
    9 }+ Y. G* F5 [7 P+ f. k
  13.   props: ['message'],& P) S0 [+ r3 T# W6 ^
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    3 W8 h% B( L* I$ U% _, Z! ^% r; B9 C
  15.   template: '<span>{{ message }}</span>'% L+ L+ Y- T0 a/ s3 Q
  16. })
    / R: t; L' d( G  o8 x7 M6 G0 C# P  A
  17. // 创建根实例, o+ T$ a% p/ H# v
  18. new Vue({2 t* o$ j: k  q( H( H! p
  19.   el: '#app',
    7 D  R* G* q% e
  20.   data: {1 K7 ]* h& v& J% r+ w  g) }
  21.     parentMsg: '父组件内容') Y0 h# [) k) T% M1 ]& |/ w
  22.   }! _- x) o" B$ x, u& B7 W
  23. })
    / a! ?; [& ?* j. o9 |7 L* q
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例8 Y4 v9 X+ n7 h' \6 S& @% P
  1. <div id="app">/ ?, ^' m& }" d6 x& @
  2.     <ol>5 P' `5 d, p& ~( ?7 Q
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>) z, N7 O8 q9 i4 d% i2 }$ T0 V; a
  4.       </ol>
    & N2 f! ~; L8 m6 ~: X& t: a
  5. </div>' W: `7 C6 }$ c* V! c/ J$ k, X
  6. " w9 n0 l/ v% o' ^4 t5 \- y
  7. <script>
      f# z8 k* p' j2 F# R
  8. Vue.component('todo-item', {" t7 v# \' E9 q' a! k! Z
  9.   props: ['todo'],
    ( s% L# w+ }7 e8 O6 W
  10.   template: '<li>{{ todo.text }}</li>'
    % I1 U; a, w$ _  z
  11. })1 ]: X2 l; \! V6 J* i  m7 ^5 v  e
  12. new Vue({
    " G7 X6 x- P* j; F1 z& M
  13.   el: '#app',
    ! u  j0 o: ]9 n8 j' k
  14.   data: {8 S% d' w. s, v, D* G
  15.     sites: [
    7 r- G9 ~4 z  |4 O' e
  16.       { text: 'Runoob' },
    ! ?0 c6 A8 A7 @/ b
  17.       { text: 'Google' },
    2 l) @/ S1 m. A$ L  w, B
  18.       { text: 'Taobao' }* A: y# K, V7 F8 @% H
  19.     ]6 ^2 d+ s; Z* [- [# b- t: ~
  20.   }
    6 c, v: r7 a+ ^( G
  21. })% {1 v( F' i1 [; M  |3 [& e
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    9 }3 p- ?# @' k9 L+ ~) A
  2.   props: {' T- ~. Q: e- a
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    % B( A% E3 w) q
  4.     propA: Number,8 K' S, I: \5 @! I, c
  5.     // 多种类型
    4 g# d: r9 W) f' H
  6.     propB: [String, Number],. b7 |. E# s. |, l2 H2 m6 |  s
  7.     // 必传且是字符串9 O+ p1 T  q4 K* D# H) G$ X
  8.     propC: {
    " {( Z' n  E7 {' a, I( h1 L
  9.       type: String,8 C7 m8 E( W+ n/ M& Z% j2 x# l
  10.       required: true
    8 t5 q5 q+ V' B- Q
  11.     },1 C- R: F0 R; k+ b7 K
  12.     // 数字,有默认值/ S, K, e1 r" }+ N1 z: p
  13.     propD: {
    . i) J3 q2 P2 z5 w3 b
  14.       type: Number,
    + T$ S0 o. x* e. H! L) s
  15.       default: 1002 p( @! T9 d& d* u5 b* E: ~, r% h
  16.     },
    9 s+ p0 y3 v: q7 a: `2 |  Z3 k
  17.     // 数组/对象的默认值应当由一个工厂函数返回# c. E' l' K* a4 U
  18.     propE: {
    ) g* W% v- f+ z8 \0 V# h
  19.       type: Object,
    ! g& Q$ e9 ?5 o
  20.       default: function () {
    4 ^; _/ l& U9 y) s9 N
  21.         return { message: 'hello' }
    4 h$ k0 f7 \4 h5 M- |
  22.       }
    + S, }; ^1 O3 J; r
  23.     },4 R# f  k& S# ?6 [, J/ N
  24.     // 自定义验证函数
    ) [: `7 e1 W7 b
  25.     propF: {
    ( L7 g( ?. h  O8 T7 N
  26.       validator: function (value) {
    0 {8 q! H7 G' |
  27.         return value > 10+ c1 y, _- ?7 S
  28.       }
    2 L, p. h. w( }, z
  29.     }
    / ^( S; z0 J; ?% B( m
  30.   }8 a: O6 q- H$ V' h
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array3 ]0 e3 A/ k) r
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    * a* W! m8 D7 ?0 p
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
2 J# U0 m( i5 q, ^* u- ^8 t
  1. <div id="app">
    ! i' o  }. T0 c& j# E
  2.     <div id="counter-event-example">9 c) z/ t7 m' `7 P) u/ P# ]
  3.       <p>{{ total }}</p>7 l$ A6 i& Q* p3 n
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>& q: j7 ]) P: A" D8 M( C
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    5 V" {3 S8 C0 Y; i! Y8 L: p
  6.     </div>
    5 _; I; @1 J( i' `  u$ v
  7. </div>
    ! W( @1 ^) U# |, J

  8. ' v7 O7 A( b% t2 y8 D
  9. <script>
    7 H4 K$ |7 R, l+ P
  10. Vue.component('button-counter', {
    / g7 H; H  _; O- t; b
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',1 n' h6 y: y# j
  12.   data: function () {
    ' s# m% p- r8 V5 R
  13.     return {
    / s- D& m+ l0 L3 w0 H$ h+ W" Y
  14.       counter: 0
    $ {# x  j0 O0 r- C1 s/ H9 f
  15.     }7 K8 U- L# o1 f9 e. }/ N* N- Q; H" H
  16.   },% s. T) D* s8 b
  17.   methods: {
    ' ~+ [0 C* E) `1 R2 W4 y$ \' \
  18.     incrementHandler: function () {; E# o' Q' x' p
  19.       this.counter += 1
    3 _. ]! e) n% z/ R$ \3 u
  20.       this.$emit('increment')
    " j7 M- N  X1 n, V. U( @
  21.     }# R  o3 O# C  F
  22.   },
    3 k2 d! H1 J5 b& O& s4 E
  23. })
    3 Z+ T4 f6 {% m. A0 w: \# {
  24. new Vue({% G; y( u; B) X8 s
  25.   el: '#counter-event-example',# _1 ^2 I8 O8 ?& R+ M) l6 F
  26.   data: {2 }' C( S3 Q' h. u6 m/ K! y* i" T" p
  27.     total: 0
    * c1 r: y( x. K3 I" c
  28.   },; B  z4 ~. O$ x" R
  29.   methods: {9 t) m" C4 C: D1 A. K
  30.     incrementTotal: function () {
    9 E2 N4 W7 y0 M# G
  31.       this.total += 1: z: B; J$ M5 L8 @( w. X/ T
  32.     }
    ; p" c4 X/ v6 D6 ?
  33.   }0 B) @% y- X8 C$ ]8 K8 J
  34. })' ?" x+ L3 y! K' p% {# {( L! ?+ @
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册3 z7 O7 z4 w+ Z5 |
  2. Vue.component('child', {" X' ]. K6 }+ k9 ]6 q
  3.   // 声明 props
    6 p' v4 W& p  a: k# ?
  4.   props: ['message'],& P  \; @$ z  o$ x7 y! V
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用, o8 e. r5 y: i3 @( X/ ]; \
  6.   template: '<span>{{ message }}</span>'- j9 ^4 ]& t$ J1 h+ P4 Q) r
  7. })
    & {9 T' X3 `# p; B; k7 V* C
  8. // 创建根实例
    " o/ u& C4 [$ `5 y% ?  k
  9. new Vue({( K: w9 O3 [- \* R7 n( h
  10.   el: '#app',  s: D3 `3 H% F% G  }6 S% T! ]
  11.   data:{6 w* b- {- c+ J3 F
  12.     message:"hello",
    + n) I0 g6 x  j' s0 j
  13.   }
    ! a0 r9 f/ p' Q/ V! |) T! U9 a+ {
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {* K, d! c# ?  x
  2.     incrementHandler: function (v) {. ~: M- j- F# w. Z4 D
  3.         if(v==1){
    " Z1 j2 f6 o' z& Z0 R7 U
  4.             this.counter -= 1! j7 t# A% f5 \& D+ `
  5.             this.$emit('increment',[1])
    ' z& I* y  C- o; G" H8 ?5 }  m2 M
  6.         }else{
    ; G* n; R% p  k& a- w/ V/ ~
  7.             this.counter += 1: _9 i6 _% s$ v/ T% [4 J% l
  8.             this.$emit('increment',[2])
    + q. Y+ m/ R5 p
  9.         }; k5 k7 J) s1 L6 z( R1 n
  10.     }
    8 _- a7 [3 C' ]$ L' k# a0 U
  11. }
复制代码

5 \( q8 D# ^! B: J3 f
8 e. {" K# x2 ^- o
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-8-4 15:15 , Processed in 0.056452 second(s), 22 queries .

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