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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15348|回复: 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,并使用它:
3 Y$ t3 Z. X" u! v( j' L) d
  1. <div id="app">
    0 y3 C" y* b2 y4 g
  2.     <runoob></runoob>
    9 W/ ?  v9 F  e) v) {+ i9 N" v; P
  3. </div>$ A4 G0 @. z0 k7 ]1 W/ o/ q4 g

  4. 4 q! J! x5 A! ], i
  5. <script>& N- [# o$ k7 w& B! N, R$ r) @
  6. // 注册  g2 ~6 j, ?2 ?( a! C  f
  7. Vue.component('runoob', {
    4 |. _+ {/ K* o) v  C
  8.   template: '<h1>自定义组件!</h1>') e1 j3 s* {- {2 P% g% l- {; L
  9. })
    6 F. ]2 d& @8 h7 V; `' r# N" ?
  10. // 创建根实例& x  `# D6 I" s3 z$ {! M. K# {, H# h/ ?
  11. new Vue({
    7 R8 O% u' ~5 x& B0 @$ W" |
  12.   el: '#app'
    5 w; a7 D) }7 k: t+ s$ a
  13. })
      k/ k  M) @3 u! f$ r
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
3 r- Z8 r2 u* M& c
  1. <div id="app">
    , b  [+ B. [! P$ I
  2.     <runoob></runoob>
    1 p( K% F2 O8 u& [6 z9 z( V% C
  3. </div>0 X( Z, q' ^0 }( S

  4. 5 Y, }- Z7 }/ `* H+ y1 \' m! x
  5. <script>
    ) S" j% {! a* y% V) o
  6. var Child = {
    7 I! G& O; `  K% ?
  7.   template: '<h1>自定义组件!</h1>'
    ! F) |3 P  v# f, ^/ J
  8. }* z) M2 K: z  L0 h* q5 w
  9. " ^! o2 _2 Z) o3 y) K- d  o4 t" |
  10. // 创建根实例* p# q' X" l$ c8 I  y
  11. new Vue({
    ) {2 f9 d1 {6 C$ N7 r* h: R
  12.   el: '#app',
    ) C" U- u" Y# @3 p
  13.   components: {
    0 F/ P, m# V5 c* r" M
  14.     // <runoob> 将只在父模板可用' }! f8 W0 u, D2 q9 C* {
  15.     'runoob': Child! _6 _4 [: F3 F) G# {& r/ ]4 ?
  16.   }* U% _* `; T1 ~
  17. })
    ) j, |! P% Y5 V* `% ~! ^
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例0 B* ]. W$ R. u* \) C# J
  1. <div id="app">; @6 ^0 }; ]! r* l9 Q
  2.     <child message="hello!"></child>! S" J' ~+ B/ ^3 X: z
  3. </div>
    8 T9 M. X& e, e6 q' m+ n

  4. & @' v) O" E0 |% P/ D
  5. <script>
    ! A/ y) U$ J% X0 ^! _
  6. // 注册
    ; B2 B) ^, i1 J  Q
  7. Vue.component('child', {1 M" C2 K/ ?* X, @
  8.   // 声明 props
    3 R4 F% ]. a" B5 E3 v
  9.   props: ['message'],/ }' t! m9 G* `7 d  c0 i2 [
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用6 ?  ]* [0 a/ u+ o  k& }
  11.   template: '<span>{{ message }}</span>'5 W7 P) f" U3 o( ]$ |+ q8 [! H2 p0 i
  12. })
    ; F- z  [( X) ^  I5 A
  13. // 创建根实例
    7 b! U, [- f5 s4 p4 Z4 \# Z4 n
  14. new Vue({; B! j+ ^( E: V1 R1 K7 @
  15.   el: '#app'
      D; W, \; S7 w8 V6 ?6 `/ L6 [
  16. })
    9 ?/ F4 L; ^! z8 n: [7 h
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
4 y6 h, u# c* X! t& n9 T5 E
  1. <div id="app">6 l& V2 E4 x! e1 o  U
  2.     <div>/ G& W. I% @3 ?" z
  3.       <input v-model="parentMsg">( r! B( z# s( u( }4 m( K
  4.       <br>+ ~+ e2 l7 [/ q$ I; s3 z6 T
  5.       <child v-bind:message="parentMsg"></child>) {; q  D5 x; ]* Z( Y
  6.     </div>
    5 ^7 O' W6 D9 D4 Q9 ^" g7 ?9 b2 ~
  7. </div>+ y% w# s+ A  n" O

  8. 3 u3 ~  M" }9 T
  9. <script>9 \6 |: [1 J6 p# k3 n% D7 \& s
  10. // 注册
    2 ?2 a6 L! w7 h' O1 x. h8 `' _4 v$ f
  11. Vue.component('child', {; e; S! Y: t- s& I! ~+ ^. a) K
  12.   // 声明 props( `; E  }! c& ?
  13.   props: ['message'],
    & i6 y; D0 Q% j' q  C. a
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用8 F; R+ ^4 J( {0 X7 H3 Z! ^6 b
  15.   template: '<span>{{ message }}</span>'
    3 L7 O# @8 r' b. ]% W" z6 z
  16. })
    0 E& Z/ s& c$ O# c3 O
  17. // 创建根实例/ }7 S+ g; u, I* Y- @4 q/ _9 J
  18. new Vue({( F. M0 ?5 }; T$ W  t
  19.   el: '#app',% {1 K- V' g: B3 \: V/ {0 d1 L
  20.   data: {+ n  M! J$ U: n) n
  21.     parentMsg: '父组件内容'
    3 g) k0 t% v5 m. W( r+ E  P$ @3 {
  22.   }$ t+ x; Q% ]' G* K/ W- p
  23. })7 _. m$ v) l2 c0 s+ j* Y
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
) S  a, _4 q" A5 c0 `9 h+ {
  1. <div id="app">
    5 e; o/ @6 S$ l1 j2 ~
  2.     <ol>
    . ]- l% m: q1 j, V" \( u, {; @! D
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>8 a: V2 X% W. U6 W9 y+ R
  4.       </ol>
    4 @& p) L  n* u' S$ W: n3 X! n
  5. </div>- e% n: V3 @$ N8 p# I. _5 D7 l% ]: Q

  6. 5 ?' N5 }( l0 ~! Z, [
  7. <script>& l" s/ I8 i" R! z: N
  8. Vue.component('todo-item', {2 g: c( z. }% R$ r0 C
  9.   props: ['todo'],9 f4 b1 J( U6 q# F; H1 L
  10.   template: '<li>{{ todo.text }}</li>'
    3 B  S' ^7 {) ^- ~: \
  11. })
    7 X5 p6 q7 d: `7 s# ~' ?7 r, }
  12. new Vue({
    4 m( a+ F* U5 g) P7 X6 q( f$ \+ R+ X
  13.   el: '#app',+ m& L! ^/ Z, _% }
  14.   data: {
    8 u4 D8 W! c( g# L
  15.     sites: [. J; v, N, b# l2 D; P
  16.       { text: 'Runoob' },, W0 `1 }+ P. M
  17.       { text: 'Google' },
    ( r5 ~7 k; f7 K# j
  18.       { text: 'Taobao' }
    & C% t  m  `! Q
  19.     ]
    3 U" L. _5 n- X9 R1 |
  20.   }6 q; {* K/ _% ~9 K% j" V
  21. })
    . _1 y7 S" y5 d) ]. P. S: A6 d
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {- t# T% E& x  d6 x7 m9 b' W7 E  a% ^
  2.   props: {+ e4 q4 R  `, e& O0 m6 O( h
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    ) N* E+ [& O3 f8 ?: g. c, b
  4.     propA: Number,3 n+ ?7 o; E# R% n
  5.     // 多种类型# N7 A3 X( P! P* e* {& l& `
  6.     propB: [String, Number],
    $ s/ h5 o  ^8 _, A, i
  7.     // 必传且是字符串
    6 Z; A% G/ x% A
  8.     propC: {+ B- J+ a# J  R1 K
  9.       type: String,
    0 {, B7 p+ G) ?4 s
  10.       required: true3 |9 ]5 N* ^! I" e. b
  11.     },
    ) |4 X+ @& l+ x( ]4 p
  12.     // 数字,有默认值
    # A$ l# o! V# X  q
  13.     propD: {
    4 h9 h4 e$ x1 _: n- n
  14.       type: Number,
    ' `; u2 ?) V; `8 ^' |
  15.       default: 100" j! R9 w6 Z/ g" B' m) r3 u3 A% |
  16.     },8 L$ ]& p% i# I9 Y
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    & q" L* H9 {5 ~" ^. b% i1 \
  18.     propE: {; U# ~- F4 R' G6 O# g
  19.       type: Object,
    - _% N- X! K! x
  20.       default: function () {! f# [- q$ r0 ^* I
  21.         return { message: 'hello' }
    - h& }# e2 j& E$ ]
  22.       }! R3 C& \% K2 f
  23.     },2 M; e5 p2 Y! R5 f  ^; R
  24.     // 自定义验证函数' P8 F) O9 \1 T4 |" V; V3 e3 U: i4 {
  25.     propF: {
    : _$ X) ~" k+ Q& z8 N4 V( J
  26.       validator: function (value) {! C" O  M) b8 [4 Z5 ^5 Z1 D- h
  27.         return value > 10
    # S7 z0 L$ D6 Q& Q2 i
  28.       }* E9 y& l- c  h6 d5 R
  29.     }
    ( d/ d* G5 g1 m) K! ?1 `
  30.   }5 r; P* h- L$ |+ e
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array, j  S4 ~* l/ m. a7 u0 r
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件8 |$ ~5 c& j( P& i4 g, d- R
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
/ u0 s' o; l. x
  1. <div id="app">
    ' z. Z( u+ T6 M( U: h4 S: U
  2.     <div id="counter-event-example">
    ) ]4 U& U, s+ u  O
  3.       <p>{{ total }}</p>
    * v; z: A, Q. `* P+ l# R" d
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>8 m5 A# s: [$ c" z
  5.       <button-counter v-on:increment="incrementTotal"></button-counter># F" q# o! \- b3 M* U, H
  6.     </div>
    ! H2 [* o/ {# n% C: X6 D  O! B+ @; u5 I
  7. </div>
    4 Z7 h6 o8 r- _8 k  ?" s1 F8 ?1 M

  8. 2 g+ w! o& `+ f
  9. <script>
    * w5 P4 T. `4 ~5 k) A7 N  I! m
  10. Vue.component('button-counter', {8 g8 t3 _+ X9 E0 K- L2 b6 C
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    6 L) L4 R3 @3 s
  12.   data: function () {0 U8 w. G0 w, S, M/ C: Q
  13.     return {* x5 S* J% d# |5 X& r7 X
  14.       counter: 00 M* y% G# {% p2 |+ j4 B* K5 ~/ t, N
  15.     }; I7 ^$ C1 c/ A6 I3 `  w
  16.   },) Z1 t3 n7 P5 t0 @2 K4 ^+ J# @
  17.   methods: {
    5 ^; r' ^7 U/ [1 C4 N$ G
  18.     incrementHandler: function () {  r8 J7 X- F- J* X$ |5 N
  19.       this.counter += 1: B1 R9 l2 H. y, ?! A. O0 _
  20.       this.$emit('increment')* C, k5 E7 m  W  F
  21.     }' l! k5 q7 m: |, t/ A, v, K
  22.   },
    . o) ~" X! Y4 O' U9 j/ c* o
  23. })' T+ `6 a* O. v
  24. new Vue({
    # v# y8 H( k6 L7 Q$ p
  25.   el: '#counter-event-example',
    - e1 R$ A% N1 K  b
  26.   data: {
    , S$ Z+ H( r6 |) R0 o( i
  27.     total: 0% x# ^/ e& [$ N& S3 N8 x! z
  28.   },
    ( y8 m5 w0 r0 y, `; w4 b0 h
  29.   methods: {
    : v, b7 h+ m, w3 h! z* ~" h6 H5 w( {' p
  30.     incrementTotal: function () {
    4 A3 R" D7 a/ |8 v
  31.       this.total += 1; m  M$ c  D* @+ ^
  32.     }
    $ V5 @5 F( J+ B9 O
  33.   }
      I& m; i; l0 K6 y, [7 t- Q
  34. })
    , ^( k, f8 x9 U4 V2 }4 }
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册2 M0 i' Z# }3 @; k" y. }7 N  J: p
  2. Vue.component('child', {
    " P2 {4 d- n7 i7 v+ u1 w
  3.   // 声明 props
    9 f/ G1 V, w: K$ p! C7 @0 H
  4.   props: ['message'],
    ' G+ I5 n9 B9 o0 x* K! M" _! S
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用3 U% M( Y" Q4 Y. b$ g3 L
  6.   template: '<span>{{ message }}</span>', J  c5 Y' H; i. ~. Q
  7. })
    : k8 F+ s4 H, y% B. l. [
  8. // 创建根实例
    0 F( ~; J( x, o( W* A4 ]
  9. new Vue({
    9 f/ `$ q2 R8 [' z8 D
  10.   el: '#app',' t5 ^: \& N+ F" T
  11.   data:{
      c1 Q+ p9 X/ ?/ y& b( ?* H8 [# t  s* `. }
  12.     message:"hello",
    / I6 |4 u6 i: Y4 q. ~1 M, G( g
  13.   }
    * Y3 q! B  v4 {) i
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    ; H/ ^# j6 d* B7 R7 F
  2.     incrementHandler: function (v) {" G2 O. f( B% F8 G$ b) Z. `
  3.         if(v==1){
    . N1 `3 I) ?. E+ _; {( Z2 y( @
  4.             this.counter -= 1
    6 w9 J* L& m2 J. z5 ~5 n) B/ n/ Y
  5.             this.$emit('increment',[1])
    8 c+ l, o  ^: U, m' f* I
  6.         }else{6 o  Z" ]: _& [; y
  7.             this.counter += 1/ c+ g. i. b0 P- L  q  S
  8.             this.$emit('increment',[2])
    3 K8 C2 K, V0 U1 f) E: t) |9 f
  9.         }
    * |1 f5 c8 K0 K/ q  n5 R: T+ u
  10.     }
    , q- X) [; v. D' N" ^! W6 @3 U, b
  11. }
复制代码
5 N+ v0 V. U+ [+ m. \

% c4 E) J3 d8 C+ R9 q
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-16 17:23 , Processed in 0.059252 second(s), 24 queries .

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