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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

& X) T' Z" w- n' g
  1. <div id="app">
    ; w! a; _9 `  d9 I
  2.     <runoob></runoob>) l8 k  v, a% U8 s; X* x8 L( r
  3. </div>
    ; z; u) U8 c. z5 B2 H# ]8 O
  4. + z; |2 G7 l+ K) }) s
  5. <script>" q) |3 b/ V% k( S, L8 I5 d
  6. // 注册
    # P: F1 z3 x0 W
  7. Vue.component('runoob', {0 F) v" d; ^7 b  f4 {
  8.   template: '<h1>自定义组件!</h1>'
    / ^& M: h% m; u, q0 x
  9. })
    * U6 D/ Q0 U, _# R
  10. // 创建根实例& I4 d6 i1 g: e8 G
  11. new Vue({+ @/ F, L9 S& y; ]! e& Q
  12.   el: '#app'
    ( ^" S) O& g; G3 P7 o5 w# k
  13. })
    $ [; W" B9 h& z1 }
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
7 X) @) v& o7 y! h/ V! E4 Q' K
  1. <div id="app">" n% s) ?- h9 F
  2.     <runoob></runoob>+ c. X! S# W. k) L, G
  3. </div>
    ( ~3 q. }% Q5 j7 W$ S6 k
  4. ) G* u) z% l# R- K+ l! s* N" {
  5. <script>4 I  \5 W! `8 o% p7 I$ e# ]
  6. var Child = {
    ' M$ D" w5 `- v, H- W
  7.   template: '<h1>自定义组件!</h1>'$ J: ~$ x4 o0 c- H' _5 |, _& g8 q
  8. }2 g  @" h2 O. |, j5 W5 F' R  J0 R' Q

  9. $ z9 |2 a. S' U8 ]2 U2 D
  10. // 创建根实例
    9 M$ J0 n5 n5 a% Q" ]& B" v, i
  11. new Vue({
    * i, O1 @* r3 n- u/ n, _
  12.   el: '#app',! D" F5 F# A7 w& x" u: f( K
  13.   components: {& m( @# m8 \8 Z2 i
  14.     // <runoob> 将只在父模板可用. ^+ _$ g+ ~8 f8 P8 a
  15.     'runoob': Child9 y* U7 d& J) f3 j& U' a
  16.   }
    1 H- l& b1 o, V0 |
  17. })" _6 }9 b5 p( x
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例5 z) A( y: p2 X/ o* h, h) L
  1. <div id="app">
    ; V; Z3 ?  H4 R% ?5 y' y
  2.     <child message="hello!"></child>
    & ~( @+ L; C+ N! `5 }
  3. </div>
    1 M& S7 T% L$ k7 w$ A$ W
  4. % }# _- E+ Q& Q
  5. <script>
    5 r7 s1 j- q. C
  6. // 注册/ @+ v, F, }- P& R9 r) K7 H5 W4 P
  7. Vue.component('child', {0 Y0 P" G: |; J( k9 b2 b: {6 ~" C# W
  8.   // 声明 props/ z9 A# w& o8 X% k5 J' o2 ?
  9.   props: ['message'],  B: Q% u0 M: u0 ], v: k
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用0 m) C1 Z& b: E: O4 [
  11.   template: '<span>{{ message }}</span>'2 w$ J9 _  ?! T
  12. })2 i  {5 q7 G9 I3 T
  13. // 创建根实例; F, O- i8 E& b, g; I
  14. new Vue({$ Q. l2 M3 }! D3 W0 @2 \6 V
  15.   el: '#app'
    " }/ ]2 f# h; u. G& N3 V
  16. })
    5 _' {. G' Q& E; c+ |" Y& }' ~
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例1 o( X% s8 r! P9 W2 b9 b8 P5 f
  1. <div id="app">
    " n8 }- v0 h/ [: p5 H9 d
  2.     <div>% B3 i2 D% O: p5 P7 h
  3.       <input v-model="parentMsg">
    # G3 s" e. g! G0 W1 T
  4.       <br>
      E1 V! K4 c9 K# K& Y6 |
  5.       <child v-bind:message="parentMsg"></child>2 |' W1 @+ M3 M7 J
  6.     </div>+ \8 b( d* F! G* r/ r0 R
  7. </div>
    8 \0 u0 m  L1 T2 u7 X' S4 b$ n
  8. 4 J) k/ b3 ]- b
  9. <script>
    ) {5 v7 s- q0 D, V- n2 z1 l/ Z
  10. // 注册
    # o* U  l6 |; I1 @
  11. Vue.component('child', {
    " P9 ?3 Y/ M+ u$ [  e% N% I% D/ Z
  12.   // 声明 props
    . ?" ~) O( j1 t, X# e  q4 L4 f  R
  13.   props: ['message'],1 _- ^8 f1 M- f% x0 [
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    & i" P/ Y1 T1 ?- p% e
  15.   template: '<span>{{ message }}</span>'
    8 A7 f' y5 \- Z  H
  16. })
    . b* m; \# _' E- P
  17. // 创建根实例
    9 S4 m( z+ P2 p  x- V
  18. new Vue({( B* w5 P" k1 a: F! b4 j! v0 u1 `
  19.   el: '#app',) B# r3 M) r/ N1 Q( S# }
  20.   data: {
    4 \- P6 f2 q; h* M' C2 _; M$ P$ I1 S
  21.     parentMsg: '父组件内容', `, s7 z( ^" h
  22.   }, ]5 B. r3 Z- m; C: X" P
  23. })
    ' I( w0 a2 y" h: q
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
% j/ ]6 T2 r7 y/ T* o. h
  1. <div id="app">
    + ?' _! a6 |, \$ O
  2.     <ol>6 E0 J2 S6 D' l8 m
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    ) S* |6 c! k8 u  w
  4.       </ol>
    4 P$ S/ C" b- R2 o
  5. </div>
    & [- X: ~. T, B
  6. 7 c) l4 q7 d2 ], S  C
  7. <script>
    ) C3 ~0 m6 h0 S" e
  8. Vue.component('todo-item', {
    1 q; }' r9 ~; s6 u: c6 C0 a& U0 A9 e
  9.   props: ['todo'],, d- c* @; Y: Y/ S2 W0 E
  10.   template: '<li>{{ todo.text }}</li>'. y, R" }) _4 \4 j1 D# Q4 o
  11. })
    5 U8 j: t1 W/ [; X8 |+ n4 K: w- O
  12. new Vue({2 Z- h+ f0 t7 B$ |  Q
  13.   el: '#app',
    1 v+ G3 \- \) N* Y/ x  U: o
  14.   data: {( _( x  c6 A) g* g5 e
  15.     sites: [
    1 `: k8 T, n. [: r, g& q$ ]6 x/ m
  16.       { text: 'Runoob' },
      }# [3 o  A* P5 Q; g$ }$ D9 j
  17.       { text: 'Google' },
    5 {! B; y7 g# F$ A( R
  18.       { text: 'Taobao' }7 {) J2 T/ n/ r% k& k& J
  19.     ]
    2 G3 V: v+ X: {6 }
  20.   }% n8 A* P5 ^: t0 E: j) c4 h
  21. }); Y7 ^, i9 ?, n* [5 K
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    " P$ i) w3 K" ?9 m
  2.   props: {
    % Z( Q9 v1 C. G8 Q
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)5 C) @9 z7 A4 e  w
  4.     propA: Number,* Q& q& e7 J7 t( S# f. L. Z
  5.     // 多种类型$ O# P. L5 z# ]7 j1 m- u
  6.     propB: [String, Number],
    : z) q' D, ~9 H9 z! l6 p4 s. I
  7.     // 必传且是字符串( ]& s5 a" l; S8 ~+ P
  8.     propC: {8 V3 P0 M, B) w% p: y- T# a
  9.       type: String,: C/ N2 r& g) c) Y, u$ ~
  10.       required: true
    3 t2 H* G5 p' Z& K& S2 W
  11.     },- D& J+ E: m2 y6 F% F
  12.     // 数字,有默认值3 h; ?) x+ [5 y1 d8 [2 {* u
  13.     propD: {3 w! [) e6 I* k6 L
  14.       type: Number,
    4 B8 H( O! J4 r1 ^2 W* ?- G2 Y
  15.       default: 100& h- B) B! M% H3 b5 n: l6 K6 Z
  16.     },+ ?5 \. m! `1 O, t- l
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    6 A2 Q" ~2 I  d9 \
  18.     propE: {
    - `, g7 m% s/ D8 [. n/ p
  19.       type: Object,/ e, y2 K! C$ G: X- `1 y
  20.       default: function () {9 ~  \4 y$ B; X
  21.         return { message: 'hello' }
    8 M1 o* j6 b) _' N
  22.       }
    5 M- C  r; d; u- K3 N0 U
  23.     },1 M, \2 S" @# ~
  24.     // 自定义验证函数
    + ?7 w% j& C0 d& t! P
  25.     propF: {) L8 S0 @. [. ]! n' F
  26.       validator: function (value) {$ w5 {. C6 \" |) \; z
  27.         return value > 10' }9 T# }$ P2 u1 P" I
  28.       }; Q$ L6 Y' k( D
  29.     }- }7 j6 b1 e4 p0 }# H) u
  30.   }
    & f2 f( }) t, C, A
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    # t8 b4 g3 w9 n. H  V, B5 i
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    8 p1 Z! ]0 D7 u
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例1 S3 d# d$ g, U  F1 l+ n) }; p
  1. <div id="app"># v0 e' K( ]3 T3 q1 W# M
  2.     <div id="counter-event-example">
    $ ^/ `) W$ ~* B8 A9 I- P
  3.       <p>{{ total }}</p>
    * l( v% s1 ^! H( E
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>: t: h: v$ n: Z# P
  5.       <button-counter v-on:increment="incrementTotal"></button-counter># p9 C# N! N$ z0 {, i) }5 p+ C3 L
  6.     </div>. L$ [) Y+ Z8 i7 M# c
  7. </div>4 L. {/ v# z: C! A
  8. 8 A& v  i$ @& r7 |. Y4 I0 T; `8 u/ ~
  9. <script>4 \1 s# l: q5 r: x
  10. Vue.component('button-counter', {
    ; d5 d; j2 T; {: S2 m; t
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    % J! e( A0 [: o8 Y( J  P7 n
  12.   data: function () {8 R3 G5 M/ K/ h; Z( T' C
  13.     return {
    " `/ E* W! c" W# G4 K; }
  14.       counter: 00 c' A+ }3 l; ]7 X1 \
  15.     }( A; _* H$ i( y1 |, s' k( W; x8 U
  16.   },/ a$ J% B; t( @; _* n/ S" @; D
  17.   methods: {; ~6 I1 V1 p1 z, j6 v
  18.     incrementHandler: function () {
    ' @1 ]$ {0 a- a
  19.       this.counter += 1. q  t. r& x* L3 [
  20.       this.$emit('increment')
    , {7 A% u: f+ n# _; O0 c, g9 g' L0 b
  21.     }$ I* l9 n5 L9 d4 r/ {  }% i
  22.   },6 x, B, W& o3 u$ S3 I% Q2 k
  23. })3 M! S( T) n& a# p& Q% X" a0 }1 w0 q
  24. new Vue({
    # |# ]* W- h; g' J' ]8 s5 O' G9 a
  25.   el: '#counter-event-example',( j1 f1 M: X2 z* O7 E2 S1 ]
  26.   data: {
    " X) C$ p6 Y7 A" e7 g
  27.     total: 0
    ' Z( D5 ~( b! G* H
  28.   },, @& x- q' M+ \8 Z
  29.   methods: {1 ~7 X" J: Q8 s5 d7 o# R
  30.     incrementTotal: function () {
    + O4 B3 o5 }  S( P; |7 ^+ ~
  31.       this.total += 1; G* K8 Z7 r8 p& y5 ?. p9 \
  32.     }
    0 ?, @- C! X5 {- l7 N: Y
  33.   }
    3 v% s2 {9 ]; B: p" v" C2 ^# D( F8 G; B
  34. })6 S/ g8 B. A3 x9 W& f8 `( y4 e
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册2 K, m  Z( H3 b# `# P
  2. Vue.component('child', {
    4 l; }7 b- L  @8 ]: W, k* C! w! Z
  3.   // 声明 props$ X% Z7 R: a. w! w
  4.   props: ['message'],! |/ V4 R8 N$ O# t% b0 [# N
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用/ J! `! |5 G+ h& F7 b
  6.   template: '<span>{{ message }}</span>'
    + V- j1 [3 X8 I, r: v$ g
  7. })4 Y- A. h+ u/ S# y$ _* \
  8. // 创建根实例  z9 w9 w4 ^2 H; u4 g
  9. new Vue({6 Q! `' p! r; x  O
  10.   el: '#app',  L$ f: V* ?/ Z# ]# p
  11.   data:{
    ! R# x; i) k% J( S: s$ x
  12.     message:"hello",6 p. B( c' K7 l" \3 Y+ w0 ~
  13.   }/ z8 a" F. ^' z! N: \) j
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    2 y. N% J9 K# d# q9 G: v- k
  2.     incrementHandler: function (v) {7 F# F/ n5 o  A# O* Z3 H) j6 l# T
  3.         if(v==1){" Z! ^5 d, m4 I
  4.             this.counter -= 1
    9 J2 v+ [3 e! k6 [3 [. w! ^
  5.             this.$emit('increment',[1])
    : l# _) I7 O8 D: t5 A3 k
  6.         }else{/ H7 }! R5 ]; ?  b% P  s% [' H# t
  7.             this.counter += 1) _, {) s/ |- e% A7 {" G; x; s, d& ~
  8.             this.$emit('increment',[2]), u4 E2 O" m. _6 q+ k, V
  9.         }
    ! w: h% Q' u* Z+ U
  10.     }
    : d# D$ U) r0 o  ~& c
  11. }
复制代码
* _2 a3 E$ Y; \, L9 x
9 }' \0 {1 }8 z* |" C+ i
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-16 20:38 , Processed in 0.102852 second(s), 22 queries .

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