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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15367|回复: 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,并使用它:
7 n, V/ I- j8 F. J: {% T1 G
  1. <div id="app">
    ! D; t/ S' O( O: W. L  J  u/ \  B
  2.     <runoob></runoob>
    1 h$ B$ O, g% M+ l; ^
  3. </div>
    3 {& ^  c; R! Z6 Z0 `, P% j2 ]

  4. * a, j. c1 }( M! {7 r. {
  5. <script>
    7 X" C. O5 B6 p0 T# a( r8 O
  6. // 注册
    1 r+ H5 R) \) {. p9 i' `  X& [
  7. Vue.component('runoob', {
    " K3 A0 j, k& G7 P1 l) q: f7 u) q: K
  8.   template: '<h1>自定义组件!</h1>'& J& D9 D  o! f5 q# @
  9. })
    $ U* P0 S  b/ ?7 v+ J
  10. // 创建根实例
    : j3 e3 z. F' S  _
  11. new Vue({- Q( s6 p! Q* U8 }1 D
  12.   el: '#app'
    # p( @4 B" p- q) x2 o: t" O4 C" s: `4 L
  13. })) F$ V: s$ _  t" \: C( e
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
  |: M5 }9 c2 ~! _# S- c
  1. <div id="app">
    / g" Z, D& C9 E9 P1 V4 C
  2.     <runoob></runoob>
    , G6 o# ?* J+ ?4 h/ o# J0 }
  3. </div>1 ^4 i' Q7 ~- p7 V( c) H
  4. 1 C0 p! ]3 ~6 c4 x, o% h
  5. <script>1 V7 k$ z# I9 I8 S5 b
  6. var Child = {
    7 s6 Z* p) _9 T/ [( ?1 o8 T
  7.   template: '<h1>自定义组件!</h1>'
    ) W) S: F. g3 @. E$ m& F" t, S" r
  8. }
    " Q5 T& c' C7 s- _5 @1 G1 ~
  9. . b3 r, J5 [6 H5 Y
  10. // 创建根实例
    5 u0 {! c1 h4 Z) u! Q
  11. new Vue({
    % `2 o; F" W$ m1 j
  12.   el: '#app',# ?, P: _- Y$ V; C
  13.   components: {& s5 L" A0 H; L
  14.     // <runoob> 将只在父模板可用) ~! u+ [/ L" E% ]+ L. {! f. e
  15.     'runoob': Child" o; A& n9 l6 j6 U. C4 [
  16.   }
    : z" {' E2 v* \1 m* O& F
  17. })
    * Z( B  M) s  Q* H  n
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例0 x2 V! S! [+ j$ Y" {; I+ K; j- {
  1. <div id="app">( l" O6 C$ ?3 L6 u/ _" o
  2.     <child message="hello!"></child>
    2 [& K1 e& ~8 Y
  3. </div>. X0 Y4 W3 p' `8 r. g5 V4 C
  4. 7 v; P& y* [) A1 \
  5. <script>& v- y2 N7 w& K
  6. // 注册
    % E4 P: s3 @! m$ F# R. j
  7. Vue.component('child', {
    ! Z3 Z6 \. d7 ?9 R
  8.   // 声明 props" u* u( z% G2 G. b# Q  }9 Z
  9.   props: ['message'],
    2 k4 v. g: ?! [' \# l) I! y) L
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用$ x8 f# r: p  ~
  11.   template: '<span>{{ message }}</span>'2 ?4 [; J" q7 Z3 R' a8 l
  12. })
    : q' m1 O8 a4 B7 `% B4 Q" @
  13. // 创建根实例
    / ^: g' V6 o3 p8 T
  14. new Vue({
    + `( I: P1 ^1 g% ?( c% J0 v
  15.   el: '#app'5 n% ]% b. g+ I
  16. })( H1 C1 R3 H- {- o2 X9 z/ k+ j6 c- J6 q
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
. D" n! M( k7 Q6 d2 C
  1. <div id="app">
      E8 Z! Q; y  s( t0 c" A! C4 i9 i
  2.     <div>- u% _0 r8 {; i/ s
  3.       <input v-model="parentMsg">
    ! B9 _% k& i/ @  t
  4.       <br>8 o& C' Q* C& o. N- r; h
  5.       <child v-bind:message="parentMsg"></child>8 t% D( B6 U3 ^: a9 J8 b
  6.     </div>
    6 r/ Y' }! v" H3 \/ ^1 n8 f5 {
  7. </div>
    1 E$ Q; t; F- q
  8. 4 x, Z# h) p  h: [; K
  9. <script>- j7 M; P& [! a) z/ h
  10. // 注册. J8 m8 T( D* b, Y
  11. Vue.component('child', {
      r9 Y+ ^8 B. Z
  12.   // 声明 props- U9 Y: n. Y% H& t8 d, Q- W. R
  13.   props: ['message'],
    8 \, z& v! q0 b/ J* j
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ; l. b. y: P1 A( y
  15.   template: '<span>{{ message }}</span>'
    8 J2 w0 v, A6 {
  16. })! P' a- g9 P3 H' W# S
  17. // 创建根实例6 N7 N& |1 r1 @$ o/ O
  18. new Vue({
    $ M. t' C! k& y; k
  19.   el: '#app',
    $ n6 y3 [3 o9 E/ N
  20.   data: {
    5 x+ i  q/ q# Q+ c& Y
  21.     parentMsg: '父组件内容'. }% n7 H+ N) {( \: e
  22.   }
    3 f! P) e+ a6 X/ H* @
  23. })
    3 L7 @! Q3 ?2 B6 \5 d
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例8 p) ?3 ?) e  Q6 w  _3 R: z
  1. <div id="app">+ _4 x1 w; }- u4 [4 i$ l2 N
  2.     <ol>4 d8 J% I: V% s2 U
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>6 w0 t! z- n1 l/ J+ I* G0 o+ Z* o
  4.       </ol>
    7 s) X. K' X' T3 c% F1 I1 m  y7 F
  5. </div>
    7 r) |3 B- y9 [' |0 Y! R7 Q6 O

  6. ( G" p9 e( w& G/ G# h2 K7 e  G3 ?
  7. <script>
    : r" w! N* X; y8 I4 y; y
  8. Vue.component('todo-item', {" o; f% M2 b$ Q* I# e
  9.   props: ['todo'],
    - b, @$ Q$ b( ~1 \, }
  10.   template: '<li>{{ todo.text }}</li>', G# x$ ^. H- D$ |
  11. })
    $ V* a; w, N$ q' o
  12. new Vue({
    : j: j9 [  R! b* I- t! \
  13.   el: '#app',4 w: ]8 ^6 X) w8 A/ C6 T
  14.   data: {9 s' x  g  l* O/ u3 E6 }2 T8 X
  15.     sites: [
    7 B4 d: W) A1 i$ P, O) f1 q7 s
  16.       { text: 'Runoob' },4 _3 G4 I, J* Q: B: L. B$ b( x
  17.       { text: 'Google' },! `. y7 `- M4 F9 g9 c$ f, T  {
  18.       { text: 'Taobao' }
    . L, S. q: p8 h5 E5 p, R# C
  19.     ]& T) S0 j: K! S' B& k% R" j1 U
  20.   }+ F7 Y/ T8 ^! [
  21. })
    6 j5 D& b& Q8 o: K# b* u
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    ; b- [. {, E' s4 G: I( u) w
  2.   props: {
    ) ]2 g( @# T) m( [& ]9 U
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    ' Q0 F4 f; r- B" n/ F0 _1 b6 F6 ?
  4.     propA: Number,
    " P9 {  y- U' H3 b+ ]' {+ n
  5.     // 多种类型& s8 v4 [' o4 w/ x! ~; Q6 F
  6.     propB: [String, Number],2 ?' k# ]2 [4 o6 h
  7.     // 必传且是字符串9 J, U7 l7 c) y* ?
  8.     propC: {* Y% i6 p5 z/ ^, q/ n
  9.       type: String," S# E/ R5 A' {; w9 M
  10.       required: true
      E1 s# Z4 X; y
  11.     },; `. @9 O3 f5 z0 l$ k
  12.     // 数字,有默认值% \# Q5 _2 R9 Y9 \
  13.     propD: {5 Y. V. G. M9 [- o8 q4 \9 N( I; C
  14.       type: Number,
    $ v3 w* @+ n/ K1 h  f5 a3 s
  15.       default: 100
    : N. s; p4 m* B* [+ c* ~1 l( V$ m
  16.     },
    , C1 I5 ^8 J7 `3 d  |. s
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    + ]- ~/ q1 t3 ~. O% B: f
  18.     propE: {7 f& H+ E+ G! z5 y, m+ \8 Q5 G! C
  19.       type: Object,+ D0 X, B7 t* H; f' l
  20.       default: function () {+ i: [0 n! ], k# g6 j- M( O: ^
  21.         return { message: 'hello' }
    ) i3 {2 E& W" d( e& j# v) `
  22.       }! V- t) _" i; A9 i$ t
  23.     },& i; O4 R6 t' T2 g- \
  24.     // 自定义验证函数  _1 ~  n% r6 x. s7 F! z
  25.     propF: {. p# n0 M/ `# y- y5 G+ B8 p
  26.       validator: function (value) {& H3 e" }6 R1 N9 l
  27.         return value > 10' F+ ]) _" ~6 Y, j6 v
  28.       }
    % o' n/ E' o1 T4 a
  29.     }2 u* T* }) M  y6 S: g
  30.   }
    ! s2 m8 C0 }- V( F" y, K6 H
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array# l- X- k3 h' `2 }$ S* L4 D1 o; q
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    6 ^# r) K9 \+ t$ M. O/ u. M
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例# U' N# S- Y. ~" t" v4 D
  1. <div id="app">7 z& V# L6 O1 a, Y% w( u* f' R
  2.     <div id="counter-event-example">
    & Z4 O8 c+ d2 T0 {0 M
  3.       <p>{{ total }}</p>$ f/ o+ C& @! I9 E8 `6 c
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    + s$ V& m* w7 m1 Q( a& e5 U
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    " d, V- g5 L2 O1 k8 {3 [2 k
  6.     </div>, z0 N4 Y+ n8 U- i: Q  g
  7. </div>/ u4 Y0 b9 {& Y5 i+ H. O. Z/ o
  8. ( r0 q3 e" y) I# ]5 {) d7 u" j
  9. <script>3 L, X* [9 @* z' U+ x3 u4 M
  10. Vue.component('button-counter', {
      y# m0 q+ V' D2 R3 x
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',4 M  d+ W$ u( P$ C1 ?1 m' |
  12.   data: function () {0 _% q/ f( ^- n! }
  13.     return {- I& s+ a) m6 q  T
  14.       counter: 0
      g$ U! R9 s9 l4 m" Q
  15.     }
    0 A  ^+ F# l) M
  16.   },
    ; o5 H, C& u& V9 R* z8 W
  17.   methods: {; x/ J+ k8 S  P
  18.     incrementHandler: function () {( v# \" y( v7 e7 D
  19.       this.counter += 1
    . B8 Q" \. y- `5 {7 X5 X  A4 K4 Y
  20.       this.$emit('increment')
    ) h1 _+ F& ^4 l) c
  21.     }& N; z* W8 U% }4 W- k4 Z
  22.   },
    * ]& g  x7 b# n  Q, ?6 `) B
  23. })
    ) n& y) d7 T! |: U& V* H* R7 C
  24. new Vue({
    ' D6 @1 s5 L1 g) v! p5 s' M
  25.   el: '#counter-event-example'," b" |# U* N/ ?3 D7 }! L* x
  26.   data: {
    5 Z; i) D8 u. |
  27.     total: 0# E+ z4 ~# N, I1 Z/ W! J9 k1 H- v! F
  28.   },
    ' \! v% b  u4 n7 \& j
  29.   methods: {
    # T. _$ q; b, N; X+ S2 i
  30.     incrementTotal: function () {
    4 S' r3 y5 k+ I# O# j0 j; Z
  31.       this.total += 1, H, c7 ]  a  \. V$ v+ W0 F! e
  32.     }# _$ O; W( F/ I$ h8 F
  33.   }4 b* p' F  ~1 d
  34. })& V0 m. t. Y4 C* t6 ^3 B+ H* r
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册6 m5 @+ K7 I1 n. V& D, o8 k
  2. Vue.component('child', {3 @0 }4 _5 G; Z2 `5 `; y  G: i
  3.   // 声明 props
    0 K+ z# R$ k3 G! z8 t7 o' I
  4.   props: ['message'],% B& |% o) H8 T( u. M
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    7 f# D& q$ `3 A( b* e6 t# O
  6.   template: '<span>{{ message }}</span>'
    7 j/ [/ S1 s* P
  7. })4 u. r6 P- }, _% T  X
  8. // 创建根实例0 ]  o# u: E( L' n) v7 D2 Q9 w5 Q- N
  9. new Vue({/ z& ?' Z3 T9 A) b
  10.   el: '#app',
    0 i; c) i- ^9 w. m8 @
  11.   data:{
    6 L9 z2 D" e+ u$ R
  12.     message:"hello",
    8 J% v/ ~" f8 K$ t0 _
  13.   }( {8 a* q0 o7 N3 u( d
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    6 K: J$ B- {, K4 B* r8 S
  2.     incrementHandler: function (v) {) e6 d. d. M6 Y. b9 ?3 V8 R4 s
  3.         if(v==1){5 E4 K) B6 M. j! H$ J! O  b% F
  4.             this.counter -= 1* u9 M9 B" T" u, B! K
  5.             this.$emit('increment',[1])
    ) @9 A( w5 I; }8 h- O- v) K. u$ U) ^
  6.         }else{' A1 ~  t) A2 Q4 |  o
  7.             this.counter += 1
    2 L, s" _; D6 \' h
  8.             this.$emit('increment',[2]), \6 {% O; w! L8 C- a
  9.         }
    8 H; F4 j- E2 _3 D$ k7 ^0 T+ m
  10.     }1 |' v* K; ?) `5 M2 X7 b
  11. }
复制代码
- T9 C. ?4 e6 t  M- q5 a, U9 Y
+ n# S* ~: h& R- {4 c
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-17 18:24 , Processed in 0.056789 second(s), 22 queries .

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