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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

& M# u" U' i9 }4 }1 J0 X
  1. <div id="app">
    $ v2 q; o1 ^* }1 A
  2.     <runoob></runoob>1 h$ _2 E4 x; D! y3 k0 m8 n4 n
  3. </div>! A! `* i: v/ S9 d8 P" ]' d

  4. * j# o9 i7 g0 u0 z( m; P* K' X
  5. <script>
    " I- J' |: q. }
  6. // 注册
    6 u( `* x% \8 b) E; Q/ v
  7. Vue.component('runoob', {7 k8 a% _" y6 W; ~/ R
  8.   template: '<h1>自定义组件!</h1>'
    2 ^4 s5 D+ S5 w7 u: B( a
  9. })- x3 ~$ w9 C  E; T
  10. // 创建根实例' ?9 d% r* J' ~0 X, r3 z
  11. new Vue({
    : F) F" N6 m* ]" r
  12.   el: '#app'
    / u# |: p' f. y9 x! I' Y* q
  13. })
    . e4 y0 I  r( `( L: S
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
9 H. C" M: A) ?' I- [# V
  1. <div id="app">* t7 }. }6 r; ?/ m4 J7 q
  2.     <runoob></runoob>2 g( x. q, m1 v# ]  p9 W0 q5 y1 ^
  3. </div>
    / T3 X' J# Y& M% _
  4. ' q" w' f8 {8 {
  5. <script>
    * W9 H2 y- t% v/ y7 {
  6. var Child = {8 P) N0 O/ p6 v' x" N+ Q/ h! u
  7.   template: '<h1>自定义组件!</h1>'2 b9 A# H! K+ I$ U9 f# t7 q( x' a
  8. }
    ! X  _% {1 W+ z/ r: s) S
  9. 3 A' N7 x" w8 v% g; z
  10. // 创建根实例
    2 v3 k! t, g4 C$ z' w5 P  ]$ ]
  11. new Vue({
    ) ~& P: w1 Q, m! h7 s% q" [, c  q
  12.   el: '#app',
    . H0 r) N0 `& G8 t
  13.   components: {
    ! Q9 f% U$ ?5 m0 r9 ?% z
  14.     // <runoob> 将只在父模板可用
    3 r6 X% ~/ U4 \2 x, a" ~
  15.     'runoob': Child8 B# l& t5 \& v/ Q
  16.   }* N3 Z/ F/ P+ `  G9 ]9 I
  17. })
    & U) {0 t9 R  k$ Q1 L3 K
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例3 X, Y- M/ {2 |- x2 W7 K0 M# {
  1. <div id="app">/ o  m+ |3 _/ L4 X/ A2 Y/ n
  2.     <child message="hello!"></child>2 D( v7 ]; I5 x7 o' D* _
  3. </div># q# k6 f$ G- I7 O

  4. ) a; w2 |' `3 V; f" P, O: |$ N
  5. <script>
    - N7 J: a* L5 J3 V  e, E
  6. // 注册
    + w  d1 [! p2 Z$ q
  7. Vue.component('child', {
      d) }' q4 i# T/ W# U
  8.   // 声明 props
    ; S% B( i3 o# u4 n; ?
  9.   props: ['message'],
    & Y$ W1 M4 N& \  m* U8 a* u
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用/ k# J8 H9 x: g+ r; P8 C! P
  11.   template: '<span>{{ message }}</span>'% P7 U1 S% x* {: Q" I
  12. })
    5 H9 l( X7 k: e7 Y
  13. // 创建根实例0 T2 W- s9 S) p, J8 U$ f% t+ ~
  14. new Vue({
    ( u* T9 M# P7 Z, w* i6 A- _0 S6 m* E+ Y
  15.   el: '#app'
    ( [" `* i: n  o& v! [0 W% Q$ g
  16. })
    $ P1 F' p' z, L3 q0 z2 I
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例$ F; m/ h7 a% U9 Z3 W8 Y
  1. <div id="app">* c& t0 ]. A0 \: l. c
  2.     <div>7 ~5 @4 s2 v$ F0 l
  3.       <input v-model="parentMsg">
    ! L" F, }% z5 g8 O4 Q
  4.       <br>  `5 V$ j; t1 C0 A* q: \' J5 g6 x
  5.       <child v-bind:message="parentMsg"></child>. u: Y8 r8 ~& `5 I0 D& `7 G) V+ r
  6.     </div>
    9 E6 V  R1 d$ E2 i7 V- b
  7. </div>6 x/ `8 c4 c  _
  8. & b4 a# [4 ]" g9 k' i, L
  9. <script>7 H5 Z* N7 r5 q; d
  10. // 注册0 t1 V9 k# R" @5 X6 O
  11. Vue.component('child', {
    ) N6 D0 ?; H) t8 K& q7 Y
  12.   // 声明 props- T/ i% D" m3 g$ A2 q
  13.   props: ['message'],) s  Q& l1 f( S8 T
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ; z8 A$ N; F' M# S1 D7 n
  15.   template: '<span>{{ message }}</span>'
    1 P! V4 P' V& v) ?3 `2 X
  16. })7 a' G' T# w2 `! l3 ~2 D& Z  q
  17. // 创建根实例! R; l+ U  Z, n9 y
  18. new Vue({! d& a% X: w% F2 P1 R  |/ e' h
  19.   el: '#app',- k" U* `5 x2 p" A8 J0 q7 u
  20.   data: {4 [- _3 x  p8 `) j3 p
  21.     parentMsg: '父组件内容'
    / t: l' m8 u8 ?# I# |+ m5 u+ q" E
  22.   }
    % f9 @& F$ W! S) ]: Z/ y
  23. })+ w/ t! z) Y+ E) d- f: H$ w, M5 ^7 Y# Q: c
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
* Q% i; |" k/ w2 U
  1. <div id="app">  ]: j5 t2 z' Z% i
  2.     <ol>% i0 M& |2 y# S- J- M" @
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    & C8 I2 n% H) p8 x' {
  4.       </ol>: i0 J9 ^/ a* l4 M7 B& U# v
  5. </div>/ |9 L1 \  M7 c. f5 j

  6. * P* d6 a) A* d
  7. <script>
    " h+ S. O. b- E9 U2 v& |. v
  8. Vue.component('todo-item', {6 g, Q) q; B) v% x4 x- V( A( Y5 J
  9.   props: ['todo'],
    ! l2 ~' p. H! X; ]) Y
  10.   template: '<li>{{ todo.text }}</li>'
    3 h; f+ C6 L. C
  11. })
    ; c3 f& m: g$ x7 S( F/ C% _; P; ?
  12. new Vue({
    . }. p9 L2 V" I7 D
  13.   el: '#app',2 q5 p0 X* N1 O- m
  14.   data: {
    6 Z3 k/ k6 J+ t& o# U( C0 j
  15.     sites: [3 ?. X. H! s% H* \3 r
  16.       { text: 'Runoob' },
    6 q: @0 F9 x& c% W
  17.       { text: 'Google' },2 V: t% ?7 o, Z* p/ P
  18.       { text: 'Taobao' }' I5 }- j& }- N4 s8 j* J/ ^* a
  19.     ]9 e0 \; D% Z6 I
  20.   }
    $ M: p  f* G5 G
  21. })- W) ~5 E  F# K$ L$ i( `; u# N
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {0 ^3 m* a# g$ I  J4 k5 W! L' t" V
  2.   props: {6 Q: `+ v+ C6 I& U0 a, J4 o
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    . \9 F: h7 Q# U8 F" o6 ]
  4.     propA: Number,1 S& g- N+ D+ v7 ^: ?
  5.     // 多种类型
    ; R1 c% s1 h; A$ ]* j* }" O
  6.     propB: [String, Number],
    5 Z, Q0 i+ H, F+ v6 f* P; e
  7.     // 必传且是字符串
      ]  X" f* x' Z7 C
  8.     propC: {6 r7 s5 {; @* i; Y8 E
  9.       type: String,- H  x6 T- `# `4 s" x1 J! q4 s
  10.       required: true
    ; G" Y+ z; V2 w! A7 F8 ^
  11.     }," k( i; S( n3 f& ^
  12.     // 数字,有默认值- A) j" D( U0 P/ w: W
  13.     propD: {
    ; ]; A8 |) S: s- `4 `8 c, J  B
  14.       type: Number,
    / Q8 k. X; l* q1 C9 H; j
  15.       default: 100: e' G1 {  j& _6 e5 W5 {
  16.     },
    ! R% @% A% ?7 [. h, A0 M
  17.     // 数组/对象的默认值应当由一个工厂函数返回6 u; T' i. d, }5 p' c
  18.     propE: {/ J* c+ G( G. U# d9 ?4 T
  19.       type: Object,1 \# {( u2 l6 c/ z
  20.       default: function () {
    / B6 H: \9 T! D8 R" Q
  21.         return { message: 'hello' }
    3 j8 P# K7 V5 D+ b9 L
  22.       }/ B3 I" o6 Q9 g( M  `% M( @
  23.     },
    5 K9 Z: V0 ^( v& |$ S3 l- g
  24.     // 自定义验证函数
    8 Y5 ~5 @$ V+ M' ~8 b/ z6 b/ }
  25.     propF: {
    & {# s4 l3 O9 ^$ J# a& a
  26.       validator: function (value) {
    ' ~% d' _( \9 e/ b7 O& T
  27.         return value > 10
    1 O4 K5 k# t2 `3 p. F! Y4 u9 A' f) l7 C$ o
  28.       }% I4 m* s# a9 j. ^
  29.     }: g( I1 z  a2 W! ?% T+ E
  30.   }
    6 ~1 Z" U- B5 ?; |0 y
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array: s1 E5 U; i0 p# J+ ^# L6 }
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    ( u( S  M6 X6 r
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例2 J1 w2 [3 S9 e/ z' w% E
  1. <div id="app">7 j$ E  ?5 ]$ t* ]8 k- n/ `
  2.     <div id="counter-event-example">5 w! N" |! c1 z
  3.       <p>{{ total }}</p>( t% m8 i0 c* R, F* J, }# u8 q
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>% ~% W% }$ Q) v* W  v$ C- H8 @, ?$ G
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    7 R$ \$ o$ \6 ]- _6 H2 W
  6.     </div>6 h. n: j$ X" J- Z, X
  7. </div>
    ) q" b9 j( P1 d% A1 @! R# `

  8. + v; E; u2 b5 ~4 ~) S4 z/ }
  9. <script>6 ^: i- H9 X4 R8 F* n
  10. Vue.component('button-counter', {
    6 A8 n) ~' C" ]9 b9 |) d, z- {6 I
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    . R7 U. G# K# a* ~, ~' }
  12.   data: function () {
    + G  H5 I1 l+ p/ N( V  |. X/ ?5 f
  13.     return {
    . K/ _: b9 V1 B. G5 B5 a
  14.       counter: 09 n# e6 X3 ~; o/ v
  15.     }
    $ D+ z/ F$ E1 k' a, X
  16.   },9 F# b! v5 w" t) v. ~0 j2 A
  17.   methods: {
    , H  q* h, N/ L8 [. f: q% E
  18.     incrementHandler: function () {
    * P+ q/ T# p- ], ?" K3 x. j/ K
  19.       this.counter += 1
    - ~4 l) T- G, p) \2 E2 E7 n
  20.       this.$emit('increment')# C) q' d. N( x, A1 e) P! _2 U& c. G
  21.     }+ y  [& u0 U0 c/ w6 m+ u
  22.   },
    + P& {7 x0 R/ G- x, G: S
  23. })8 h% U) W/ N2 t0 g" k; @$ t- K9 E
  24. new Vue({, W- i2 T6 u: ?$ h
  25.   el: '#counter-event-example',# {- Z: R' |" ^, x; D
  26.   data: {: V: |7 @" z4 {1 p
  27.     total: 0/ y1 o1 y$ k* e* G% z$ ^! H; Q
  28.   },5 B8 F8 ~$ i: \3 K. e0 p! }
  29.   methods: {! d1 C- H* z) h. C! |: J, |2 g6 p
  30.     incrementTotal: function () {. D/ _6 l/ L5 W# \1 q6 L" Z& w
  31.       this.total += 1/ N- |- @: s+ P# b& }$ ~, L
  32.     }
    ; k% `6 I. k  |& t7 P% {1 U8 w
  33.   }. C* N, k# S  ~# O
  34. })+ w+ C5 o& o0 b6 C
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    . n: D% G, Z8 y# ?
  2. Vue.component('child', {
    ; P- Q9 l4 w5 T" `4 D' L& d' {
  3.   // 声明 props
    " a% {$ a6 Q% [# o2 y5 s
  4.   props: ['message'],
    5 x- n) ]7 v. o; z9 N- F' v' Q/ T9 ~
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用( P0 m5 b/ B+ J9 Z. `+ T
  6.   template: '<span>{{ message }}</span>'. w2 m. a. Y$ g; B& d. u) M
  7. })
    + s! Z; Q  _; e* V3 V+ o
  8. // 创建根实例
    9 `2 @. [/ C  _1 c7 v# k1 ^7 C
  9. new Vue({) w  x* \7 i/ h0 R8 u
  10.   el: '#app',/ B9 ]9 x2 P& Y( q0 e. T
  11.   data:{
    3 L7 G/ r, I. X3 V
  12.     message:"hello",
    0 N! o2 d# u6 o. ]9 h; E, L
  13.   }
    2 J9 `+ G3 e8 F7 h# g
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {9 D: G0 }) I& p  w
  2.     incrementHandler: function (v) {+ c6 K. ~; P' O" p: V% m
  3.         if(v==1){$ z, w& f+ q! T( @. q
  4.             this.counter -= 13 \- I+ p  O" Y
  5.             this.$emit('increment',[1])3 N7 z& a0 I( F2 `2 L2 E
  6.         }else{
    % F, l, ~4 n+ t
  7.             this.counter += 1
    2 O0 j6 C) E" J" ^% u% X
  8.             this.$emit('increment',[2])
    2 f" ?& t* r1 E* ?: W1 |. T2 X, K& {
  9.         }
      N) v) `$ ?. E0 T
  10.     }
    ' U$ K3 h8 M& j' \
  11. }
复制代码

5 P9 x/ u# t+ M  y' X% @4 v' z; G' C9 |( X( _, ?
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 14:28 , Processed in 0.052858 second(s), 23 queries .

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