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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15646|回复: 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,并使用它:
5 K% i3 U( I  |9 x
  1. <div id="app">
    3 }; z9 M2 @2 |2 [$ y: t3 k
  2.     <runoob></runoob>
    ; P: W- n2 Z7 v0 z" V& X5 u2 r2 X$ e
  3. </div>
    7 ?1 n% B$ r; Z* e. ?. r. y

  4. " n" i" F4 M9 n4 |
  5. <script>
    0 ^2 }' i8 B. k( `0 C
  6. // 注册
    & q5 T! ^9 K) u" q. c! e* E
  7. Vue.component('runoob', {! l. o) j2 C+ K) ?$ `& h- C1 s+ u
  8.   template: '<h1>自定义组件!</h1>'4 p: P; k: o! _( O7 L- ^" E
  9. })
    + R4 e. w$ Z! J1 [3 }9 c0 M. r, T
  10. // 创建根实例$ p* E$ Y) [  q8 T0 h$ K  k
  11. new Vue({
    # A8 |( v% S( e
  12.   el: '#app'
    " }' l% W& e# J' R+ F
  13. })
    + c+ M% k+ y7 Q
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

* l; u$ q+ [' h* }5 p; x$ p
  1. <div id="app">2 w+ O& b- l7 v% k
  2.     <runoob></runoob>$ a3 h$ l1 C9 M# K/ n: R2 H, f1 }( v
  3. </div>' F* {5 V6 P5 m7 ~, T

  4. ( Q5 w$ a! A2 M  W6 C
  5. <script>& |' F3 {4 A6 C. r# n% s3 S9 d. t
  6. var Child = {: _- g* r8 U# R
  7.   template: '<h1>自定义组件!</h1>'7 z/ Z8 M& ~; z8 t, S6 `
  8. }
    1 z# z* }+ N5 [+ S# A8 R# I! Q! {

  9. & k' s3 |4 h9 d4 H0 q) p
  10. // 创建根实例
    9 K* j& t5 h; `* g7 x6 ]
  11. new Vue({9 y. J' S! s, t6 F
  12.   el: '#app',
      [; J; Y6 F- n1 r) W, z* N
  13.   components: {, A& H4 G. m! P
  14.     // <runoob> 将只在父模板可用
    : M. W3 F, d  }" h& x0 f4 {) E
  15.     'runoob': Child4 U& o) C& N4 M* Y
  16.   }
    ; R- s$ z$ B" ^8 E5 q& P
  17. })
    7 {: m. q. F  N- y& l6 ]
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
2 ^( \" c" G0 r
  1. <div id="app">
      b! V0 F. d  L8 Y' C# L* A
  2.     <child message="hello!"></child>
    - ]* l! H& j# b3 e3 X
  3. </div>7 O7 s% ?' `7 j2 X

  4. : F8 O) B* f4 Q; f
  5. <script>
    3 [6 S) h! M0 D' x
  6. // 注册$ }2 w" o- M1 |& ^; B% y
  7. Vue.component('child', {
    ( O/ }# V7 `0 D; H" v/ ?
  8.   // 声明 props3 x( v6 a" c; e) G+ v4 b
  9.   props: ['message'],1 H4 K' h/ U3 c6 |' d+ I8 |
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用, B, O  x8 z7 r* B: e) L5 A+ x. G
  11.   template: '<span>{{ message }}</span>'
    # Q# f7 `& ^1 p  m
  12. })  U. Y  c  t: O& O
  13. // 创建根实例
    1 G# I7 R# Q/ Z, l
  14. new Vue({
    8 t2 Z' l% [  n0 W" `8 X
  15.   el: '#app'/ E3 [/ n: [' G5 u6 q# r
  16. })0 u7 g7 o$ b3 F
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例' V: p5 r$ P+ l! ]9 a0 C
  1. <div id="app">' }% Z  t$ ?9 {( o1 i% I
  2.     <div>% \4 N) a( c, f7 ?; Y' G# k
  3.       <input v-model="parentMsg">; o1 \8 C- J: @( c! v6 n
  4.       <br>
    , @, T! T) i8 l5 L( A* m
  5.       <child v-bind:message="parentMsg"></child>
    * K  }0 @6 P" ^) ~2 F; r
  6.     </div>
    9 A3 ^: P3 D2 j( }7 k
  7. </div>
      Y& L: h" G3 W+ T

  8. ! O0 ^1 M+ D  u+ [! e' I
  9. <script>
    0 W! V1 u  K- I0 e" h2 @4 M  L/ ^
  10. // 注册
    # j/ Q4 V; Y6 o9 b& C
  11. Vue.component('child', {
    # {/ p9 d" ]/ e$ f( k
  12.   // 声明 props
    * Z9 O: E" [& y+ J! h
  13.   props: ['message'],
    6 `0 L0 V% W4 I1 `/ u
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用: e9 }9 U1 X& z5 f( G
  15.   template: '<span>{{ message }}</span>'
    . Z8 J) q: _& m- {6 J
  16. })4 d7 c/ K# K/ h4 ~, z
  17. // 创建根实例
    2 Y5 z+ s3 g5 }) u# o. }% S1 _
  18. new Vue({6 ^8 g. B7 I; R  K1 M+ N) U
  19.   el: '#app',: Y+ \' ^4 P* ^1 }% {
  20.   data: {9 P$ T% b) ^( D/ B2 b6 V
  21.     parentMsg: '父组件内容'4 {4 c! h% Z/ `& \5 I( C! ~- V
  22.   }
    $ G* s5 |# F: l$ p4 R( H
  23. })/ |9 `2 f" }# ~# b
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
* W- U4 U, h1 C$ @0 q) t
  1. <div id="app">
    $ `6 q: c9 S* O. z) [6 i. H0 T( }
  2.     <ol>0 t2 g0 ^$ f& S; h% U! K
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>7 b5 y  a) |! w! S  s# t, n% L
  4.       </ol>
    + b2 ]' d  a8 T: ~
  5. </div>% a( ~( i) g0 n2 s

  6. ! n& B$ ~, H& F6 X6 ~  D4 c
  7. <script>
    + y. h! J) F4 k! D3 X8 v7 d, q( m
  8. Vue.component('todo-item', {
    9 m3 [% R6 U, K3 }% y
  9.   props: ['todo'],2 {2 }1 f& r# J  w
  10.   template: '<li>{{ todo.text }}</li>'
    0 @) A  Q6 P1 G8 U( w! @% q8 [6 J4 y
  11. })- L- {  U* Q9 y
  12. new Vue({
    * v1 X  p: w) g
  13.   el: '#app',( s' J2 `* U) B% E
  14.   data: {' `1 @8 o& K4 J* e6 `0 M
  15.     sites: [
    3 U6 T1 D: G. X' j$ z( m/ c
  16.       { text: 'Runoob' },+ o/ w0 x: l7 e/ L1 X
  17.       { text: 'Google' },
    ' a0 q* \! \; t7 o* C
  18.       { text: 'Taobao' }
    4 `/ b# ]- G, P3 d. w0 D7 \2 q
  19.     ]; ~. F$ ^0 `; \: O& a8 a
  20.   }
    ! ~3 x/ G9 q3 g2 R/ R  ^
  21. })
    1 K: u" I& g/ O
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {5 T, G% K! t, x* Z% O* o1 }6 @% n
  2.   props: {
    : E4 ?& ]( v) C& L/ j; _
  3.     // 基础类型检测 (`null` 意思是任何类型都可以): `$ Q: t+ ?2 C
  4.     propA: Number,
    & g$ p6 a* K% E
  5.     // 多种类型$ {( U3 |/ l) x2 u& _
  6.     propB: [String, Number],
    5 i3 A) D/ W  y; t/ Y: @
  7.     // 必传且是字符串
    , l) l5 B7 q0 N+ b* Z: G
  8.     propC: {
    0 P$ t' A/ Q4 {8 n! u- j( U! f
  9.       type: String,
    5 V* G9 B9 _) g6 e5 |: X- a
  10.       required: true  X$ T1 V8 b6 L
  11.     },
    * R" Q- k; J) W8 k- u; I! c
  12.     // 数字,有默认值, r7 u+ l+ r& b
  13.     propD: {
    3 r4 j, k+ G1 c  p' T: _2 r. v  {2 `
  14.       type: Number,, n1 \" e6 g6 {6 t4 @  H' _
  15.       default: 100
    & b2 z% P$ t* L" W* R
  16.     },
    ; s7 l/ v8 Q  _0 K' J
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    ' J" {1 L. e5 ]; b; w: _
  18.     propE: {
    9 U' z, U! x$ R# x& |, Y  X
  19.       type: Object,+ k6 L+ `8 b9 R/ H  z% u# M
  20.       default: function () {
    3 N& ]1 H( G! A8 \
  21.         return { message: 'hello' }
    ; x( Q, ?6 `6 X. K7 T1 I
  22.       }
    ( B2 Z" z4 Z, x, `
  23.     },4 J3 Z- k  E' |2 E/ ^% g  _8 {+ @
  24.     // 自定义验证函数0 F* [0 m5 p  g9 {$ V, [
  25.     propF: {
    & J( |" Y" h, A; L' b
  26.       validator: function (value) {4 N& r, c2 S# ?% q
  27.         return value > 10
      p# f/ Y( H4 q) H. D! s% o
  28.       }# I  }4 x- f! b5 m0 _/ o5 O( o
  29.     }! m3 _- K& P  F; ~6 R7 u
  30.   }. ^$ Q  O) K* `
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array  a6 c$ t  }) E1 C4 \
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件8 |7 \2 k9 l2 S# Q- U8 {
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例! O  o% `* C( s, v
  1. <div id="app"># w- D+ l5 a8 q) S$ J
  2.     <div id="counter-event-example">) a. A0 o& P+ M+ y0 J
  3.       <p>{{ total }}</p>2 N# U* Q  x1 k  z
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    : m' ^1 i3 Y5 z5 O4 i
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>, U5 M, V# a4 _2 J+ j! a, l" n  ^
  6.     </div>
    7 I! S' q2 F; Y5 F7 d9 p
  7. </div>
    / A' T6 V9 v& O3 Q( F8 M' h
  8. / L4 _% l) y1 F
  9. <script>6 t' I& W6 F7 H2 P% ]) c% S- T
  10. Vue.component('button-counter', {/ U! H' ?9 Q, t
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',! V- G5 s# p/ t  F5 Z1 N  I
  12.   data: function () {
    7 \/ B8 p, O7 ]% M& x
  13.     return {
    # m0 T& Q1 {5 \2 ~; v
  14.       counter: 0
    4 ]* {0 J/ [; `1 G4 V$ o) |& r
  15.     }
    3 \: X, y4 s& |  u3 _/ k5 {
  16.   },
    * r! o! R$ f( @: k1 s0 e1 t8 b% t
  17.   methods: {
    / O5 r3 Y( [, ^" j
  18.     incrementHandler: function () {
    & k2 b6 |4 K0 G. f0 k
  19.       this.counter += 1
    ' k; d- A' W% ~- a3 T7 \9 U' n
  20.       this.$emit('increment')
    5 e3 P) x* e5 I7 U
  21.     }
    " M& h9 x, ~8 J8 x3 `, Y9 ]
  22.   },
    - M+ K  t& ?+ Y- \
  23. })
    6 V. m2 Y) B, N& O6 z# H
  24. new Vue({# \, w' p: x$ k* k( Z; S- ^" j6 }
  25.   el: '#counter-event-example',
    9 L% K/ m% }  A% |0 R
  26.   data: {/ w: u2 ]/ R2 U$ [1 E- d
  27.     total: 0" {$ X( V* B' C/ q  A4 N' C- K) w) F
  28.   },
    ) J) h# O7 \  P5 ]- u
  29.   methods: {
    0 p/ @  t$ V: Z! x( I8 y$ f
  30.     incrementTotal: function () {
    + H0 `7 u" N, s
  31.       this.total += 13 O, e6 R% C+ z8 q! h
  32.     }. T6 p9 R/ h" Q4 ~1 `; d7 b7 _
  33.   }, G/ |8 R( `% Y0 g; h) C, E' h
  34. })0 L- Y! [8 O( \3 n/ ^
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    : q6 N, F" y' W+ y! j; T0 z
  2. Vue.component('child', {
    + d8 f" F7 |  X: Q6 b0 |
  3.   // 声明 props1 ^) U7 I! S5 a) F( ]' E
  4.   props: ['message'],
    * x0 c& ^% d7 \" k% S2 c$ L
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ) U9 o# P  L5 i' b8 ?3 ]
  6.   template: '<span>{{ message }}</span>'9 X  i2 w9 V: _. I/ _$ I% c
  7. })* W& v, H7 z& p  [
  8. // 创建根实例
    6 u% T" F+ D! Z) p/ J" N; h: q- [4 _
  9. new Vue({6 k. U% m' r. {+ x% U$ |4 c
  10.   el: '#app',. u( B. Z- F+ u8 H
  11.   data:{- O% U( X, h7 T: \" T$ S" Z
  12.     message:"hello",
    2 `2 q5 U) k( u( J: k, r/ _
  13.   }3 a8 a3 c! j) p$ n
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {) V. H; A& |4 p8 k
  2.     incrementHandler: function (v) {; q1 W4 ~0 W" A3 v; ?" d  N: n
  3.         if(v==1){$ n1 X! w# a3 E5 p/ N7 E
  4.             this.counter -= 19 ~5 {% L4 L  d% X1 o
  5.             this.$emit('increment',[1])
    9 t' |- j; M- i$ q/ [# \
  6.         }else{
    " u5 e4 B7 h2 G8 I
  7.             this.counter += 1
    $ K8 [$ A$ G7 @# f) W/ m$ V, U
  8.             this.$emit('increment',[2])( u( d. `; c! ?# A
  9.         }
    2 O  G) G# c3 W- o8 L$ F
  10.     }
    1 B" `. C" P2 c. `5 e# R$ r) F
  11. }
复制代码
: b1 i$ c& D) ^) I* Y
9 ]4 h8 W( Q9 c% }2 @0 T( G5 V$ p
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-4-30 19:56 , Processed in 0.077431 second(s), 23 queries .

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