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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15215|回复: 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,并使用它:
# r- @1 e' e6 M. t
  1. <div id="app">/ T- |1 O/ i* V$ ^/ p( C6 ^; s
  2.     <runoob></runoob>
    0 V! `6 Q$ @+ h
  3. </div>" Z6 b2 p4 w/ g

  4. * m8 p: v% {! N: v* ]
  5. <script>6 p  c& K4 \* S5 b( q1 m3 O
  6. // 注册$ U* Y- i! _- n5 i- y" h! }0 m
  7. Vue.component('runoob', {
    , ~; g4 ]) f0 k, `+ x+ v# x5 j
  8.   template: '<h1>自定义组件!</h1>'* C. ]/ R% |$ v* N( n4 x! z+ C
  9. })
    * K' {- z- V  e, _5 k6 a9 S/ s$ C
  10. // 创建根实例
    ) Q# i& P% |. _5 p0 D# [+ E3 o
  11. new Vue({, J1 b, ^0 i0 W$ T9 f8 m  A( A
  12.   el: '#app'0 l5 ~; ], ^& N
  13. })
    - s! g# y! O/ P. T/ Q
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
7 k! w- Q4 b, w# t9 b% u3 l5 Y
  1. <div id="app">* d! A4 n/ n1 r+ Z3 F! G( s2 U
  2.     <runoob></runoob>' F/ f' D. n- W1 X9 E/ M$ s3 [; h+ Z
  3. </div>
    ; C3 a& V, l3 ?- O$ p
  4. ' g3 G) F/ ]. G4 k# \8 r
  5. <script>* L! f' G" c" }6 |7 L$ E& q
  6. var Child = {
    2 @5 f# ]- B' w5 K+ `$ e3 e+ w
  7.   template: '<h1>自定义组件!</h1>'  F% _6 o$ U  `$ h7 h7 U3 W
  8. }
    2 l( l+ @6 p' @
  9. 1 p& U7 l9 r4 L: P+ J
  10. // 创建根实例7 j  K2 N( A3 m2 M- u
  11. new Vue({
    $ ~: |* e& d6 @. A
  12.   el: '#app',
    / J3 {' L  Y4 u! X* N& d
  13.   components: {* W) y+ E, W* R0 x( _
  14.     // <runoob> 将只在父模板可用1 }  z! J7 b& I4 D( I
  15.     'runoob': Child5 q9 p. X4 c! F) g4 H
  16.   }
    . i9 C) c# u1 ~
  17. })# `) N& u9 v9 ~# {" _8 S
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
4 `* B4 p+ p* h2 }) n) c4 L
  1. <div id="app">. O7 o& z5 r& M  q
  2.     <child message="hello!"></child>( _& v0 {6 |) h- U$ W: e2 h( W( b
  3. </div>/ n* c4 ~2 y( r. k/ x
  4. 1 f, L2 ?5 N* v7 B+ ?4 T, ]
  5. <script>
    4 m4 A$ z8 \; s1 Z% d0 t) a0 x- C
  6. // 注册
    4 g! L  f- U, M/ Y% R4 z
  7. Vue.component('child', {8 x* Z' g( m: j1 V. }
  8.   // 声明 props
    * ?  G6 J, @& J) v8 k" z
  9.   props: ['message'],
    7 p. Y" D1 v' h9 ^5 p: q
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    - B' U; [5 y7 n4 {0 H
  11.   template: '<span>{{ message }}</span>'
      ?5 X4 i, x. H5 P+ V
  12. })
    # M" K/ a! s: s  Y' K
  13. // 创建根实例
    1 q. v' e* t3 ?
  14. new Vue({- }# D; ~& e3 D& c# G; S
  15.   el: '#app'
    + l; V4 B. X0 K2 B
  16. })2 ^7 P0 l; j+ r: A! P- [1 @
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
' D+ f6 \- B! C$ T# ^& c
  1. <div id="app">' e+ V  `9 ~% E- h9 c" L0 S
  2.     <div>  C1 v8 [  N- |, D* N3 D% s
  3.       <input v-model="parentMsg">0 w6 R' E: t+ y1 h- Y2 t, M
  4.       <br>* k" z6 y( }9 R& i& I
  5.       <child v-bind:message="parentMsg"></child>
    2 O3 ?( f2 I9 P9 h) N2 a
  6.     </div>
    6 z4 O& k6 ]4 P' g4 F+ p/ W8 ?% z8 X" q
  7. </div>
    & R7 j4 V( m# I, b
  8. 4 v# K& i! T9 \! c) i! j
  9. <script>" W+ |" X" m0 ~# }& k
  10. // 注册
    ( _7 l6 F7 _% ?$ _8 j/ Q
  11. Vue.component('child', {  s) l# o, E. V) X1 ^/ i; F
  12.   // 声明 props+ D* Z7 L! b* U  J* A
  13.   props: ['message'],
    5 E3 a6 l, c( E  ^3 _; Q" l: m
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用" E* Z! `9 ^# a2 y, }/ d* ?
  15.   template: '<span>{{ message }}</span>'
    . a7 Q8 q6 b% [. y9 ?* x9 o/ b
  16. })
    5 j" q- w& I7 F! R9 o' Y1 w
  17. // 创建根实例
    5 H# K8 ^* }7 U; T
  18. new Vue({
    2 \* B5 V5 a- |! i. p. x) A. p- r
  19.   el: '#app',* F& Z  ^9 R. e% n/ i! u* q
  20.   data: {
    6 ]# M/ L, X+ ~$ w7 Y' }7 W0 E
  21.     parentMsg: '父组件内容'5 m7 }* r  t7 w' v% b  j- s0 _
  22.   }
    - u6 n7 e+ Z3 u7 [
  23. })" ^: a+ w& k; ?+ ~" }
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例! `" N/ E2 G0 a( j9 ]
  1. <div id="app">( T, K9 C1 n' G; V5 U# v
  2.     <ol># x$ u9 r4 t, U
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    : x% b. I8 J; f" u9 T# O
  4.       </ol>
    4 M5 e* _8 J4 ~8 v
  5. </div>
    % k+ P8 V" P" D, F, W
  6. 6 Y8 |+ V% G: B9 ^
  7. <script>
    / g. m( `5 X# `, H" S9 L' G$ |
  8. Vue.component('todo-item', {
    : r8 S$ U2 x( |! ~: s& K
  9.   props: ['todo'],; j3 {: B3 S& p" \/ X
  10.   template: '<li>{{ todo.text }}</li>'. r/ V! ^: j& ^& g3 `
  11. })
    / o0 `# D' _& W3 f* f! ?# m
  12. new Vue({
    ( g% \' a% I+ S# _: @$ W
  13.   el: '#app',
    $ z9 H- D0 @/ r$ @
  14.   data: {% }3 A# |' J% [- v2 N' I& P1 ^
  15.     sites: [
    $ t5 O; I- a6 e  {- ?7 U+ b1 B
  16.       { text: 'Runoob' },
    1 X$ i) _" s- a& k
  17.       { text: 'Google' },1 y% l/ x6 }0 J4 ?: D4 V  o
  18.       { text: 'Taobao' }
    5 f& U4 c8 g. ~. T
  19.     ]# w* [: u+ H. \6 \
  20.   }
    ( _/ W, G& E  `, }
  21. }); i4 [' A- a; h
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {- l0 s! T3 b. y: |4 K
  2.   props: {
    ; D! ~' P4 S+ t- l
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    / _6 L! j# C! `6 N6 j
  4.     propA: Number," f& n& m: ^. q$ U3 c
  5.     // 多种类型2 K! Q! }6 U3 }4 N
  6.     propB: [String, Number],
    % [6 l+ G9 ?' Q: @8 }6 l
  7.     // 必传且是字符串( T  _7 _6 {5 ?- k
  8.     propC: {0 e, Q$ E6 n! L: w/ X5 W: t
  9.       type: String,
    1 J5 [9 `$ ~6 O# X( h
  10.       required: true* F4 r0 J0 _; i9 }
  11.     },8 }$ ~1 Y, ]( Y% G6 a0 E
  12.     // 数字,有默认值4 V7 i, ~0 Q- R; M; f* G, `& h2 ^5 z
  13.     propD: {' g. r; `9 s, e* }
  14.       type: Number,- ^7 E* t1 ~( y. M
  15.       default: 1004 I$ G- k) B9 E5 n$ F1 o4 e
  16.     },
    2 a! j$ F" q) Z1 ]( R
  17.     // 数组/对象的默认值应当由一个工厂函数返回/ Y, ^3 N6 l' p
  18.     propE: {
    3 v4 G9 x* G. i
  19.       type: Object,
    3 |" Z% n3 e& [. R6 N8 P$ X" }) \
  20.       default: function () {
    1 T* }3 L, ]% o' x5 ?4 H% ^- ~
  21.         return { message: 'hello' }. z0 O6 K6 e/ K8 \0 R
  22.       }. p. ]6 i1 c" [* Y& c" L8 J4 U
  23.     },* ]# }% c- Y  B; |0 C, v' k; y
  24.     // 自定义验证函数
    $ c; N) s, u) i* I# X) u
  25.     propF: {
    % p; n1 x: ], N5 w& {# M
  26.       validator: function (value) {
    , A% T  K& H- ^6 Z- M
  27.         return value > 10
    3 b# Z+ m5 R) W3 K+ A
  28.       }4 g4 S1 ?6 b% D
  29.     }
    ! X8 {+ w% L+ ]; m1 W
  30.   }" O. b2 ~3 X  ~
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    0 j& A; y. R( r' M/ d5 F
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    & ]# d# E; H" t8 F0 ~* ?- p$ T9 X9 k
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
: a5 k( |0 M+ E
  1. <div id="app">
    " T* ^3 j; S- {- l5 {' u+ h8 t
  2.     <div id="counter-event-example">& }/ k5 i0 K; t) T
  3.       <p>{{ total }}</p>, _3 E+ I& t) L! C0 [9 T
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    9 J: W+ I. e  M3 f
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    ( X5 h0 J4 Q. ?0 W$ i
  6.     </div>
    & z" D# d. M+ k$ a8 H7 {
  7. </div>0 }4 R/ M4 w1 t& [% H; o- n

  8. 8 n: B% `6 O1 \! A& T( b
  9. <script>4 d# |! t: ~5 i; [2 S9 F
  10. Vue.component('button-counter', {
    ! J3 _8 F0 s$ g. w, L3 ?
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',0 L* q' Q$ v7 s8 q& a$ v
  12.   data: function () {! w! u' T3 L( C# Z# I9 t
  13.     return {& q9 w+ M, O% O! u8 s' B% O
  14.       counter: 0: ^; P3 V- S5 b4 u' B4 a
  15.     }. L7 _! H# t0 A, P, z6 I
  16.   },9 T4 e* D$ z3 c, J. D# g) n
  17.   methods: {
    / u: l- o3 x6 n' ?0 k8 a
  18.     incrementHandler: function () {5 h& a/ U, T  N4 F& F
  19.       this.counter += 1
    5 Q" j8 d7 D& {& S
  20.       this.$emit('increment')
    ! i' C# M( j' k  {6 W& ]  I
  21.     }; n, O+ D. H; `$ T
  22.   },
    - Z( v/ ?! T& O5 [9 w% j
  23. })
    0 K: g/ y& ~- |3 f8 D; P" J+ _
  24. new Vue({
    ) K, {( A& v' a5 Q
  25.   el: '#counter-event-example',( z- ~9 R7 \8 L: F$ |- R1 d3 a5 R
  26.   data: {" k3 e9 t5 r  E* F
  27.     total: 0
    4 J" M  X9 z/ w7 T
  28.   },2 D* m, @/ S" p& `0 C3 h
  29.   methods: {
    " v- `6 [+ K5 C, j
  30.     incrementTotal: function () {, `% G; J# Z6 E! Z) D, h0 z1 k7 r
  31.       this.total += 1
    7 x3 c+ g6 b& T) V6 [
  32.     }
    5 C, _# C: x4 Q9 F
  33.   }$ ]$ j5 t$ G. h# D
  34. })# U+ D; @  `4 c, ]/ _
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册* H. |2 [) @$ J- [% {4 p
  2. Vue.component('child', {9 G0 x( ]" _6 e0 f/ o: k
  3.   // 声明 props# v" Y% [" W+ }
  4.   props: ['message'],
    + A3 \, O$ F$ K
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    6 o# [7 W- d! o$ T3 }- L9 O
  6.   template: '<span>{{ message }}</span>'
    8 }( j- e* B3 v8 q! N# c: c- r+ R
  7. })0 p" f. j/ O7 U+ Q  ~$ l+ ]+ l
  8. // 创建根实例! X" n# n, C) p# @
  9. new Vue({) _5 \2 s9 b( d( \& B$ U
  10.   el: '#app',
      W+ F) R' Y/ V5 n
  11.   data:{2 s+ }. I- ^+ Y/ h2 h: a9 m" T
  12.     message:"hello",
    " z1 X9 F9 I: v* a# ]) [8 g: A
  13.   }
    3 j3 m( I/ T! ?1 V9 h; p
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {) k* x5 m" e3 `! x( w
  2.     incrementHandler: function (v) {
    4 {; w7 o2 p4 [+ L6 @% C3 K, I5 I" w
  3.         if(v==1){8 a) F- d2 ^( k
  4.             this.counter -= 13 c, j# Z! u* n/ q
  5.             this.$emit('increment',[1])
    ) K9 L  G0 a( f/ x2 }
  6.         }else{8 W. l  v" h$ B7 R' h" K3 i" ]" e% ~  T
  7.             this.counter += 1
    % }0 V8 p5 o  V: Q3 b0 J, H! @2 m
  8.             this.$emit('increment',[2])
    4 j1 G4 y' e) \. m2 T4 \
  9.         }
    , Y  ~, U7 _0 Y/ @, z$ y! M3 I9 {
  10.     }
    4 `0 e8 v: I/ }1 F2 X6 G0 y' |
  11. }
复制代码
9 Y: v) ^$ f2 u

6 b9 T* B4 h" p" f
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 16:45 , Processed in 0.059512 second(s), 23 queries .

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