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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

" J9 F- L: Y) x8 x% l2 l
  1. <div id="app">
    & @9 z0 i+ I6 c1 U" L6 d- K2 C$ a
  2.     <runoob></runoob>6 o! C* i6 `; J2 a' ?$ i5 T  Q
  3. </div>7 @1 m7 W/ b4 @" |$ |) ?8 l, ~5 B9 y

  4. ) G0 i/ P" Z+ O% T4 r2 q. T  Q
  5. <script>
    2 e6 n( y. H, I/ I
  6. // 注册
    9 r# @5 e5 P- Y
  7. Vue.component('runoob', {( P0 N- l: u9 ~# e; f% m
  8.   template: '<h1>自定义组件!</h1>'
    % V. m  t2 t4 V( s% ]% G% ?/ [5 B
  9. })
    : Q! L/ _- x, E; Q
  10. // 创建根实例5 y# E: G% a0 p. S; z+ B6 s; m
  11. new Vue({3 X7 a+ k, u- Y2 b% q: `  [2 ?  L
  12.   el: '#app'
    8 @2 W5 k1 H, s- L0 l+ D
  13. })
    " E& U1 W1 R& M: \1 L6 b4 m
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
( T3 O4 o! n$ m- Z; F( C$ c" K- Q
  1. <div id="app">
    : F6 h+ j) h! S( |
  2.     <runoob></runoob>3 N2 P  d: q5 |
  3. </div>
    % b' X7 }$ d) h4 W
  4. & ]3 q3 `" ?5 r3 d2 H* m: X
  5. <script>
      G) [4 ]! o1 {3 R  d4 e
  6. var Child = {& Z4 a& [5 o) z8 _  g6 e2 l1 Q
  7.   template: '<h1>自定义组件!</h1>'; {9 z0 r0 R8 W8 Y* D
  8. }) V5 o3 R: y* O1 z

  9. 6 d8 {" c9 X' E7 F/ Z5 j3 }
  10. // 创建根实例* l$ m# G& P, {! O( @( h, `' G
  11. new Vue({  v- c4 a0 u: C: T" _% S/ K
  12.   el: '#app',
    : y2 u  f# n* [7 V
  13.   components: {: L2 J6 m0 X( `4 j& s
  14.     // <runoob> 将只在父模板可用' T" c  u: U. n7 k6 I( l
  15.     'runoob': Child
    ! f$ U' v! u3 I- y
  16.   }
    : Q7 K* m( }5 ]4 s0 n
  17. })
    ' g* `& _& F& X: b* W8 E1 x% k
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
4 d, K' Y9 ~4 k3 V+ J, @: Y( P  o
  1. <div id="app">! @8 Z2 ]; Q: R+ u7 [4 w) r
  2.     <child message="hello!"></child>6 g: q4 e; D+ E0 \
  3. </div>' Y7 w( V$ I2 S" u4 G

  4. 4 K+ [+ {% k" Z
  5. <script>+ N+ S. @* [! X: P( o8 i
  6. // 注册
    7 h! `. y# b0 @
  7. Vue.component('child', {
    & V# y2 r3 i; N0 X( Q& I4 y
  8.   // 声明 props5 c6 E0 K& I* \( }
  9.   props: ['message'],' O; W/ m- g& \' X* Q
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ! s7 O, K5 y7 j- c; V' t; a
  11.   template: '<span>{{ message }}</span>'; h, }* \8 b- x- ]
  12. })
      r; C6 t+ z. j( g
  13. // 创建根实例) u$ V+ z  _$ W7 ~
  14. new Vue({
    - _. V- [0 ~3 z% F+ \
  15.   el: '#app'
    * E0 j! U1 s; y& a# P
  16. })0 W0 L3 X+ W! f$ }% x1 z. K
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
# `: c3 b7 n- ~$ c, k* c
  1. <div id="app">
    - P9 L! b2 g6 A8 d* L: {% Y
  2.     <div>
    + Q- I7 G( k) q% x5 l
  3.       <input v-model="parentMsg">
    . f7 }2 _1 M9 X# p' |
  4.       <br># p! E4 F3 o; G* n7 X0 E
  5.       <child v-bind:message="parentMsg"></child>5 W+ N# I3 D8 G
  6.     </div>$ `% A) S  G: r: x- ], |" J! `
  7. </div>% f0 s& @$ S2 b

  8. ' \% {% I. W4 M; G9 z
  9. <script>
    - _  M7 C  d* x! D( o
  10. // 注册4 l% [* Z6 u( l/ m; ^" r/ x  U# k
  11. Vue.component('child', {
    . l. Q2 f3 t/ |( \
  12.   // 声明 props
    7 V7 X7 I# m4 j- f% B
  13.   props: ['message'],9 a0 u3 ?5 f' r; _: j' v' j& p
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用) N" H8 J) }% ?
  15.   template: '<span>{{ message }}</span>'$ b8 @% x9 [( `) C
  16. })! I, e6 {6 L! J
  17. // 创建根实例
    ! m) r% \* M% l; _" ?
  18. new Vue({
    $ u  I. ~. r4 u8 C$ e( g2 c
  19.   el: '#app',8 Y; v3 _' v1 N" Y- ^0 u
  20.   data: {9 M7 o5 A  {& G6 M: h6 p. R1 X
  21.     parentMsg: '父组件内容'' K% h6 n8 ^! ?. `0 x
  22.   }
    : \8 ~: g8 \# l" O7 s
  23. })! s5 v' ~# {3 w, a5 g4 G! G
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
! U$ `/ n* @" B
  1. <div id="app">
    / J1 U& R$ o0 C4 t" `. i) }2 _$ E
  2.     <ol>* Y7 c# {9 E: w3 H. D" \
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    7 _. `6 ~- a6 F8 l: v& F; Z
  4.       </ol>
    4 f( d2 l" q, j" k: m
  5. </div>
    " ~/ z9 r4 G, C% m* _4 p
  6. + D  A0 @- V& Y7 T( S
  7. <script>
    " Z- {5 |4 p9 w+ S6 A/ Q' Z
  8. Vue.component('todo-item', {
    . K' N3 F' x. y3 v
  9.   props: ['todo'],' w# L7 J7 u8 f5 {3 O8 z  U
  10.   template: '<li>{{ todo.text }}</li>': p1 B: x0 K: x0 T
  11. }); I! e7 p0 b- d3 G) Z
  12. new Vue({( Q. s. C5 \9 m5 {. K/ |9 f9 F
  13.   el: '#app',' \) x5 g4 ]% P( @* V/ z0 s3 M  R
  14.   data: {
    ! P8 Q7 K$ U6 w7 C
  15.     sites: [1 G2 I5 l; I  z" p! W
  16.       { text: 'Runoob' },
    " Q2 s' C# T* y7 k' k! M( Z7 H
  17.       { text: 'Google' },
    * x" Z9 t0 ?# g' c3 [8 g; n+ v6 q
  18.       { text: 'Taobao' }+ B! x, E' }( Y4 F
  19.     ]
    ( @' q) ]; U" R7 W5 b% X9 t
  20.   }) J5 U, @' k, v0 L) C- L
  21. }). Z6 Z/ M0 t3 ~+ ~" a
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    * D+ p1 d+ _5 w9 }
  2.   props: {2 j1 q+ F7 @$ L9 f9 R! s* g3 H
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    ) O* O' V- Q, e$ J: e- M- O$ C! V
  4.     propA: Number,
    7 D6 U7 }+ \% T* @: m' Z7 a+ b
  5.     // 多种类型- W3 G9 v7 N: r9 ~$ h
  6.     propB: [String, Number],  b$ d9 y( W" ]4 t& B4 @) J
  7.     // 必传且是字符串$ H: b6 ]1 ?8 h! O2 o; d# d# U
  8.     propC: {
    ' s  P# A: {/ h. ?6 U* B
  9.       type: String,
    & _1 T  B' P7 P9 a: d
  10.       required: true; w% o8 {: V; y! O* Y% v6 a1 [
  11.     },1 `3 N9 z+ E5 [1 L
  12.     // 数字,有默认值
    # s- @8 C2 C# p0 {3 ~' H% ?& J$ C% g
  13.     propD: {* b5 }: W# [: q, A8 H0 T# a9 t% C
  14.       type: Number,
    % C0 ]( h, I! }) w
  15.       default: 100
    9 h% `9 f9 H, r8 h9 K
  16.     },5 T* y- ?3 k% x& V7 p' k
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    9 e3 D  \* d; y9 q, O$ L9 C: a2 _
  18.     propE: {
    6 V8 [9 P5 Q0 a4 V. Y/ u
  19.       type: Object,1 }  d9 y4 a- O- m# y. D
  20.       default: function () {6 i) P) _# t4 \5 U/ G9 y2 j" A9 |
  21.         return { message: 'hello' }
    # t; \3 B1 h5 Q& O1 H% j; U
  22.       }
    + p% b0 _- U& T, c2 F$ H
  23.     },
    0 o) v% d& y% d' f
  24.     // 自定义验证函数
    * ]- l4 n& V) b# S# r& A0 i, f0 U
  25.     propF: {4 |/ ~7 ?) {9 I* x6 D( w, H7 I
  26.       validator: function (value) {
    7 A: d/ I9 Z4 w$ C' J% c% n; Q
  27.         return value > 10$ D% Z4 t# K" L' d* n% I
  28.       }
    1 m3 s5 i; |0 j* G
  29.     }9 y: r0 w8 I$ }
  30.   }4 H" c& x$ y  z- {
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array, ]+ b. j# M5 m+ O: @3 C5 ]
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件" Y+ U4 |( ?3 i) F$ Y- ]6 h# m
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例% y6 H. ]5 b: D3 H" T9 d
  1. <div id="app">
    * z( V' |, W( k' J0 r8 d8 ^# m& F
  2.     <div id="counter-event-example">" @! p9 {# Y7 G; N0 [4 D+ G# H, {
  3.       <p>{{ total }}</p>+ _; p3 V$ L0 c, y! R5 E
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
      X! O  }8 i) r6 D- P" v: y
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>2 M1 V! F6 R) W5 c( A; X
  6.     </div>
    8 i. B6 F4 b/ a# p- T) ^
  7. </div>' y5 _; b1 k, L

  8. & E* r  ]4 C2 v3 ]( N
  9. <script>4 l8 i! }, C, ]" A8 b4 _: T- d! W; h
  10. Vue.component('button-counter', {
    + O5 |! g' b) U1 ^; \4 Z
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',; R) J. a, m  a( J1 m5 a1 I6 B
  12.   data: function () {  q. c/ Y. m& N: p/ l1 V% X( f  z3 [
  13.     return {
    & Q! P# m- {+ [  r/ e
  14.       counter: 0
    7 w% V4 W2 n& O* i" u: ^6 W) u4 n
  15.     }) z- Z# O! y6 U0 n
  16.   },- F# D1 s3 v3 ?$ v
  17.   methods: {  y! a7 G4 t5 g; k$ p
  18.     incrementHandler: function () {: J) |' ^  P- C6 Y
  19.       this.counter += 1* L2 B3 r- W2 d  q* F7 M5 ?
  20.       this.$emit('increment'); O3 e+ G; S  b- b) u
  21.     }1 f" V6 H: k9 y6 c( {
  22.   },
    & ~% D9 M- L. v. y6 H3 |: [, ~
  23. })( h1 J5 r. S. b( [9 z4 K
  24. new Vue({  G4 U/ P& x& P+ X$ j
  25.   el: '#counter-event-example',9 @4 W- u$ p( B, @& U, P
  26.   data: {
    * h5 `3 k. W: @* x1 T) u
  27.     total: 0
    ! R8 s. d) G8 T9 j9 ]$ O3 T
  28.   },
    . G* d9 g4 l2 D- F9 P
  29.   methods: {0 c# ?, U- [8 x
  30.     incrementTotal: function () {
    ' i. u* F; o- b  U) ]8 r
  31.       this.total += 1
    9 @& G5 X3 H3 }  O
  32.     }
    5 [& p1 N% q$ k
  33.   }1 O7 e7 C7 R: a  _( M7 H* V( s( J
  34. })
    : J7 V( d8 a7 |$ U% m
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    * a9 Q% P, U3 `2 _
  2. Vue.component('child', {/ s5 F1 f8 J! c  G' ^
  3.   // 声明 props% H' S8 r& _8 k- ]; i
  4.   props: ['message'],
    4 p) \4 f8 a  E; K$ I
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    7 o+ H% p4 E9 \/ l% K
  6.   template: '<span>{{ message }}</span>'5 q- C9 s  V# B0 F6 _1 N
  7. })" R& F0 I# h3 ]8 V& w. F3 C
  8. // 创建根实例, ~3 u% P3 M- U1 t/ x4 `0 {
  9. new Vue({
    ' D" ^# @! |% T. G9 t9 q: ]- E
  10.   el: '#app',6 g; P: ^. o# ^! c
  11.   data:{, Q. F5 M+ k9 S/ ~  C
  12.     message:"hello",7 r  A' L- @  t: c) p" x1 O
  13.   }+ B$ r' O# J, x2 G) J
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    3 {! t: R, X+ I  s
  2.     incrementHandler: function (v) {
      j$ T5 c; g- ?& n
  3.         if(v==1){
    % ?5 E% n1 a7 N) u* h! A+ w
  4.             this.counter -= 1
    1 p' f' F8 u! R/ e7 u. J6 b( i1 C
  5.             this.$emit('increment',[1]); X4 i8 L' A4 a3 f* V
  6.         }else{3 Y$ A% s7 Q' f' E, x  n
  7.             this.counter += 1
    9 z1 j# q' p2 C* @3 w, @& H
  8.             this.$emit('increment',[2])- ^& x3 o6 a- M+ \: Q1 o  q
  9.         }
    " l" R/ p, \% w, o, A
  10.     }
    . t5 o( K4 b# _+ F/ [
  11. }
复制代码

3 H" k, \$ a, W- y* V9 b8 ~6 x; T/ l# o6 o( j8 p- Z
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-8-4 16:07 , Processed in 0.060100 second(s), 22 queries .

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