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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15217|回复: 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,并使用它:
/ l# \+ F. M" @; d# F
  1. <div id="app">2 b# s' A7 J8 p3 x7 v4 q
  2.     <runoob></runoob>
    8 q" z9 d  N. Q. }
  3. </div>
    ; `. a3 H# _5 v; Y; u3 t

  4. : Y: P- l8 c2 R6 k7 `
  5. <script>1 T$ g7 ^: X3 f; g
  6. // 注册. q) p' X' Y! T7 @% h
  7. Vue.component('runoob', {
    ' U) P: |0 v: t  d5 m# c
  8.   template: '<h1>自定义组件!</h1>'; v# n7 M, J( q) g0 j' H
  9. })' b" e4 R8 g) a( R* S0 j
  10. // 创建根实例
    ( ]0 a1 _! Z% L
  11. new Vue({
    $ [& e. }3 d$ N9 `* E1 C6 E
  12.   el: '#app', I2 w. ?% a8 T8 a8 w1 }" H1 v
  13. })
    ( x# X0 ]) Q2 Q, `: C
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

, N% H) x* W8 Z" b4 ~3 L+ k, {% v/ Y9 v
  1. <div id="app">* n, Q3 u0 |' G
  2.     <runoob></runoob>  c& U9 w: K. {+ S) `; K
  3. </div>
    $ G  Q  d& v$ s! C
  4. 3 A) T$ c8 R7 s7 ^* B$ }/ {# q0 v# ]/ l
  5. <script>4 l" }: I( O0 ?6 P  P: S. Y8 [
  6. var Child = {
    * X1 n- N. ]& F, Q' q
  7.   template: '<h1>自定义组件!</h1>'
    ( T# D' Z/ W. i
  8. }/ c- J& ]/ [7 g; G+ E) d

  9. ' q. [1 O' k+ g  ?
  10. // 创建根实例
    $ A" [, K$ F( q/ u
  11. new Vue({1 E* R9 }7 h- R% l
  12.   el: '#app',. @# H0 X, N- {- c% E
  13.   components: {
    4 t, ~% r$ ^' c! H' u1 G7 h; }
  14.     // <runoob> 将只在父模板可用: }9 m! D1 {9 q! \! k
  15.     'runoob': Child
    * S! G0 o  O; G' @
  16.   }
    % U. p* c% w. ^( d( j" m: I
  17. })8 ?1 s! t8 _! s7 S/ U, N+ N+ D
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
$ W% y3 k% r' D+ Y+ _5 |( @
  1. <div id="app">/ n# N$ b7 \5 U6 r8 G
  2.     <child message="hello!"></child>
    ; E9 E. O1 l# L) d$ E  q$ j5 t9 U
  3. </div>; I1 o+ Y4 V( D$ Q
  4. : `3 @% U+ C/ ~$ o% d# I
  5. <script>4 B* q) u1 v& r) ^) n5 G( ^% I/ C
  6. // 注册9 Z, k) L5 c% P2 g( e6 R
  7. Vue.component('child', {/ L/ I; H, D+ n5 F5 X
  8.   // 声明 props
    * B( }* d7 q: H0 H1 W) q3 F& w
  9.   props: ['message'],
    * K  f0 }7 y; k7 g7 x1 M% y
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    . t, N# @" w! B0 ?. c- d1 u
  11.   template: '<span>{{ message }}</span>': l0 _8 c, l1 c$ N: K9 E$ k
  12. })
    + d* `" e" Y, B0 b6 w) r
  13. // 创建根实例  f7 g8 \" L0 A3 t
  14. new Vue({' G4 T4 M' w# C' I3 W
  15.   el: '#app'! [; J% p, P5 Z  z6 K5 E
  16. })
    $ k% W% {. {! \1 J
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
2 Q8 ~; G; G( Y1 V0 t! v& e/ b3 f
  1. <div id="app">  ?) h$ ^( |6 U" A7 I) g
  2.     <div>
    & @4 k  f4 q- u/ t3 c; v
  3.       <input v-model="parentMsg">
    . E! E$ ~7 O3 h8 _1 D) u5 Y
  4.       <br>$ F4 m* X" ~1 i
  5.       <child v-bind:message="parentMsg"></child>
    1 i  Q8 s: r4 _5 l. r  Z7 h
  6.     </div>
    $ D7 m* h% J+ }1 }
  7. </div>
    ( \. F! T1 b' l- Q5 z
  8. 5 l! ]1 U6 n% R* r* R' @" \
  9. <script>
    : \% v7 [/ `, h- E9 q( |
  10. // 注册
    . k6 |% y! M7 v" }4 a& n" f
  11. Vue.component('child', {* ]& E' u* b- w, a2 {
  12.   // 声明 props4 e& E" M7 a/ ]/ |# |6 z
  13.   props: ['message'],& m( p4 {, d$ L* ]2 m! q& ?) L
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用' n! C6 X' T* W' S! k- N" A! S3 |
  15.   template: '<span>{{ message }}</span>'
    2 h9 e) e+ m; E" A/ V
  16. })
    & `' h" Z3 N% C' ^
  17. // 创建根实例4 U  f: y- }, y
  18. new Vue({$ w" d2 M% _5 y" o5 r
  19.   el: '#app',
    * `& y2 @) \: ~  Q1 ?
  20.   data: {0 [5 R6 ?! k( O1 a. G
  21.     parentMsg: '父组件内容'3 {. a' A# q# L! _; O! U
  22.   }6 a) |% I# c; ]( Q, [8 f
  23. }). F+ `! x$ N6 J$ n. x
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
& y% }" i4 ]- [
  1. <div id="app">9 I% I9 r6 O* p; d0 m
  2.     <ol>
    + ~# g) ]* k4 Z
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    8 s: T6 E/ Z: i+ X( {
  4.       </ol>
    1 M/ T! _3 ?1 W& d1 }. Y
  5. </div>/ @7 o$ ?+ h2 w# X2 m# o
  6. 0 a5 ?% Z, ~9 P
  7. <script>  J$ ^5 G* J8 ?
  8. Vue.component('todo-item', {
    " W$ Z; Q  I! J
  9.   props: ['todo'],
    7 H8 V' O. {5 y' j( h
  10.   template: '<li>{{ todo.text }}</li>'
    + T: F# j3 h. U2 t) Y
  11. })! p. p' e8 H( E1 ]
  12. new Vue({
    $ r2 @, ^$ N3 U- U. w( F+ L$ I
  13.   el: '#app',
    4 L+ Q( F1 Q$ `
  14.   data: {% s/ Y! O2 z' c& q6 `
  15.     sites: [
    $ d9 M2 p% G! s1 g
  16.       { text: 'Runoob' },
    ! ^, x) Q/ A- H& N
  17.       { text: 'Google' },
    6 @8 S9 U% I: \0 e# M9 T
  18.       { text: 'Taobao' }
    0 l% W7 J. V0 N" B1 @4 @# E6 z2 _
  19.     ]
    & E! N3 B4 S/ s
  20.   }: z9 ?3 Q+ R; N3 l3 j) R
  21. })
    ! a* i/ D9 ^) c* o( d% {
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {$ F8 T& k) X, k7 U+ ^
  2.   props: {1 T  Y1 s+ v1 H* N+ n" j
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)- h) O; g# T( Y  v2 Q
  4.     propA: Number,
    / e8 q! \1 C/ h
  5.     // 多种类型2 V, o. C' o/ `0 U  T! G; ]
  6.     propB: [String, Number],2 g' v  q9 f3 u7 I* a6 e( u% @" _9 M" C
  7.     // 必传且是字符串
    4 @0 w2 ^) C" F+ _
  8.     propC: {
    5 T9 q3 S  ?8 Z6 B
  9.       type: String,  R3 a! O; s1 B8 T
  10.       required: true" v2 w) t* g. ?- i$ H
  11.     },
    3 H& r% m% w* s0 A# Q: [7 h" H% Y
  12.     // 数字,有默认值* q5 [: Q9 I; q$ c6 S
  13.     propD: {$ I* R* e1 U* l8 u8 `
  14.       type: Number,
    0 U! S' u* F* b5 l
  15.       default: 100
    9 y# l8 E+ W6 m/ ~5 Y1 |) A# p, }+ s
  16.     },
    7 n, M) O/ g- ?. X
  17.     // 数组/对象的默认值应当由一个工厂函数返回$ V0 }6 K" h+ |( g9 X1 R  R) J
  18.     propE: {! ^' _, U1 N# U
  19.       type: Object,7 O4 u! P2 w5 {* r# c7 T
  20.       default: function () {2 t- g  s! f* J5 S* g# r7 o- d# q
  21.         return { message: 'hello' }/ ]! S3 T% S- ]8 T- B
  22.       }  l' v# D! G9 G( q
  23.     },
    & n0 z9 D5 g# D  U0 O
  24.     // 自定义验证函数+ w5 \( ]- X; z! V
  25.     propF: {' F; |" D9 E, {3 t
  26.       validator: function (value) {
    1 I0 ~( g4 {7 `% C
  27.         return value > 10, F0 U8 k6 o& j; Q3 h
  28.       }) M4 w7 s: s2 s0 r6 C+ j
  29.     }
    ( K6 W( }  o' x3 \0 U8 \
  30.   }2 x( z; |- D& P# m
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array$ M; A! h6 N' o% }
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件0 }# N% ~3 Y, q7 V
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例5 u& {" u% _1 U% X; h: Z$ p7 J
  1. <div id="app">: u& _2 _/ v: D0 i& a0 {+ y- C
  2.     <div id="counter-event-example">
    . y) w3 b. K' U% k4 E; m
  3.       <p>{{ total }}</p>
    ' ^2 p7 U, p- F* W  q' E
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>. P8 r4 z7 D- n9 ^$ H" J. j* M
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
      u5 F1 P* L/ J# q! B+ q
  6.     </div># V6 Q" F' M+ S0 H( V! C7 @0 Z0 ^
  7. </div>/ H% V' |, m7 e6 J0 o

  8. / R3 O7 L7 r/ ?, p$ `5 j/ `
  9. <script>
    8 _' h) \  Q; {( Z# f1 M0 }, ?0 x) J
  10. Vue.component('button-counter', {9 V' P; p* v" L) [3 ~! @, A, t3 f
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    9 n$ a4 }* Q( h% [9 W
  12.   data: function () {
      _0 g( X( h; ]
  13.     return {* l  N6 Y: U) ^
  14.       counter: 0
    ! z  _# @5 h0 v$ ?" P$ i
  15.     }/ ?" E, W; v! X; H5 M6 H9 [  c* {! v
  16.   },& X9 B3 x; {  `; D3 b6 T  z- P
  17.   methods: {
    5 b: _% ~1 l2 c/ r/ y& L
  18.     incrementHandler: function () {
    , D+ {- A$ }- j) A
  19.       this.counter += 1) M2 w% L9 _% ~+ E: \
  20.       this.$emit('increment')
    ! }3 n- V( [; w# t5 f1 U+ Z2 U
  21.     }/ h. g( q8 l5 o' ~7 _& v) b
  22.   },4 B# ^6 K& [0 [/ _
  23. })
    7 b1 b) m" z: `/ J7 h
  24. new Vue({
    : _6 q& i( W" }& a
  25.   el: '#counter-event-example',
    ( v/ O! P4 a4 T. ^2 {6 _
  26.   data: {: F6 w9 U" n( V( `6 {
  27.     total: 03 x, J1 ?" h4 v: @, p8 U6 N
  28.   },
    0 p, Q! o, z4 ~" }
  29.   methods: {
    ; y) }; a' k7 d/ x
  30.     incrementTotal: function () {
    : a% B8 D3 x& `) c- N  F, X
  31.       this.total += 1
    6 |+ M. J4 b" c0 o, C! Q( J
  32.     }5 B, l" g* ]  B; ^* |
  33.   }
    $ b- C+ f! x' l1 H, d
  34. })
    1 }" Z9 V  V6 _5 J8 v
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册* l6 f0 t* B+ w4 u) S6 x5 X2 t" P# z
  2. Vue.component('child', {$ T0 E3 p& D2 a; s2 ~1 R
  3.   // 声明 props
    ) O: o: J- N' |0 j' Q; s9 U7 s7 v
  4.   props: ['message']," t8 m8 {7 P' ~  H$ d0 D
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
      b( I& [# d; W3 }  t% P
  6.   template: '<span>{{ message }}</span>'3 S* B2 B( p8 \8 ]  w
  7. })7 r' D; w$ ?% B; ~7 `  d- ]) \* G. s
  8. // 创建根实例2 M7 v6 z' T# a
  9. new Vue({. ^# r0 ]- ^- n
  10.   el: '#app',
    " P, R9 `: b( d1 d
  11.   data:{, Q: n: T+ _, x/ G: \  C$ [8 }- q6 h
  12.     message:"hello",
    , n4 i( I! t0 l- a; M5 Z
  13.   }
    7 o) _/ p, {: o/ _6 I
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    : g. y! [. j7 L7 O
  2.     incrementHandler: function (v) {
    ' v2 l5 h! r6 l6 R$ ]$ b" {
  3.         if(v==1){
    0 c, f! v% u' H" ^4 _# u
  4.             this.counter -= 1' s7 T% R' M+ p. p6 K4 q
  5.             this.$emit('increment',[1])
    * r# B. |$ n* b% Z) N  i. W6 `
  6.         }else{
    / `# t( C* m$ g
  7.             this.counter += 1) v) I, R9 T8 ~( i
  8.             this.$emit('increment',[2])# M0 q3 T9 q6 H% H
  9.         }( K0 Z6 x- [' i# \) V
  10.     }
    * R  w$ O/ Q5 f' R: L# T) N
  11. }
复制代码

% E) [2 R9 p. o* P4 T1 M, T1 A: `  |. H9 c
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 19:01 , Processed in 0.080965 second(s), 22 queries .

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