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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15826|回复: 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,并使用它:
! M7 ?5 V  w' l6 Q! M
  1. <div id="app">
    : ^% @) o" l3 `6 ~% t3 a
  2.     <runoob></runoob>
    1 H1 k% S* I, @4 y
  3. </div>  h6 ?; w" }" i( U
  4. ! O8 k) K  f7 b% J; j
  5. <script>) E; N7 s, T2 l  }+ v, F
  6. // 注册
    ! U1 f2 N0 X* |8 Z
  7. Vue.component('runoob', {# X6 C* X  G+ [* N* j
  8.   template: '<h1>自定义组件!</h1>'6 Q/ ]7 ~" j6 o3 M7 g
  9. })! p) ?; z4 l# N' O3 b! ?' L
  10. // 创建根实例& Y9 ]0 [! R/ e# S+ i" b: J2 V
  11. new Vue({
    $ K/ X3 r: K* C: P/ Q
  12.   el: '#app'; V0 w4 K+ c5 ~, c, k5 z
  13. })& ?6 m: i  j8 B# W8 }% j  V
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

+ g6 G8 g. @% \/ `  K# [/ N* B
  1. <div id="app">9 j) r& ]' R) F) a2 x
  2.     <runoob></runoob>
    " W2 {- t. j- b0 y5 P/ `" V8 r- _
  3. </div>
    " `" O5 s- C- N( ]& X8 O- Z
  4. " j8 A  l$ Y& G4 j$ p6 }* [
  5. <script>$ q7 U: b( |  G. Z0 u( s
  6. var Child = {
    6 t1 V$ p+ y; j
  7.   template: '<h1>自定义组件!</h1>'
    . T% [, z6 |" N7 H& w% D& S
  8. }, r" y+ G) E5 s: \/ l

  9. 6 Y# C* j  Y3 s. l: G( f+ c$ b
  10. // 创建根实例
    ' T* c! w8 {8 I7 V
  11. new Vue({
    ( W1 R- ~2 e6 D# l( ]
  12.   el: '#app',7 u5 R0 Y* }4 U1 s
  13.   components: {1 B9 L! H8 p) v1 d1 D3 R% l
  14.     // <runoob> 将只在父模板可用# [0 @' R  p( m! F3 \* m, m" u
  15.     'runoob': Child2 j. c8 a7 J5 w1 \
  16.   }+ s/ x5 _: P' K+ l2 e8 H- o/ e
  17. }): ]3 e3 n/ [8 }) x
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
6 p- I# p& `# F% Q& L5 z! x7 {2 c3 H2 y
  1. <div id="app">$ B' m& M8 W6 [) h- Z0 S8 d# O9 P
  2.     <child message="hello!"></child>2 p. Q: t5 c& G) z( h, W/ F& u
  3. </div>
    , Q/ G9 _7 H! q' l5 `8 p
  4. - c& l. y* n" G+ H2 F8 {1 p
  5. <script>( W" N* {8 O( T! d
  6. // 注册+ ^9 X* i/ q2 E3 \0 I
  7. Vue.component('child', {/ S! O5 K3 ]/ R6 Y; H# K8 l
  8.   // 声明 props; `6 G& u( }5 u" A
  9.   props: ['message'],5 b8 e% X* {8 J9 X
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    $ k( @$ t3 \6 P( L
  11.   template: '<span>{{ message }}</span>'
    7 i7 @  ], K$ @; H, h: k3 z  }# v" a
  12. })0 f  s8 n" K- T8 {( T
  13. // 创建根实例3 C: |( Z) K7 H4 T; l% v- s
  14. new Vue({, ?" Q- e2 ?$ F! U$ w
  15.   el: '#app'
    3 b. _2 _+ T1 p8 g4 G
  16. })
    0 \; t& I0 Q. ~$ G3 k  d% \. o
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
4 \) D- g4 O5 S5 g: q) B6 U
  1. <div id="app">4 J; w. h5 W! W; B
  2.     <div>
    & m  ]' K- s5 Y7 {: |) C6 `
  3.       <input v-model="parentMsg">+ F6 `! x% Y3 @) s
  4.       <br>
    , ]' l- o) \# o6 E# `0 z" d
  5.       <child v-bind:message="parentMsg"></child>$ Q" T' I# D# L
  6.     </div>
    ) U0 h! J4 \& r7 \3 D7 N4 s
  7. </div>
    / w4 o. V" W; D5 _5 @+ l$ W

  8. 3 Q- s1 `/ p6 q4 Q1 I% E
  9. <script>+ I0 g7 F* w$ `
  10. // 注册
    , P0 P. I- ?2 H* [' y
  11. Vue.component('child', {+ p7 M& p& a( G- e& k+ q5 Y) t
  12.   // 声明 props3 |# m4 K0 g& Z, C: }
  13.   props: ['message'],) L/ ?# H; }& y( e! M
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    9 @; ]+ ?. M$ Q8 L) n7 \
  15.   template: '<span>{{ message }}</span>'
    ! [! Y1 H1 X2 K6 a( X/ `
  16. })6 \, R  F$ P& H$ v0 u% |! _, m- l
  17. // 创建根实例6 j6 t. x# d. Y$ X  k
  18. new Vue({2 s4 L; R5 }9 x; f* Z8 f% A* ~
  19.   el: '#app',$ J: \0 g9 X4 C: C1 C) h0 M
  20.   data: {
    ' D- g+ U% _" e1 [; _
  21.     parentMsg: '父组件内容'
    8 t1 ]3 L. C% W- c7 f' k5 Q
  22.   }  L* l* ^- Q  _& d& J
  23. })
    2 t! d& d0 {( h
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例- F) C; r6 _9 k# L+ v4 Q, G0 Y2 D
  1. <div id="app">4 o5 T4 t4 V' c3 A
  2.     <ol>
    * ?- u9 O( C# q8 N" q
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>3 u+ }# V- N& J7 y& t
  4.       </ol>; E2 f+ `; h" s+ N: ~' Y; y# r" P
  5. </div>; j1 m, T6 l% Y. d5 v6 J! S# q
  6. ' w1 l, t0 @  s4 b; X
  7. <script>0 _9 T! q$ J8 |) V7 h' X
  8. Vue.component('todo-item', {
    4 T# X% y8 T- k+ ~2 O! |1 o3 @8 k3 T
  9.   props: ['todo'],
    2 |' H  R0 S3 d" `" }. u. V8 z# @6 {* \
  10.   template: '<li>{{ todo.text }}</li>'1 s1 {5 s2 j( x, J& w4 x1 g
  11. })
    # R# G% [- }1 e. F3 f* L: u
  12. new Vue({: X- E0 r4 x# t& W) ^) j( P2 ~5 M! [
  13.   el: '#app',- B8 l) |! o2 y* G) k
  14.   data: {
    ) ^- L; s: R& S3 {+ S- Y1 D6 M
  15.     sites: [
    9 M- K) Q$ K" I3 b0 Q, u
  16.       { text: 'Runoob' },
    , p6 K, F  u1 L: T- ^1 V
  17.       { text: 'Google' },
    & s; L- F3 Z& j% c
  18.       { text: 'Taobao' }
    . \% Q0 v/ o7 x, N
  19.     ]5 d2 @6 P$ Q) A! c
  20.   }# D7 v- i' y6 j1 }* g5 }
  21. })
    - Z- w+ r! ]  k( Z2 m
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    9 a' j+ X- {4 h, q6 v# ?) S9 Q. K; ]
  2.   props: {
    9 }* h- K4 F( y5 X
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)3 O8 K2 h( a/ F: g1 r
  4.     propA: Number,
    8 R% g- z5 v( l% I* C8 k3 {! h: s
  5.     // 多种类型
    + x) m! e5 \( h- ~% J. m/ F  V( Q& n
  6.     propB: [String, Number],
    % `* C2 d" _  V) Y  g: u
  7.     // 必传且是字符串
    ) @* g% f2 r3 L. D5 P
  8.     propC: {
    , x6 h* r6 ^" s% D* B/ s
  9.       type: String,
    0 M. A* s- H& m- P  e  `0 E- s
  10.       required: true, g/ c' F% b7 U* A( a
  11.     },8 F1 p7 l6 }) T* i# |" J- r
  12.     // 数字,有默认值. i8 u( o7 e7 _; @' C" y7 I
  13.     propD: {+ t" B. t# D6 o! y  _7 w5 l
  14.       type: Number,
    4 D9 I- v7 j0 z1 i. a6 n
  15.       default: 100
    , w9 g9 `3 @& f3 n
  16.     },9 g  \; H; n& A% e: n  m/ _7 n* {
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    4 q$ w1 h" I5 V: e
  18.     propE: {
    2 Y1 C* {) b1 y) x* Q) I) o' l7 n' T: [
  19.       type: Object,5 b. n$ e# ~$ f
  20.       default: function () {; m' s7 x  p4 x, M
  21.         return { message: 'hello' }5 D2 D$ K" `5 Y  ?, h1 c9 s0 k" x
  22.       }$ E# \7 O4 ]- Y; \8 Z$ x; d
  23.     },
    6 k; _" t5 v* I* G/ n% ]
  24.     // 自定义验证函数
    6 y* Y' d8 g( M. V
  25.     propF: {  k1 _* K+ g7 a" M
  26.       validator: function (value) {
    2 h* Q: y7 d+ N( v' [* H8 X! M4 H
  27.         return value > 10
    + @8 `& @- `) E3 n# S: ?
  28.       }8 J7 V6 o# o' L2 \' X1 R$ e
  29.     }% \. M6 }, x* G3 I% Z
  30.   }/ H) ^+ M, d% k/ }$ h4 v
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    3 [; B( q1 X6 `+ F4 _4 n
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    ; }) P4 {6 _' R( e$ P, s
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例$ B" R: e7 i$ L* ~) {
  1. <div id="app">
    ) h, S# g7 _( X6 H  L* u, ^
  2.     <div id="counter-event-example">5 N& d6 {& R; c/ S
  3.       <p>{{ total }}</p>
    ! s" c! k0 s  t) Z& i. ~2 i
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    " {+ j8 O, d) [, h. W6 e2 H  N# \
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    6 d" w8 ~1 Y2 ?" N0 e$ M8 ]$ i
  6.     </div>
    - @  M# k6 p  o! E, p; F
  7. </div>* M: {) a3 V  f& S5 X4 P1 h  x
  8. ( {: N: c! j! j* v% Z3 x
  9. <script>' G" j$ i. Y! _6 @5 c5 ?6 {
  10. Vue.component('button-counter', {
    ) r/ C  C1 q& Q3 x
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    $ F8 V+ L5 i2 N2 y# e
  12.   data: function () {
    $ X1 g/ g3 C! H
  13.     return {/ n: K) Y' w, L7 E& M( L
  14.       counter: 0
    * T1 s9 e( d+ y3 i* Q
  15.     }. ?+ h' v, }! y3 A. W  Q
  16.   },7 E7 J$ _" x3 Z
  17.   methods: {4 q4 v4 @! l$ j* C
  18.     incrementHandler: function () {
    4 F# K1 y8 P3 g! C4 s; R) U) A& \
  19.       this.counter += 1
    1 e3 D/ a4 @7 Y4 l& l( |, c
  20.       this.$emit('increment')
    ! c+ |" u4 E0 L0 e, N
  21.     }4 T, {+ @2 k' ~
  22.   },
    : E0 _$ I: }) X3 h9 g2 @( p5 {, l  F' w
  23. })5 |- z) D7 p8 `0 n; [9 v1 R/ o
  24. new Vue({
    9 q4 N2 q9 i( s% A9 q9 z% b) E, m5 a
  25.   el: '#counter-event-example',8 k9 Q1 [$ N3 C: j6 h+ @, S
  26.   data: {2 Q' @. t# f3 U/ s% m  A5 n% V$ G, V
  27.     total: 0
    " E8 T$ S9 o* c
  28.   },+ Z. v0 x+ _, g0 L7 o( ?
  29.   methods: {6 R& u) ~6 P4 c: z/ d, n: H/ J7 t
  30.     incrementTotal: function () {) A6 ^0 e; }0 D- ~9 o9 K0 Q8 M9 r
  31.       this.total += 1/ O: H+ _; ?) H6 o
  32.     }* b* W% W& I5 J$ C; L9 R
  33.   }# e7 Z5 g8 |; j
  34. })2 w7 K: J: R: D' v2 N: }
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册+ h1 S, X! C. o4 w5 g
  2. Vue.component('child', {
    $ x$ f, G) [: f3 n- d( |' t
  3.   // 声明 props
    5 O  Q. t( y+ m2 t" L
  4.   props: ['message'],
      V& |5 P8 h% |7 A# F+ v
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用4 ?" z) a4 e+ v: ^. X0 k+ L4 M
  6.   template: '<span>{{ message }}</span>'
    3 s# R: W) ^  W( w( ?& P
  7. })
    " e8 C. U% ]4 h3 W2 U; ~/ ~( f4 X
  8. // 创建根实例3 C( F& u* E6 p, L: H3 F+ p5 {  Z
  9. new Vue({
    8 t. v9 m# Q: V# z* m5 O
  10.   el: '#app',
    4 x" Z& @6 e; ~6 G+ `4 X6 [# X
  11.   data:{9 g. |! }: y7 w0 \  I& {7 p0 L
  12.     message:"hello",+ F2 O4 |5 ?  p% s3 \1 }0 x- u6 C7 B
  13.   }( K% ]& ~- i& g  `  E3 b
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    ' s  w- _) e# I5 s' A
  2.     incrementHandler: function (v) {; Y1 d0 q; @1 }0 |( y9 b) k+ Q# N
  3.         if(v==1){8 M* _6 H6 z, Z  k( \- j2 l. y2 P
  4.             this.counter -= 1
    5 u8 P& D% m" o
  5.             this.$emit('increment',[1])
    , Y) o! X9 R0 P4 `( v' y: z
  6.         }else{
    0 G; D* ]* R5 T6 E" @' ^2 t
  7.             this.counter += 1
    ) i6 @! I0 g/ b- {) H  p
  8.             this.$emit('increment',[2])* X$ R' v: R7 v2 s, t( U
  9.         }
    1 v7 A& Q- i/ _* M
  10.     }
    ' G1 I5 ^* f, ]6 c
  11. }
复制代码
5 V, a0 }( n9 i3 [/ ?

4 N, y' j( x0 h( q$ b3 v* a
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-19 22:44 , Processed in 0.066341 second(s), 23 queries .

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