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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15651|回复: 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,并使用它:
$ z+ D- l( l: w0 O) d6 F+ e" G
  1. <div id="app">
    7 @( X& _2 c6 x& \4 O8 ~
  2.     <runoob></runoob>$ T1 c/ m( k% P* [+ C/ T
  3. </div>, Z4 ?, I9 W! ]& H. ]( A
  4. ( `) B5 V) M- {6 X3 b
  5. <script>$ w  z- V; k4 C& V& l4 {. q
  6. // 注册) P% Z2 Z" G1 P3 Y/ `; y9 n
  7. Vue.component('runoob', {1 S6 I' X2 o6 P" Z4 o' F0 j) H
  8.   template: '<h1>自定义组件!</h1>'
    ; s/ g5 n  ~9 o0 [, R3 _
  9. })
    - V8 @8 E6 w# ~% c
  10. // 创建根实例8 o7 R* t0 Y1 F. B  d# R* Q
  11. new Vue({
    / V, k! q) I7 v. D0 X/ J9 r; m% ~
  12.   el: '#app'
    ' y+ L8 N* ^. U; ]" r6 ~
  13. }), y* l9 ^! y( F# T- X
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

) z* c5 b1 n! C
  1. <div id="app">9 @: c! }  e! K/ K4 C: d
  2.     <runoob></runoob>
    6 R" o0 P0 v+ o" E: u5 ]% }
  3. </div>
    # c) [: |& R0 q) R  d3 l& T
  4. : K8 F5 u" P; m4 Q! M( l
  5. <script>4 g( d, ]0 Z7 V& e
  6. var Child = {/ m' ^8 [+ Q+ O& |
  7.   template: '<h1>自定义组件!</h1>'6 g# {( p2 N( l& ~9 Z3 `
  8. }
    $ Z: o) {; i9 K+ @" ^* G& M: U
  9. , ]% d. M: |& R! E9 O9 d" [
  10. // 创建根实例
      h! [* ~; f" v  d4 h4 [; W3 ]! T
  11. new Vue({
    ( c, s1 d' F  R
  12.   el: '#app',
    1 z9 ^  V: H1 L. v2 p8 s
  13.   components: {7 a. y- Y# U) v! l0 \! O
  14.     // <runoob> 将只在父模板可用! M% _0 I& ?. W. Y
  15.     'runoob': Child
    5 o. M8 c( }1 ^+ c/ r  S! b* N
  16.   }
    6 b! ^$ y9 I4 G" n6 h
  17. })" ^- g: o' ^. L' j
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例/ g0 C7 u% T$ I) }
  1. <div id="app">; h  [: ~+ y  @9 G0 t
  2.     <child message="hello!"></child>
    . q! j3 T3 g" q  t  d' C
  3. </div>
    ( I% Y  m. R7 M3 u" P8 n+ [" P+ V2 u
  4. 8 Y! h/ E1 Q3 ^( Q" Z. o/ K
  5. <script>: a  d; E+ T/ |! M
  6. // 注册
    2 S7 ~2 X! N0 E1 d
  7. Vue.component('child', {" a7 O4 [2 f9 P* y+ m' \* L! v" N
  8.   // 声明 props
    ! j3 D+ W1 H  h8 |2 l/ L
  9.   props: ['message'],
    $ D* T3 H! V  k! K
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用4 C# ^: `8 B+ T; O8 k
  11.   template: '<span>{{ message }}</span>'
    $ [# h. y0 E# ]
  12. })# V9 t+ @. X. T6 ^* t; M
  13. // 创建根实例; r. r* ]& a: T' B( z( O5 b0 p! O
  14. new Vue({( u5 f$ T) v# H5 A) |  e5 C; {& r
  15.   el: '#app'+ I* u& w/ |  H; _3 M* z
  16. })  o9 N9 ?0 n& y' D# h
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
/ O) ]! X% n  j$ D
  1. <div id="app">
    ' r) g  k' F6 d. i1 z& q
  2.     <div>( [' U, D" c7 u5 E( U+ e
  3.       <input v-model="parentMsg">
    # x; I( J& |- @+ R' Z: f3 [  _
  4.       <br>* p* J* Z0 ?! L! N5 E
  5.       <child v-bind:message="parentMsg"></child>
    1 C3 R: R+ i+ J3 }5 p; \
  6.     </div>' y  U; ]. n) S+ W
  7. </div>
    3 m" s% a! P% E' N1 ?+ H
  8. 4 P& ^" b0 {9 f
  9. <script>
    # F) Z8 V: a; M+ }
  10. // 注册
    8 m! B, L, }: B) i- [; Q
  11. Vue.component('child', {3 O! K% I& j: \' }9 n' ~
  12.   // 声明 props8 A4 C1 [4 H1 ^) v- {
  13.   props: ['message'],
    ( L% n- F+ G/ Z4 T' V7 g
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    8 U" U' p! {- P; h9 t
  15.   template: '<span>{{ message }}</span>'
    1 ^; `! e: q1 g8 p' t3 N5 e$ M/ [
  16. })
    9 z9 @0 x& k2 Q
  17. // 创建根实例
    3 M* o- ~% C4 i/ S; w5 O3 m
  18. new Vue({6 c/ v9 D1 U1 L& [4 a# @, K  i
  19.   el: '#app'," M. T+ b5 X3 W
  20.   data: {+ U( c+ \- T, @6 }0 z
  21.     parentMsg: '父组件内容'
    3 m% p0 d8 p# ?4 u# X8 W
  22.   }. F$ u5 j4 E/ r; M( R( t
  23. })
    9 J- ]0 [) \& ~4 k* Y% q2 O; c
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例: U( u. L! W5 q8 t' y5 ]9 L. D
  1. <div id="app">/ H( k2 j( G1 m& h
  2.     <ol>/ F" ^8 b; J; m" A: {
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>/ ?5 p: S. G3 M. `* d
  4.       </ol># v& K1 p1 }( u1 R
  5. </div>
    : h4 P! b1 w: p

  6. ! d# v. w1 v: |6 J
  7. <script>0 H# M2 b) K- _5 g; x4 Y( y& _
  8. Vue.component('todo-item', {% C6 F5 r* I/ \9 C4 O, Z
  9.   props: ['todo'],  }6 d+ {& i1 _* G
  10.   template: '<li>{{ todo.text }}</li>'
    5 k* Z& A4 d# }1 N5 @* T; ~2 w
  11. }); O, \6 B. J# }4 a9 l' h/ q" E
  12. new Vue({
    0 d' g* X1 w5 o: C, z
  13.   el: '#app',! S  O( g; V2 Y4 }% j6 M) @
  14.   data: {
    / F0 h) l9 b6 d2 h' V' L' ~. W# N
  15.     sites: [
    * @- O7 w- s& |( f& {
  16.       { text: 'Runoob' },2 ^7 I! D( G4 c- ]2 U' `
  17.       { text: 'Google' },
    9 _9 E7 n: D. E
  18.       { text: 'Taobao' }0 j% y% L4 A' a2 Y( |/ E- o
  19.     ]6 J& N; n3 y. ~) v& N8 Z: I
  20.   }: S  K6 \5 x3 X. R9 m
  21. })9 r7 g- Q  V% I& |2 t
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    6 Q9 }5 D3 L" d( S
  2.   props: {5 Z6 a  N! z& U  d0 I% G% z, F
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)5 s; H" J" C9 m9 `7 p- P
  4.     propA: Number,
    1 ~# F7 l: a& N1 F
  5.     // 多种类型( P# f. L' m" d
  6.     propB: [String, Number],
    * r, t( f* m, b5 y
  7.     // 必传且是字符串* H6 B+ z4 X( \
  8.     propC: {
    8 |4 H8 K( t1 I! O
  9.       type: String,
      ^7 u: M5 G) v2 ^
  10.       required: true5 Z7 d& Z' V+ M1 I+ \
  11.     },5 x4 o1 [! }6 ^1 S' I
  12.     // 数字,有默认值' J7 z- Q6 S: n: v
  13.     propD: {- m! L+ g& a1 F6 R; [
  14.       type: Number,0 ^8 j1 k) n  ]$ D
  15.       default: 100  j9 r4 \) R; X. {& d8 u0 \
  16.     },
    6 q. |- q5 Q7 V, w5 H& P
  17.     // 数组/对象的默认值应当由一个工厂函数返回, L6 Q2 A; u, b" U7 ^* y. q* ]7 b, Z7 B
  18.     propE: {
    ( F$ Z1 P1 s) Q5 D
  19.       type: Object," h2 {1 _; ^5 v  E
  20.       default: function () {
    - A7 E3 k! ~9 x4 V
  21.         return { message: 'hello' }
    5 {! B+ M' ]# r* M( u6 q% E4 D5 m
  22.       }# Q0 O$ R5 |! [4 N. M& w
  23.     },) ?' K! a/ ~* N. W" l, }
  24.     // 自定义验证函数! h7 d# G5 g" f
  25.     propF: {
    1 Z; D+ ~7 `/ E# a
  26.       validator: function (value) {& [& u) D/ F9 ]. m, G: T* C5 d7 |" c
  27.         return value > 10# n' e7 J0 n5 o; a1 W
  28.       }
    ; e0 d1 R# s! w; }* ~; k
  29.     }
    , N. K5 |5 @3 R( j$ |
  30.   }7 X# c/ l9 E7 v2 [- B/ Q
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    7 u: j7 d- o0 g4 w$ \
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    + o8 K8 X* e! Y" Q3 u$ \$ y* e% I2 `5 z
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例: `+ a- A: Y8 F: g3 E* _# x
  1. <div id="app">
    ( ^6 i3 N3 x, [2 B' \
  2.     <div id="counter-event-example">1 r% f# E, Q2 ]- W! k4 O
  3.       <p>{{ total }}</p>
    * x7 E8 @7 a+ N9 a0 j
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    # F" K" M3 ~9 E! ?9 G  {
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    8 B8 [& g: V% m( A( k
  6.     </div>
    . U+ p! Z$ l+ B
  7. </div>
    2 @/ o8 e5 g; g& V. ~
  8. , t" [4 x3 W6 `: }3 C1 X
  9. <script>7 M8 T9 ?. C' q& i
  10. Vue.component('button-counter', {
    9 G3 f- m+ W8 O, f/ a+ P2 ~( e
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',* h+ P8 W9 ]" I" E0 i
  12.   data: function () {& |6 {% D; v3 w$ x
  13.     return {
    9 t8 j; g& X8 ?# B1 X9 w! j
  14.       counter: 0
    ) L' N0 g- S  p
  15.     }
    ) h, F' A  a, K! U5 L+ N( I; v
  16.   },
    : ^1 C' f+ ~" f
  17.   methods: {) W& I0 N5 U) g
  18.     incrementHandler: function () {! T2 e; s' p( B& A
  19.       this.counter += 1
    ' e& R+ E* b( X) S9 v
  20.       this.$emit('increment')* t2 B; R  w8 O$ c( _
  21.     }
    + a2 g' {/ M) B) H
  22.   },7 o0 u  Z5 W9 Z; s
  23. })
    5 L5 Z4 d1 l- ~: R
  24. new Vue({+ a, f& f( y$ w7 S5 V% {  r
  25.   el: '#counter-event-example',
    / Z# ?, {. `1 O2 L! q4 T( A
  26.   data: {- A# x# V# Z$ Y& j% N
  27.     total: 08 Z) x/ ^* _, @
  28.   },% q/ J8 z1 u4 ~% o
  29.   methods: {7 q3 k) ]- d- Z, o
  30.     incrementTotal: function () {
    + a2 m0 N& ~9 ]8 O( \1 N( A7 D
  31.       this.total += 1
    9 Z3 d3 \/ G. y
  32.     }% w3 T/ |5 m: ~8 Z: c6 V
  33.   }
    4 S" a- S; c- _( H6 M+ p7 p' d
  34. })! C$ v3 [7 _# R. T6 E
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    1 K+ c$ u7 n" @* E" L; w* `4 H, U
  2. Vue.component('child', {! @. ^0 `8 R; I
  3.   // 声明 props
    " G( P6 m7 a% D$ Q( A# U1 y5 y: k
  4.   props: ['message'],
    2 O& E& \0 O4 Q
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用% h& T" D! P  |( n
  6.   template: '<span>{{ message }}</span>'  Z" v5 s& q9 A$ D+ `/ ]9 W
  7. }): i) f" U2 S0 V% [0 {+ Z% ?* z
  8. // 创建根实例1 Z, k+ w" K& T4 K( y8 T$ e
  9. new Vue({* F+ j: k! W  B  l
  10.   el: '#app',
    ) d6 i3 @9 v/ k' I% o7 H
  11.   data:{- l3 Q4 n3 [8 N5 m1 |
  12.     message:"hello",
    , M! ^4 A- q0 {4 p3 E
  13.   }
    % ^- j/ Q2 E$ x7 R8 [& K
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {% U5 f$ Y+ g1 p) R8 D  h* I/ ~! H
  2.     incrementHandler: function (v) {
    9 o  @5 |6 A" @
  3.         if(v==1){7 n' t9 p2 V& T% Q0 h5 q; p% T
  4.             this.counter -= 1, I. O% u2 H7 ^6 C" k) G1 v& K  z
  5.             this.$emit('increment',[1])
    # {8 M) l$ B( Q/ R, k/ d0 c
  6.         }else{9 ]9 ?7 _: v1 E% ?& A
  7.             this.counter += 1
    5 E; A' l- b: h$ u! }8 |
  8.             this.$emit('increment',[2])
    1 v" S' w: F  I! n
  9.         }7 l0 F; }: Z4 e# R8 V0 Z
  10.     }$ L  ^7 Y) S9 _& }! Q; n
  11. }
复制代码

7 x8 \( C8 P4 `7 W1 M8 y
+ n, y  ?* j7 l. x" @
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-5-2 13:34 , Processed in 0.055932 second(s), 22 queries .

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