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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

. h/ N, X/ e6 M9 W$ J' w
  1. <div id="app">* K/ W3 i& M" P2 _4 E" Z
  2.     <runoob></runoob>: y* i6 h4 |) j9 @
  3. </div>6 d2 Y, E) j; v, J3 _/ H

  4.   e# D6 a( `# l& d1 ~$ M0 {4 h
  5. <script>' {3 @- W) ?8 x3 J9 R% |
  6. // 注册
    - R$ q9 j/ `0 O% z  P$ A
  7. Vue.component('runoob', {
    2 r. D" t3 w* G  p# |
  8.   template: '<h1>自定义组件!</h1>'6 c6 ]; t& Z" H. h( n- W# ]
  9. })& u3 \1 {. ~: Z
  10. // 创建根实例
    0 ~6 d. o  L: M* f& }
  11. new Vue({4 {0 z2 D: k' P1 y
  12.   el: '#app'
    & |' y! U, N* Q* x3 s
  13. })9 Z- `" J3 F6 \0 O- d  Y" i& p& l
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
( y1 B5 }2 R. W# D/ H/ n5 j
  1. <div id="app">2 P2 A6 ~" L% G; D7 b) T& r
  2.     <runoob></runoob>  w  A. V6 B* a2 J! Z
  3. </div>
    . D7 [8 |8 H& q2 ~6 v7 V
  4. / D, B( L& f1 H. {7 L
  5. <script>
    $ E/ ~. s7 w; o8 j
  6. var Child = {
    1 C/ z5 x7 X: K7 E# O* l+ K0 D
  7.   template: '<h1>自定义组件!</h1>'. S% c& Y+ I5 a% |
  8. }+ z7 Z( e2 `) A) W% C

  9. 4 J( o; P2 p1 D2 h
  10. // 创建根实例5 p( [6 P& |# Y6 @
  11. new Vue({
    0 Q: K* b5 \9 [, b5 s1 I1 e
  12.   el: '#app',
    2 F  ?1 N! l6 M; v. R( H0 Q
  13.   components: {
    " u) r  d( \# w  r: f0 R
  14.     // <runoob> 将只在父模板可用" `/ a; \# z9 X6 r  o
  15.     'runoob': Child. K1 A. m5 F& x! d% h  b6 ^7 k
  16.   }* |5 }% e' T" B& J
  17. })
    : x6 M  |9 @5 h; w7 ?5 b# y
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
+ W% S/ E, j) N9 N/ b4 X2 c9 a; j
  1. <div id="app">8 r4 g' Z' ^1 f. o3 j3 Q, U5 U3 T
  2.     <child message="hello!"></child>* V% i* V- v1 ?, K  ~
  3. </div>
    + h3 j& x# @$ E

  4. & q' e' _$ X" f0 `7 @
  5. <script>
    - }4 B+ S: g: R! t6 L0 D
  6. // 注册' {2 R. [* ?6 R6 |. V( F. L0 x
  7. Vue.component('child', {
    + w+ g2 }& X; ^- t9 \+ b
  8.   // 声明 props, S# A% `% o  u
  9.   props: ['message'],4 c- C0 L9 u5 E; ?
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用' v+ W0 q3 F* L: R! R* ?3 R1 l9 Q
  11.   template: '<span>{{ message }}</span>'" n+ {1 U% f9 a- M' w
  12. })
    ) m' T' E2 U! s3 P4 k1 B3 K
  13. // 创建根实例
    ) A# e- L. }4 s- y4 i3 I
  14. new Vue({
    % d4 T% y( C" U6 [
  15.   el: '#app'
    $ u7 m; v3 C' C) S! J
  16. })
    , }, ^; @. `7 V3 b9 I
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
9 H- S+ D4 c. o
  1. <div id="app">4 Q, ~* N( c. f: g( B0 m
  2.     <div>2 z8 e! [  y" I2 a' B: w
  3.       <input v-model="parentMsg">
    1 ^% R0 ?& p  Y6 J
  4.       <br>& }9 l: R, \' p  g3 i
  5.       <child v-bind:message="parentMsg"></child>
    - U6 \: c3 }) j5 h
  6.     </div>( e! r! r9 Y( c$ M% e# z
  7. </div>+ A- p8 q* j( F! }7 d0 U
  8. 8 ]: i# h# ]* {' m: \7 i$ L
  9. <script>
    5 Q5 n" r5 o( O% F/ k4 M: v9 A
  10. // 注册
    & A* ~( s& I( C0 N% b! \1 d9 C
  11. Vue.component('child', {0 |9 c- O1 q  G" ?& P
  12.   // 声明 props
    4 h4 L( ^( A5 b4 I+ y4 h) P
  13.   props: ['message'],
    5 C; m, a) H; a, V
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用1 u2 U5 o) ]& G! ^4 h
  15.   template: '<span>{{ message }}</span>'& c& d9 ?; }% G  U# _
  16. })5 _+ O4 W, I9 I8 t% W$ k: ?
  17. // 创建根实例, j) A; T! R6 }
  18. new Vue({  M4 `; Q4 C7 H: \1 z! R$ ?9 N
  19.   el: '#app',8 J3 R; ]" G/ b" n' D* f& w
  20.   data: {, H. z1 h& j5 f& [' d
  21.     parentMsg: '父组件内容'; }9 k; k! }8 ]; `$ T
  22.   }
    % X. y3 E( i1 w* f# @
  23. })( v) r* s' {4 x" a4 n
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
+ \5 b* J( V$ @, T
  1. <div id="app">
    ; M5 r9 f% J7 G9 V4 E
  2.     <ol>
    - K1 }4 i$ `' {+ \
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    / v+ B; N7 m9 e
  4.       </ol>5 P. v9 I* X" s2 J
  5. </div>
    ! m9 N9 n% P$ c  ]) L

  6. - b; I7 v& K- Z  Q; r* P
  7. <script>2 m* {; B1 k. i# ~7 F- G
  8. Vue.component('todo-item', {2 t  R3 _7 v$ t, D; m
  9.   props: ['todo'],$ N4 w  O0 G% L4 _4 v/ f
  10.   template: '<li>{{ todo.text }}</li>'
    6 C6 g* h. F7 K7 L2 e0 R  B4 K
  11. })8 h6 p" m1 T2 n2 i. q, [3 q' i
  12. new Vue({
    3 {9 N9 l  t9 v$ A4 l$ J1 S1 Y
  13.   el: '#app',# X1 J" l' _) [9 b
  14.   data: {
    / b9 ^# h& m; i" x9 q: o
  15.     sites: [
    * u4 B+ j# H4 Y$ z
  16.       { text: 'Runoob' },
    / q. H0 ^6 ]7 c5 c2 d
  17.       { text: 'Google' },1 `# [' F% y( l7 v3 S$ X; y* \
  18.       { text: 'Taobao' }
    + C# l. d+ C) G- P; \: h; C
  19.     ]
    1 J% H3 d# ^: J3 d7 K
  20.   }
    1 a  }. v. c  |: x7 m9 ~6 O$ w
  21. })
    # [" M# V& M6 Z
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    : Q/ x9 ^) v2 U6 f" [: i/ S! t$ J
  2.   props: {' a1 e1 C* f: [7 w  W4 y
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    % u3 m' a) i& j" i( I* y
  4.     propA: Number,$ N% O1 A/ n: E5 D: D) u% n* C
  5.     // 多种类型
    5 G( p/ f: f0 V) A
  6.     propB: [String, Number],
    ; V# c7 |, `/ O& \
  7.     // 必传且是字符串
    5 d3 F7 L: Z# F+ q  y
  8.     propC: {
    & \+ y& g, H) h
  9.       type: String,. h- \! N, p8 r* ?4 V: {
  10.       required: true$ M5 S  Q6 M. Y0 X8 h
  11.     },
    ; l+ y0 w( e; ?" c
  12.     // 数字,有默认值
    9 t. f4 N, h4 t0 A) a6 y
  13.     propD: {% c, c/ `/ h% J$ z; w5 ^& H' l( ]% B
  14.       type: Number,, a7 V* `( f' D% L1 M
  15.       default: 100) P; m3 @2 ^; X! T
  16.     },9 n4 ^# i7 L& U
  17.     // 数组/对象的默认值应当由一个工厂函数返回! c$ _( I# g! O9 b' t
  18.     propE: {
    3 [/ r; d; C4 U; \: v
  19.       type: Object,4 {1 A8 p1 Q2 b! Z
  20.       default: function () {
    ( c9 x. V8 i7 I' L! m
  21.         return { message: 'hello' }( l# P+ d2 {/ N3 L5 ]' }
  22.       }
    ; k2 |2 v8 N; p" Z# w: y
  23.     },3 x3 w$ F' ]$ {
  24.     // 自定义验证函数
      |7 Q9 L4 p3 Z" H" U
  25.     propF: {, ~, G/ e+ P8 ?& _2 H
  26.       validator: function (value) {8 X. h6 O0 p$ {
  27.         return value > 105 f7 d" A3 o+ N. M% j
  28.       }  r6 r0 ^& C4 {( w% L
  29.     }
    & D/ K+ ?' V3 C: J! v/ [
  30.   }$ a2 {# C: z, w! q/ |# P( b5 p
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    7 L0 ]- U; o2 f/ S5 N" {8 X
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件+ ]" _4 V2 b" ]
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例% V3 z: t5 Z( o  e
  1. <div id="app">
    . v+ \$ W& V: N3 o8 u0 }
  2.     <div id="counter-event-example">0 a2 G% V# U' Q4 s( w
  3.       <p>{{ total }}</p>
    ) N5 l$ h  d1 _# D
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    1 ^) R7 n- k6 ?
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    ! W2 J# C3 S$ ?5 e" B3 T
  6.     </div>) a7 a, |- k( ^
  7. </div>( m3 t& z2 a; ^
  8. ; w' e; q2 X$ t1 b
  9. <script>" h2 R5 a. @4 q0 g* r5 h) E
  10. Vue.component('button-counter', {
    2 b  g& ?4 ?$ L$ g" V2 s5 p
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    : d5 E/ i" t+ [9 l4 Y( \
  12.   data: function () {; b5 K; M$ x$ _, g  a
  13.     return {
    * S( v1 F6 z' J; Y* k& J& t
  14.       counter: 0
    % ^2 f( q' L7 w( X6 B
  15.     }$ g3 S. f; |& h- ]
  16.   },
    & l9 G/ E; B1 d$ Y! H$ J
  17.   methods: {- x. ?8 Q$ D1 t: p' o
  18.     incrementHandler: function () {
    ! \/ n/ k. C* w+ f& H
  19.       this.counter += 1
      G6 C0 W6 r5 R; A; F: B' p0 k( Z
  20.       this.$emit('increment')5 F) V0 S; q, |* J5 Z
  21.     }$ W  v1 ~# k/ b- K9 w5 Q. e
  22.   },7 o- @, m: z9 l4 Q2 R* b0 V5 t
  23. })8 T! Z# `" D6 S
  24. new Vue({2 R; S4 l8 Y0 [, o6 b
  25.   el: '#counter-event-example',; H3 t8 D  d" F* E
  26.   data: {$ q! ~0 f2 Q* @2 a$ r( \/ k
  27.     total: 0
    2 U! w# r2 d9 F  x& q2 @3 p& _
  28.   },( w4 m4 K5 T% E* o
  29.   methods: {2 `: y, _* ?1 x
  30.     incrementTotal: function () {
    ) f3 {0 n% @5 Z) X! N
  31.       this.total += 19 x: |  A& x) t' p
  32.     }6 z0 R. Q; T4 \. O/ z; k8 a4 `1 d
  33.   }$ z0 `' e4 u( ?: ~/ |
  34. })
    5 w' M. R% m% g0 w; N7 _
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    * d: h# b5 q5 k7 g% g7 p; Y
  2. Vue.component('child', {- O# h/ [8 `- p% j3 A8 `" T
  3.   // 声明 props$ }+ h0 z; `$ y& i
  4.   props: ['message'],
    ! g* b9 v! w5 Y7 y) S3 ?
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用* o/ m+ L3 e. I$ P
  6.   template: '<span>{{ message }}</span>'
    5 w2 A. h+ B' U& u& _6 a1 L
  7. })9 q: ?6 D; i% {! m3 X
  8. // 创建根实例
    : ^* t$ x! i+ K
  9. new Vue({/ ~; ^+ p8 o' A
  10.   el: '#app',
    . A* Q  f$ B, E* G3 D0 B
  11.   data:{, D; ?: v. J- _; N$ M
  12.     message:"hello",- h8 u: t/ L3 j% K5 F" j, w! Z
  13.   }
    : ]( `4 R% D  @0 P, G
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {0 s" k0 Z& N6 Y& {5 H6 @% f
  2.     incrementHandler: function (v) {8 c/ q+ x- J* O1 D1 B. L
  3.         if(v==1){
    / c$ @7 a; V; L& x$ g0 G9 b
  4.             this.counter -= 1
    0 G( n- h/ g# j, X9 |$ d8 X  \
  5.             this.$emit('increment',[1])
    + V8 {3 F" l' R8 h$ [$ x
  6.         }else{' @( X- ?% |# k3 \
  7.             this.counter += 1
    . f  D/ G- T0 b3 e
  8.             this.$emit('increment',[2])
    % K' X) b8 A1 c2 u. ~
  9.         }
    9 t: J: k5 q6 G+ ?9 t+ S
  10.     }
    ; t' M9 e6 k! F6 u
  11. }
复制代码

2 O$ u, ^* I1 D. F! u) }0 b+ {% z. L1 a9 F5 X9 q
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-17 20:21 , Processed in 0.073396 second(s), 22 queries .

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