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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15356|回复: 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,并使用它:
& i, c3 G( g% R4 ~, b) d
  1. <div id="app">/ H6 ^: L) a) [) @7 C
  2.     <runoob></runoob>" C. S2 H; b0 e1 \# I
  3. </div>, p$ f$ e4 n% {8 |" f" R
  4. ' v& W  R+ A; Z% I$ l! e7 m$ x
  5. <script>: N3 X, Q! o. I* z. `% o& N
  6. // 注册
    ! i0 p9 Y9 V3 X8 A
  7. Vue.component('runoob', {
    2 i# W" e5 F8 J) z+ q
  8.   template: '<h1>自定义组件!</h1>'5 t" s- e- x6 S2 k8 Z
  9. })
    5 J! p: W3 B, n4 s  I" q
  10. // 创建根实例
    # M) j! {1 H% G$ s; h' w
  11. new Vue({
    4 t: W7 l0 S! X- |! n
  12.   el: '#app'
    % r1 |" y% j& y( z& }1 n
  13. })" ~7 n/ |9 g! h+ ]/ c; A" C$ T
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

' a% v! `+ R4 a' P! f3 N
  1. <div id="app">7 q# K+ S* Y: ]. y- S
  2.     <runoob></runoob>6 z3 A( K5 S3 e% e9 @
  3. </div>
    & W7 K+ h3 D9 `3 \1 d$ X

  4. - U6 D+ A# o5 j, n5 N. w9 _2 J
  5. <script>6 y  z1 e, y/ k' z$ w" Q+ c3 ~0 F/ G
  6. var Child = {. f9 x6 K6 A) e: _
  7.   template: '<h1>自定义组件!</h1>'( g3 w; E3 o5 @$ G9 v
  8. }. g% f' Z! s, C5 Q- `
  9. & `8 \) s+ j. `
  10. // 创建根实例
    3 X( @' k8 o$ R
  11. new Vue({0 g, _6 H( {  |. [$ C& h$ g
  12.   el: '#app',
    5 W$ m- O, s3 d
  13.   components: {
    6 W" t6 p* [* y6 D/ h" [
  14.     // <runoob> 将只在父模板可用. _5 ]9 S  y$ D- ~2 }: i
  15.     'runoob': Child
    ) [- l4 s- @* m
  16.   }7 h/ ?7 O! g0 r7 X  w0 w0 @- J$ A
  17. }); X+ v4 Y* [* J* p( W$ ?3 `8 \
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例* t# m4 L8 o* G& j) c5 T3 d
  1. <div id="app">" q) K; x  l1 S+ y9 P
  2.     <child message="hello!"></child>1 x) d+ Z% x8 H. t
  3. </div>1 `/ m6 G/ x( X  |  M- h
  4. ) }+ f9 o# g( \1 y3 ?* b
  5. <script>
    4 l* y% p2 {6 Q( W  M
  6. // 注册
    7 B8 r( f( ^$ w  T2 d
  7. Vue.component('child', {
    ! X, o7 r/ |8 U4 b/ t
  8.   // 声明 props. C/ o) M% [% u
  9.   props: ['message'],
    : z+ R, w+ [3 j* Q+ [" m! N9 T
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用' o2 v9 l! M  b. m/ ~
  11.   template: '<span>{{ message }}</span>'
    " |" O! u3 _# \5 t
  12. })
    0 g6 q) Z# }+ Q# P
  13. // 创建根实例( f' m' D, x( Y; m
  14. new Vue({
    1 S. G3 v/ }9 K) N1 D
  15.   el: '#app'8 M% k3 b& t+ k6 o
  16. })  m8 x1 N  o" J: q: r) U; _* b9 x
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
: H4 l7 k" J  W1 Z; W9 v! \* Y
  1. <div id="app">
    , R- B; ]* L" D7 {7 [, D
  2.     <div>) m; c5 r5 m( Z+ \# e
  3.       <input v-model="parentMsg">
    % _$ [: J; k4 A4 n; Z
  4.       <br>
    8 H; C" ^! p. I2 I& ?! g- O6 _
  5.       <child v-bind:message="parentMsg"></child>; F% _2 i- E! s- n& [/ T
  6.     </div>
    0 P. b$ [( m$ ^* v* I. R
  7. </div>! l' R2 z3 A- z; H6 j

  8. + Z  ^4 F6 j/ P
  9. <script>3 k) {. T. y, ], R
  10. // 注册
    - P* Z. B  r7 x/ x  j
  11. Vue.component('child', {- g6 i1 s. ]& C2 L# T4 f
  12.   // 声明 props9 S! Q9 [- k6 _
  13.   props: ['message'],
    ( f& W+ S) Y" G8 ]0 G6 F
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用( P" [- s: @, n9 }& k) e- c% Z
  15.   template: '<span>{{ message }}</span>'
    + C1 S  K1 z6 `5 R
  16. })' y; |/ G' _* h6 H+ D
  17. // 创建根实例
    1 V9 F( ~* A9 S( p+ l2 z
  18. new Vue({  _: y8 k% z1 w  V( L9 b
  19.   el: '#app',5 w$ z( `* D$ }1 Q/ z: ?& b8 [$ T5 H8 o
  20.   data: {
    % }5 u% v4 [* h4 Z5 W
  21.     parentMsg: '父组件内容'# X) x2 |1 w+ k9 F- @
  22.   }5 C5 B  u' @. h" ]9 Y( \8 x- v
  23. })
    7 I; Z+ m0 x+ u
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例/ p8 [# ~5 O% T' g& a% m
  1. <div id="app">
    2 w( k- z* L& }1 z
  2.     <ol>
    6 m6 ?4 c# `: i
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    0 Y6 [6 C6 h( R2 t9 s, X8 P4 R
  4.       </ol>% Z+ B1 x" u1 P; }- m
  5. </div>& q) ?+ j# [- {9 G0 k; M

  6. . j8 t$ H+ v. C; K0 J
  7. <script>! Y4 L) r; y; N% t" D3 }0 j. f( f
  8. Vue.component('todo-item', {
    0 H! a6 a2 b/ K# @1 D
  9.   props: ['todo'],8 ?6 ]/ g- }3 M7 E5 H: j
  10.   template: '<li>{{ todo.text }}</li>': K$ [0 j1 u+ m4 j0 R
  11. })
    ' M- K8 U' X* u4 a+ R# B) f
  12. new Vue({3 l  d$ \! ^1 V, T" {0 f& O" s
  13.   el: '#app',! r$ b9 I# P3 V- m/ h0 K
  14.   data: {3 a2 i/ D' e# t+ w- T* @2 ]
  15.     sites: [
    ! R2 c$ W" H! \: Y; h$ d
  16.       { text: 'Runoob' },
    ( v: X3 k; \, U/ s6 p; E
  17.       { text: 'Google' },
    9 D& r5 l* \+ H* H
  18.       { text: 'Taobao' }
    2 r8 a5 ]; k) D; V
  19.     ]
    ! B3 v, Q% q3 m6 i) O7 S, _
  20.   }
    3 b) x( g" I/ ]- W2 P
  21. })
    " Y" b. t4 w) H& ]
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    ! a; W! K9 E& h% T# K" j1 m; S
  2.   props: {
    6 n' _" a+ o0 \) o* C
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    ) O  j& t% K! Q$ `
  4.     propA: Number,5 L8 Z: `- W* W  {! y$ [7 C1 x: x
  5.     // 多种类型6 E% A. m! |$ V
  6.     propB: [String, Number],
    4 R8 c4 K: O( y. a* L
  7.     // 必传且是字符串
    / B$ g, ]3 k7 a( ^
  8.     propC: {2 t7 _  {2 m( K7 o* h% v& i
  9.       type: String,9 i/ q) d. B7 W: B8 L8 G
  10.       required: true
    + I' t6 F6 J5 y3 j6 R& M
  11.     },; t5 `0 u9 y: `5 W8 ]; t7 b& ]
  12.     // 数字,有默认值
    * b6 Y2 S* _6 A
  13.     propD: {
    * o# p! o" ?1 U- C- l1 x7 f3 T
  14.       type: Number,
    . U2 j  G! A5 u
  15.       default: 100
    + h, _$ E0 n+ S6 X  ^, p) v) C8 N, P
  16.     },
    6 \3 ^" F" K+ z" S* Q( ^3 d' S, P7 e/ s- I
  17.     // 数组/对象的默认值应当由一个工厂函数返回' ^. d0 O1 A, R8 k  s3 O1 K: E# E# s
  18.     propE: {
    5 N3 c7 K* q( n$ I
  19.       type: Object,
    : R* w3 d4 O1 A
  20.       default: function () {' j- ~- ?+ c" G/ u5 G
  21.         return { message: 'hello' }
    $ p3 p4 _, E( z
  22.       }
    1 M7 Z6 k3 F: H3 \
  23.     },) J5 ~% o1 g7 B# B
  24.     // 自定义验证函数2 h; h- J+ G  W+ O  {- M3 [
  25.     propF: {6 L3 r- u0 C0 M  K2 f7 h4 H
  26.       validator: function (value) {
    6 U5 W# X9 x2 \3 r# n8 v/ o
  27.         return value > 10' Y. t7 G" L9 F9 k
  28.       }
    : D; @. H% m, m; N4 c7 M9 {- }
  29.     }% B' Y6 L! V4 }$ z
  30.   }1 t9 Q$ W+ n1 s& b2 o: l. u& r# J9 ~& v
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array! f2 |7 t) w! x
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件+ w) V; [1 z: G0 W) a% X  m" k- S
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
$ Y! r8 P  z  c9 ~
  1. <div id="app">
    / O# e$ S- M7 O% F* ~. p! x
  2.     <div id="counter-event-example">
    0 G8 F) l/ ^, M" E4 n8 M
  3.       <p>{{ total }}</p>
    5 Z# ]( X6 `7 R0 `3 w, k9 A
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>1 g1 W3 z$ l! l7 B1 x+ K7 @
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>' D7 U: m. i: D! C7 i3 T# N
  6.     </div>
    & I, n3 D! I5 e( o- s+ _/ G
  7. </div>
    2 c0 s/ x7 S2 a2 K

  8. * m/ x: L5 U- d
  9. <script>+ B  ]& @/ v9 p) ?, q
  10. Vue.component('button-counter', {; _/ X+ O8 H& _: K" r
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    , w; q9 M8 C) K/ Y: ?  @
  12.   data: function () {
    1 Y, ~+ t6 ~  L  c% P  X
  13.     return {* P4 i0 T, T0 {6 f( K' o
  14.       counter: 0) X, b* ~5 J8 E6 |- ]) r8 }3 z
  15.     }8 h2 l+ n9 L9 w9 E/ |' z2 N
  16.   },- i1 O; @1 f- ]4 w; [- Q
  17.   methods: {1 @( D! @4 H6 U- N# N
  18.     incrementHandler: function () {/ K2 t9 Y2 ^: e$ E
  19.       this.counter += 1
    6 v4 @: K/ H3 L, U. f5 L6 @6 n
  20.       this.$emit('increment')
    % Q, |' ~4 w, T3 g2 V
  21.     }
    , ^" C2 ^3 j* z3 X  [2 h3 R1 p
  22.   },
    : o9 X1 @( a- P% _; D. b
  23. })" l  ]7 ]% t+ K0 T
  24. new Vue({& o' [$ C& w9 y& M
  25.   el: '#counter-event-example',
    ! b: X6 N6 k) U% x. @" P& D/ _7 T
  26.   data: {
    $ ]  O% `1 k- X* `) a
  27.     total: 0' L, _8 f' W" U7 Q1 C
  28.   },- w8 j) W/ }4 e7 G; `& A
  29.   methods: {; E4 T, f& b$ C+ A
  30.     incrementTotal: function () {+ Z- V5 ?4 o5 {" u
  31.       this.total += 1: I/ v9 r. B; k% B9 I$ Z, q
  32.     }: X- N4 M0 A3 K( Z! i% b% L
  33.   }7 P5 S  e* s) {0 c# Q
  34. })
    - I* l* i! S5 n
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    4 r: L9 U! y- W* F# [
  2. Vue.component('child', {8 O5 J0 R$ @7 S
  3.   // 声明 props
    ; O4 p6 ~; P' |% L3 V7 B
  4.   props: ['message'],; B) b( G4 l3 p# u+ A/ P0 L5 q
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ) L* E* K8 |- S# j
  6.   template: '<span>{{ message }}</span>'
    6 V8 J4 g# R4 {6 r. w7 p* B
  7. }); @; z5 ?; W$ p, I; J
  8. // 创建根实例' c! U$ S% i$ r1 k: B8 U
  9. new Vue({
    - u, g% L' U( A( [5 |
  10.   el: '#app',
    ! w; c6 H+ ?5 [
  11.   data:{
    9 w) ?; `* e6 {- Z  F
  12.     message:"hello",
    ; t" m4 A: N8 l6 G4 n# l& f
  13.   }
    + X3 o7 c$ y% G( R" J. E
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {3 g1 ?- u: ^& A1 q4 p7 ~
  2.     incrementHandler: function (v) {& G1 s. S! i! c  F. o3 K( x3 }4 [
  3.         if(v==1){  G; w8 f/ M3 d1 U3 J
  4.             this.counter -= 1' ?  k2 r/ k9 P- e: o. S  L# \
  5.             this.$emit('increment',[1])
    % ]& Z7 Q& ]# b, N9 \- b
  6.         }else{
    " r: B5 {, M) F
  7.             this.counter += 1
    - L* x  B6 x" w# ]
  8.             this.$emit('increment',[2])# X7 t" v8 W4 `7 Q$ M5 l$ r
  9.         }
    9 Y% i8 o* b: ^6 v# B! P
  10.     }
    1 p# O& V! F+ Y; A
  11. }
复制代码
. u2 k8 @9 n3 v  p6 c4 E$ U( v
. t8 l" u1 r  n5 T9 O: D9 A# g
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-16 19:02 , Processed in 0.057693 second(s), 23 queries .

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