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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

+ s, n- m( D( ~7 H
  1. <div id="app">
    7 w+ H. t8 R) z9 T
  2.     <runoob></runoob>  d$ k$ r( q0 {6 f2 S; L2 B
  3. </div>; _$ g7 [0 Z2 T( J6 y( X
  4. 0 N4 {! }5 p! A  _
  5. <script>3 k/ T  o0 Q4 O1 z. i0 C/ u
  6. // 注册
    ' f9 \% I) ?! F
  7. Vue.component('runoob', {5 f$ }# X4 \0 d3 l" D% B
  8.   template: '<h1>自定义组件!</h1>'
    - z2 D* W- O( i) T/ A- h
  9. })
    3 }' T: }5 w8 M! q8 U4 ~
  10. // 创建根实例* f0 R1 y# `% G- ?6 v4 f* G
  11. new Vue({$ x# B, c6 \& `1 q( N2 O
  12.   el: '#app'
    " N1 u( e7 p  c1 t8 @  R
  13. })
    $ V* O% [- a+ R0 M7 Q7 d, B
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

6 ~; Y# R2 R' N/ [7 u9 R6 Y
  1. <div id="app">
    * x& j# O5 X7 \. ?. c
  2.     <runoob></runoob>+ L; o& ?* o' L
  3. </div>
    . N3 e1 O2 p0 u
  4. % H+ a# W" P. K) L2 \1 Q* O
  5. <script>' `1 S# o: a; c5 v  M# g
  6. var Child = {2 R; V- d) D, j  a! O
  7.   template: '<h1>自定义组件!</h1>'" ]2 b+ c1 S$ m
  8. }
    7 |8 Z, _! K7 \# }+ m7 u1 @( F) m  V

  9. : @: \( j: a/ F, |7 \9 O% n' [( O
  10. // 创建根实例
    . u+ L0 [7 @: K
  11. new Vue({
    + q5 f% n: {; [+ W: D0 P2 n% N; J. B( n. y
  12.   el: '#app',& x/ c1 T5 {- g3 l4 n  Y( R
  13.   components: {
    % o. z4 d' ?. {8 X' G+ q
  14.     // <runoob> 将只在父模板可用
    - F& S& f) d# G3 i* @
  15.     'runoob': Child
    3 D. N! o& ^0 |# H- ?
  16.   }+ S3 ^. x+ N2 L0 h" r7 s6 N
  17. })% j- U* J& s5 f: s" i! Z0 ]
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例8 U; l8 Q7 Y3 n( o
  1. <div id="app">- _% N' `1 Z  `8 `5 p5 A" ~, p
  2.     <child message="hello!"></child>, C6 M& y% Q0 C4 V4 p4 D
  3. </div>
    6 h) I3 t  E8 T
  4. & A, T% n8 N, C  w& t
  5. <script># P: f3 e2 ?1 h; l2 f! w$ E
  6. // 注册
      w) V- [4 L7 c1 [7 z# h# B# f0 c
  7. Vue.component('child', {# l, v& V( k/ S  E3 f4 b& H
  8.   // 声明 props/ y9 M* ~% m$ C# _1 J3 s
  9.   props: ['message'],
    ( S: Z' D: q; C. Z
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    3 C0 R7 Z: _: e
  11.   template: '<span>{{ message }}</span>'
    - w" a7 c* G2 Y2 e7 W( \1 [; a3 z. k
  12. })! F7 }$ q6 w2 V5 c: J3 a
  13. // 创建根实例3 ^+ Y: O% m' m; X/ K3 j
  14. new Vue({
    9 ?8 A8 x. p" h( |/ F: L
  15.   el: '#app'
    9 E5 }4 O: d/ J& \
  16. })
    4 b: z9 K% S7 a! e  W  I
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
* b, d! w) Q4 x0 _5 s; t
  1. <div id="app">$ g! ?- K+ O3 P" T* Q, W
  2.     <div>
    ( `3 V+ J/ L: P, [- {2 Y, d7 g
  3.       <input v-model="parentMsg">
    ! q# s1 e2 l% W' G! k  U
  4.       <br>
    * j3 Y; t7 C( j% e
  5.       <child v-bind:message="parentMsg"></child>
    - j2 I5 ]9 L+ c; ^3 W! K6 N
  6.     </div>
    8 s+ V% D- z. ?- d  V3 O
  7. </div># w) \; c) U+ q2 D( M: y3 m
  8. " ^3 Y. y9 t; o0 y
  9. <script>
    7 S3 Z0 d2 {' ^  {. x% u
  10. // 注册# J# f1 u3 g/ ]$ B
  11. Vue.component('child', {
    6 x! [& J2 H6 S' R6 ~
  12.   // 声明 props- q) j0 l5 T! E' P
  13.   props: ['message'],5 d" i$ B2 k/ J/ [+ [6 e( ~
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用2 D$ k3 l; ^  o/ K: Q* u
  15.   template: '<span>{{ message }}</span>'
    * i4 \% M5 ^4 B# c& N
  16. })
      t3 k3 C% k+ a! G! w2 r' F" G# H* w
  17. // 创建根实例& q+ L9 d$ _5 W2 \+ ^9 \# Y; Z
  18. new Vue({& G( M; F  t: |: E) m& ~" O& ?
  19.   el: '#app',
    # ]: E; b. c: d4 x; C
  20.   data: {; E/ E1 |# o! y: {7 D: v# q$ \. {
  21.     parentMsg: '父组件内容'
    6 d) P6 Y. {* P$ G
  22.   }7 G$ ?! S6 v* J( A+ O- _; L8 N( d: [
  23. })% b1 Z+ Y0 {3 o4 v# R
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
+ R1 B0 p8 @( T0 h4 J
  1. <div id="app">1 s& h1 v* m1 h: v/ \1 f1 D3 x
  2.     <ol>' [7 n. r" X; d, G( x
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    7 f6 y3 a  a0 n9 \: |
  4.       </ol>$ |! t  \8 O1 x& d/ @' o; ]
  5. </div>
    2 i2 L1 J; w' T. T' s  b0 i

  6. / c) U3 E: c% Q# P& ~2 W" m4 w
  7. <script>8 I; }/ g- i0 y, l7 z
  8. Vue.component('todo-item', {, H5 n& `2 g4 Z- G- M" w. j
  9.   props: ['todo'],# y( ]6 |8 A# ?1 l6 j
  10.   template: '<li>{{ todo.text }}</li>'
    1 A5 u0 z, H& l% q: ~9 g7 c
  11. })
    * P8 _# o6 w6 \1 U7 S
  12. new Vue({
    5 @6 H5 h! S6 T
  13.   el: '#app',6 P4 ^+ ]8 ^1 g9 v
  14.   data: {
    1 [0 Q' `0 |5 r6 ?, N" e! {
  15.     sites: [! M* h0 G# _/ q/ i2 y- ]% c
  16.       { text: 'Runoob' },
    & [' g. w2 u$ q* J. l+ @
  17.       { text: 'Google' },9 @/ [& l9 g, s6 y. m: @2 R
  18.       { text: 'Taobao' }" p( b" w! o9 f8 L/ d
  19.     ]
    9 W( C* ]& a! T* Q/ h8 C; Z% E1 L
  20.   }, W$ f9 A# {+ {+ G
  21. })
    4 c1 F1 L  j7 f" Y2 q8 e* J
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {' `& G7 l9 _' C8 |
  2.   props: {
      i/ }! M: a7 w( [; g" |8 X1 W  K1 V
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)# I% U/ S, D; {& g/ B, K/ m
  4.     propA: Number,
    3 n$ T! s! d1 w  `
  5.     // 多种类型
    4 W! d. N! L1 q, q
  6.     propB: [String, Number],
    : q! o8 y- H1 _* c6 F
  7.     // 必传且是字符串/ q+ E' ~( x9 b: ^; S9 c+ U
  8.     propC: {
    # F4 j* T, h4 ^% y/ }0 F6 r1 ]
  9.       type: String,
    . C  N1 X0 N- q
  10.       required: true; s& a4 {. s2 W% _& r
  11.     },
    4 r5 [" E' G6 K
  12.     // 数字,有默认值
    6 A: a8 ?0 d- c; E8 Z
  13.     propD: {3 s, {# r$ D7 k0 A! D6 a0 i- F
  14.       type: Number,
    , ]7 g( m$ T$ S$ L5 c6 X( b
  15.       default: 100* F! ]1 `6 I9 `( q5 f$ X
  16.     },# C4 l4 Y" ^1 J" g& u- r7 b
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    / Y" Z5 H. F! @  [- o) _' m1 v
  18.     propE: {
    . ?! A( E! {. K" ?
  19.       type: Object,  b- @! M1 W! Y7 x4 g
  20.       default: function () {
    9 Q8 i6 v- a  c3 q* y
  21.         return { message: 'hello' }
    - G0 r# ^6 F; D0 r5 d6 `& ]
  22.       }- o' {$ M# R, |8 `: e3 j
  23.     },
    7 D* b5 D0 r: }0 X/ r
  24.     // 自定义验证函数
    7 `1 V6 l8 L! P2 [$ T9 {
  25.     propF: {
    " p/ A6 U3 ]& o; m
  26.       validator: function (value) {
    $ ~9 y, _# _5 x' D4 j' A3 L
  27.         return value > 10, b+ T. m& n% e3 G  m/ j
  28.       }3 S; e& i) l9 x0 C+ a
  29.     }* h  U) L2 V1 w; A+ ]& I: ^! m
  30.   }; ~' u/ x( q( H0 L/ s# K! p
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    ; h& m9 t: s4 h4 b
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    ' `0 J  l- ?3 ]1 h. \* L/ a; P
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例# p$ U; y  b' m( R
  1. <div id="app">: Z# J! x% M" m( f+ S% s
  2.     <div id="counter-event-example">7 }. c0 c* G0 Z) @2 m0 \. \
  3.       <p>{{ total }}</p>
    8 y, s, q4 v  n! g+ l
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>4 J. b# h9 d1 r( p
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>) H! I' e! I- N8 U0 F% n' P4 _
  6.     </div>
    $ ^4 f! ^1 Y( R$ R& q5 D7 \: i
  7. </div>
    # W* v3 ]: ~, V2 Z, w

  8. ( a$ @8 N- }$ e! {
  9. <script>4 g, W( d5 B- V$ o
  10. Vue.component('button-counter', {+ d0 _) \5 }. k/ B) o6 U! L( C
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    : e) u- t, P1 D9 M
  12.   data: function () {. Y7 ]& J  a: Y  L1 U0 A+ b
  13.     return {
    0 J, z5 P; `+ t4 A, r7 f8 ?
  14.       counter: 0
    7 j% A  q7 m: p" J& r4 q
  15.     }9 \$ M* E+ g2 M2 Z, N
  16.   },9 ]: o7 g" C4 h. |* s$ [
  17.   methods: {
    $ h2 ^! s0 E5 M
  18.     incrementHandler: function () {+ q0 X( Z- _7 Q9 j% R9 X+ P
  19.       this.counter += 1) ]- v5 ^# c! U7 ?* J3 R/ F( m
  20.       this.$emit('increment')
    ; Q3 @! h$ w4 C  z4 n
  21.     }) n  L' b) i( f$ q" ]
  22.   },
    . I. X5 T; y: |$ R& ~, ~
  23. })) B% @+ @0 G  W9 v/ ^/ V
  24. new Vue({
    6 U0 C% ^! z) O! h6 u: |% X1 @9 z/ A
  25.   el: '#counter-event-example',
    7 a; S( ~! P+ k2 E0 \7 }
  26.   data: {
    9 b: P5 W3 e7 x0 w7 d2 k
  27.     total: 0
    8 b/ f2 S. T7 _: D3 V
  28.   },+ s0 ]$ n, @7 A/ a
  29.   methods: {2 Q% E1 }" o1 h5 Q5 `* z% A% z. C
  30.     incrementTotal: function () {
    ; N6 `6 l! h1 j! E6 ?8 P) K9 x
  31.       this.total += 1
    ( d% M. S! v7 F! U* W3 K
  32.     }9 S" Z: M. M5 y5 C4 T! c" a! Y
  33.   }
    ' l0 z; D9 ]2 u% i4 U" T7 d
  34. })
    ! S; s+ l* S3 T- c2 F" x, [" U
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册; R/ z- i+ l+ Z0 N+ E% m
  2. Vue.component('child', {
    * Y& t, b; D5 L  t, D5 W& W6 k
  3.   // 声明 props
    8 y* b4 C4 c- Y6 U3 R; l( l* R+ A
  4.   props: ['message'],$ ?# v$ _: y; E4 J4 ?& A8 X
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用* I8 Y, M* S; R+ q: z
  6.   template: '<span>{{ message }}</span>'
    / N, v1 H: @2 m& H
  7. })
    & U! `5 ^6 O7 Q% i8 g. V; l) P6 l' A# u
  8. // 创建根实例/ Y3 n2 _8 J; Z8 y( S* V5 |
  9. new Vue({& g; `1 N# ?* b, f6 x
  10.   el: '#app',
    4 d% x. f- e8 }" h
  11.   data:{4 @8 t' t8 ]' A/ W& A# i* S) _
  12.     message:"hello",
    * t( H8 L( n) S* M+ e) l
  13.   }" E# g6 N7 a; \: p5 e) X9 ?) x' t; N
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    1 i; Z9 O* o3 o- M! t
  2.     incrementHandler: function (v) {
      E  J  N4 {9 t8 e: _  ^
  3.         if(v==1){* i& U8 x# ]# o" y1 c
  4.             this.counter -= 1
    + v; x, N* _! }
  5.             this.$emit('increment',[1])" r! M) X8 R: ?2 c* @/ E# m0 F$ V
  6.         }else{8 c0 e3 Q/ }/ q( x2 Z. B
  7.             this.counter += 1
      _7 p$ R( Q) U/ b! v
  8.             this.$emit('increment',[2])
    + e( q/ w# ^$ P
  9.         }) a- i/ V0 `& Z+ b
  10.     }& q0 V- x, y$ q
  11. }
复制代码
% n2 [- ^5 M$ t4 T, b
  C0 H/ A" B3 G, k
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-9-21 03:11 , Processed in 0.087282 second(s), 22 queries .

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