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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15685|回复: 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,并使用它:

) c( s9 C0 H2 `& P6 Z; l( c
  1. <div id="app">6 g/ j1 q& h4 L* w  M7 t0 L
  2.     <runoob></runoob>; C3 y0 r! P; @/ ]
  3. </div>
    % }4 Z$ {; s# o- I" {* E

  4. & W1 F, b2 V0 D
  5. <script>* S2 }6 C: f# Y/ f- S7 h
  6. // 注册$ C) t" Q6 D- @4 n
  7. Vue.component('runoob', {% Y/ N1 b3 ^& C- O4 \
  8.   template: '<h1>自定义组件!</h1>'
    4 Z9 ]1 G6 g5 x
  9. })
    $ Q2 y& V2 d( }1 y
  10. // 创建根实例0 I/ b+ B( f: M( e, k3 w+ v
  11. new Vue({5 D2 N$ ]4 s+ N4 R. Z
  12.   el: '#app'
    1 ~5 x8 P2 t3 y) y) }
  13. })) `: y# o+ M! `& t0 K9 \
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
9 e( T+ L' N+ f4 a3 U* F' y
  1. <div id="app">- f( b5 a# O+ A9 k! r; _
  2.     <runoob></runoob># J, B+ P0 E. w6 B6 z3 S) J/ `
  3. </div>  n7 e+ j' U8 V7 T  A  `- z

  4. 9 X( O6 w: q- b/ l, x% v( y  R
  5. <script>
    . ^$ N- b2 P8 E5 `! k& ?" G
  6. var Child = {0 q; Q, z& `$ V. I; z# p
  7.   template: '<h1>自定义组件!</h1>'$ E  J' X8 ~$ k6 l+ W" X" A
  8. }+ A, t9 m- N! N1 K, z

  9. & V0 W0 {* M: v8 Y2 y: z- ~, B% M
  10. // 创建根实例
      E: j6 O4 A' Z  Z  Q
  11. new Vue({9 V" A$ b8 ]1 D$ L0 O  R& b! m
  12.   el: '#app',. v' o" R5 M& V: Q* {8 z# ?
  13.   components: {, ^& \' o  F# F
  14.     // <runoob> 将只在父模板可用, v; s5 S8 \! ]3 u0 O6 [
  15.     'runoob': Child
    9 ~- k( w2 s9 K! Y
  16.   }5 ?: J4 w4 L- A; i: I! @9 }8 e
  17. })' @" y- N- O: |* _5 G
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例, `& V) |, x, l& g7 i/ P1 j
  1. <div id="app">$ Q- F! }6 x: p+ h  o% y
  2.     <child message="hello!"></child>$ B8 Q/ W" X4 ]. c
  3. </div>
    ! `* m. a% G2 T
  4.   W: e. z# M, R1 T5 z1 A
  5. <script>! W6 z" a* h0 ?$ @
  6. // 注册& z* d7 m2 ]1 p1 ^# T% b  k' V) R4 {
  7. Vue.component('child', {# Y4 }1 J! c2 `+ \" {2 F
  8.   // 声明 props
    8 J1 U( d2 Y8 Q# g6 @* ^
  9.   props: ['message'],3 R" J2 u! X( W
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    2 l( q: P- P7 O: L, N
  11.   template: '<span>{{ message }}</span>'
    ' Y. y0 o. g. p: |7 ~/ K9 U( P
  12. })$ r- ~8 V9 u  u7 z
  13. // 创建根实例1 C) H4 Z& a$ O
  14. new Vue({0 A% N" q5 u0 w; w( m! q! M
  15.   el: '#app': h- Y8 J& @- M# h) E/ V  V
  16. })) S* x5 O4 u& F! L- B8 T' U
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
8 v2 W6 d4 S2 H% L8 V, T
  1. <div id="app">
    ! \& p+ ^# o9 E2 H5 ?
  2.     <div>
    - |+ R1 f5 U5 F$ T" ^1 f; G
  3.       <input v-model="parentMsg">
    $ B! }- c1 y  U! ]
  4.       <br>  L: i( Y* E4 Z3 \+ q4 W1 f
  5.       <child v-bind:message="parentMsg"></child>1 A' w. C( V% E
  6.     </div>9 j) ]# ?* O& @0 e# c8 D; a8 V8 ~
  7. </div>' e( `2 D4 N" i: b# q

  8. 4 m  _$ N4 x* H* X0 M5 {& S
  9. <script>
    0 c0 y, R7 h- y) c5 t* W4 v
  10. // 注册
    1 c, X$ h1 o+ O, \( I2 s' G
  11. Vue.component('child', {8 U& ^. t& N3 t% i
  12.   // 声明 props
    . X; v5 W. j% [) B1 e% |
  13.   props: ['message'],
    ! d/ q$ `& s0 M: {* C( W3 A; M' ?
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    2 b. O( `8 G/ {3 c3 E6 m% C) e
  15.   template: '<span>{{ message }}</span>'0 O- E. R: s2 H/ |) o, ~
  16. })
    - R* l$ f- e) S9 N) l2 I2 ~
  17. // 创建根实例
    $ d$ G/ p+ j  w$ C5 p
  18. new Vue({! p# A& \1 {+ @2 y- _
  19.   el: '#app',% A! Q  V6 U% i+ U
  20.   data: {( n( L5 ^8 W/ X3 U) X
  21.     parentMsg: '父组件内容'
    & k9 A1 R& W7 \( E, ]9 U! P% K; Y
  22.   }
    ) W4 S6 y, k+ C' b, V
  23. })
    ) F- {. k1 E  F( d
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
( j+ S. v7 Z$ \9 ^& q
  1. <div id="app">$ j0 M' g7 X) _1 q: n2 i
  2.     <ol>' x9 m+ Z8 J/ J' ~% M0 d8 c4 m) Z% b9 N
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>7 y" O: P/ o% ~/ h3 p; V! g
  4.       </ol>
    % z* d; I+ ]) t0 W+ O
  5. </div>
    + y" Q$ `" E8 V. [1 [5 s
  6. . [  n0 K) q1 l( A) T" Z
  7. <script>
    , Y' i4 m/ I8 E$ a+ z- q
  8. Vue.component('todo-item', {% }, f: D0 o3 c6 y( j$ c
  9.   props: ['todo'],; {$ @1 i" ]+ w  ?. R& Z
  10.   template: '<li>{{ todo.text }}</li>'
    " _( M. V0 i  q* L5 ^5 @' J- p' P
  11. })
    7 d% }$ W0 t: }* _8 e3 e& d4 f
  12. new Vue({, N) f2 S- |/ I- L3 E8 H
  13.   el: '#app',8 q, _/ d- i/ r3 o
  14.   data: {
    4 {: T' J9 l, S6 J7 R0 _( V5 {1 R
  15.     sites: [3 \9 i. B* w! ~( @
  16.       { text: 'Runoob' },7 D9 k# Q( Y9 o) p; k, S! k5 ^
  17.       { text: 'Google' },
    1 ~. i, I2 h/ v3 D, U
  18.       { text: 'Taobao' }
    - p) z7 @: C/ n6 @9 {- D
  19.     ]" l: U- `7 {; l0 H
  20.   }
    ( u  }4 d0 v! F0 Y' b
  21. })
      a1 O4 I2 _, B+ u9 p, p
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {3 |6 z: }) e1 y/ b
  2.   props: {6 V) J4 z0 a& h
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    - P- ~# W1 u+ l6 Q
  4.     propA: Number,
    / I1 n; {# ?# T& I! A
  5.     // 多种类型+ S. }7 T3 a& m8 |; ~- r
  6.     propB: [String, Number],3 p# j9 v* x1 }- x9 w& T, l: M: H
  7.     // 必传且是字符串
    + c# U- Q5 y1 K+ N; `, r, `5 w
  8.     propC: {3 [- v0 |6 @% [+ h; q- E# q
  9.       type: String,3 q! a- K4 o- V. F( W
  10.       required: true
    ' w2 d4 s1 h6 m) Z
  11.     },7 n: _; x; ?0 u4 r: E
  12.     // 数字,有默认值
    2 ^  J' b9 V* o% A; i0 |! {8 L
  13.     propD: {
    4 R4 ~7 n  j, W  q
  14.       type: Number,
    % ?' j4 z6 M! w5 j: C3 O
  15.       default: 100
    ) p1 M5 C- s4 R1 [/ C
  16.     },8 X; r* x- {& B3 H2 J$ L
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    5 `) C9 N3 ?6 V4 r/ `" W% L
  18.     propE: {
    * l" A* X! s: ^! T  P
  19.       type: Object,3 L* x# F; B8 e, A9 V! e, R
  20.       default: function () {
    , {3 p1 Z  r: M, c! B. _
  21.         return { message: 'hello' }  R9 V6 U5 c! m
  22.       }1 x  U) L/ _# f5 }1 L
  23.     },) ~/ ^8 N" ?! m% g* S
  24.     // 自定义验证函数( ^  \7 l' a3 e! U) L
  25.     propF: {
    ) @, b8 d+ ]4 _
  26.       validator: function (value) {6 }' K5 {* q7 A% d# D
  27.         return value > 100 S4 ]" X; t% w1 }. W4 P" i  p1 ^
  28.       }0 \, }1 ]9 S2 o8 m
  29.     }
    3 \2 ~6 Q; r5 O6 K/ f4 ?4 b) p
  30.   }
    ; y3 @5 j& T: }! |- f* ~7 [
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array1 S' H9 U$ O' n+ `) v+ Q. W
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    6 L# N/ _0 j# p. t/ M  J: j
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例" T0 {- v0 H2 ^* Z
  1. <div id="app">% ^* y, `& ~1 X, T, _5 K
  2.     <div id="counter-event-example">; t0 H+ r" G) e) f0 l! h
  3.       <p>{{ total }}</p>
    7 N, h4 z: j2 U: @  g) d
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    1 }6 A) ?8 e" I/ _, O: d6 c
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    2 O3 d- M# e. ]% Q
  6.     </div>
    , ?6 @" e, X6 R* R3 |- ]* u) ]2 }
  7. </div>
    8 `1 P' e% Y6 ~. X" R0 }

  8. * e& W/ j0 f* J# R8 u7 D
  9. <script>: ?0 |/ d) v& V3 O5 D& p. R
  10. Vue.component('button-counter', {
    & ?' t$ a! @+ N7 p( \9 D* W9 J  r
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',, S6 c0 y0 |( {, O! }% o
  12.   data: function () {6 \4 t6 j  D2 _" U/ ?8 V$ f
  13.     return {% r! m+ q  O. ^
  14.       counter: 0# G  S( f& [' L+ `9 t
  15.     }5 c8 A# H/ M# k3 F
  16.   },; B+ d0 o3 [, m/ o' X2 O  E4 i
  17.   methods: {" ^# B$ R  ~: l
  18.     incrementHandler: function () {
    - i+ n8 c8 L% r$ R8 U) L) _1 }1 S
  19.       this.counter += 18 i  R# r. s4 a3 t- s  g) V8 ?2 B5 t7 Q
  20.       this.$emit('increment')8 z, J' Q. h2 r( L
  21.     }+ C' @/ I" {% y4 ~2 A) E7 g& K9 z
  22.   },$ T" C2 j3 f0 }& _
  23. })' E* p9 j' i; `- D1 d. i! g
  24. new Vue({+ Q) m  I- k% L6 `: z  E
  25.   el: '#counter-event-example',
    5 l! t6 Z8 w) l- _- Y2 O
  26.   data: {
    ( T* x! }" B# X  W" P. S, G
  27.     total: 09 Z$ v1 @4 u+ p& W8 |1 m
  28.   },$ o; Z0 k* O: ~
  29.   methods: {
    6 j" j8 _1 b  N& r: d$ J5 l$ Z; B
  30.     incrementTotal: function () {6 B0 U' g! l1 g
  31.       this.total += 1+ z* O' {4 n2 h+ D
  32.     }8 y0 ]0 V4 r5 o4 `& i
  33.   }3 k5 ?/ }# V) G- o* r' k
  34. })
    4 P( B" X! [. U
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    ' y( H( B1 l: i/ |0 X# S% q  L
  2. Vue.component('child', {/ A( F3 p$ N+ N9 Q+ \$ e/ y
  3.   // 声明 props( M, D; G4 c5 q; `2 L0 p1 P( E3 z
  4.   props: ['message'],* N9 o) B+ z7 h5 m
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用" V/ e$ S6 m$ s
  6.   template: '<span>{{ message }}</span>'
    2 ]5 S1 i& F+ a; s9 [' n
  7. })$ F- B; Q: V: X  L" h; `9 _: ^
  8. // 创建根实例# o' f5 i  P' ], @' o4 J% y! i% F' z
  9. new Vue({
    : i2 m; \& M3 v
  10.   el: '#app',' b* k' y+ B3 m  K8 ~- z8 y
  11.   data:{% ]( K$ b1 m: J
  12.     message:"hello",
    : s% C- }, V3 D
  13.   }
    ( G% s3 d2 q" o  N
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    ' V/ n7 q  @; W7 V
  2.     incrementHandler: function (v) {( l% r# d0 q: L* i
  3.         if(v==1){
    ' p9 Z3 U/ O8 W( K
  4.             this.counter -= 18 r$ u* O' z. y; A/ j5 w
  5.             this.$emit('increment',[1])+ Y5 J$ y9 Y9 ?4 e8 B/ n& F
  6.         }else{
    ! }# G( F5 ?4 i# h3 F/ h
  7.             this.counter += 19 G1 v: D& P7 w, l# Q  e+ S) s" d
  8.             this.$emit('increment',[2])$ q9 v' d7 H6 m1 X
  9.         }$ a$ p! k& @9 h% A2 w$ e0 q
  10.     }
    ! l, l% e0 b) c. B: u  @
  11. }
复制代码

( n) ^$ U* l3 K0 i- k
5 ~: o. k/ Z  T0 V2 \
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-4 09:30 , Processed in 0.086395 second(s), 22 queries .

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