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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 16302|回复: 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,并使用它:
( Q5 [/ b; O+ C. |- C! Z
  1. <div id="app">* O& G  R+ E! c5 k' _
  2.     <runoob></runoob>
    1 ~1 s* n  o( ^/ o) X& D' O
  3. </div>
    4 T& b$ m6 s" c+ V/ U7 C) O- r% k
  4. 0 H) R# p1 {$ @$ x
  5. <script>( ^3 q7 g' k* n' o
  6. // 注册7 E" j0 @2 f7 @3 t, V2 ^5 e( W
  7. Vue.component('runoob', {* X: S# g0 T: T0 q- V1 W
  8.   template: '<h1>自定义组件!</h1>'
    * R' H" [! e& i# j# k4 b
  9. })1 V& X' ]  U6 _. S& c
  10. // 创建根实例- j2 d0 y& h' M1 p- [4 i' C( z
  11. new Vue({; ]- j  e$ l0 G+ z, f
  12.   el: '#app'
    3 r' P/ p/ @9 Y9 @
  13. })
    " \, B3 K' c4 A# N* A! e- w
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
/ {9 W4 @7 y5 w# u! Q
  1. <div id="app">
    $ N  G, h  p2 o/ `
  2.     <runoob></runoob>8 y' w/ M+ y5 P
  3. </div>
    3 I. o2 a0 O& v# v
  4. 6 T$ _' x$ Z" X5 m; Q' b8 |+ z
  5. <script>: H8 V! ?9 s  n% s( K0 ]
  6. var Child = {
    & L* K- J, I9 ?. Q  D& }% a
  7.   template: '<h1>自定义组件!</h1>'! s& H0 x# ^- v
  8. }
    4 D) ~( S/ T. a
  9. . W3 H8 u2 x# \& l/ N$ H6 C0 K, m' ^
  10. // 创建根实例4 o; U' ]% D0 A1 c6 b% m
  11. new Vue({/ n% ~/ h' w% p- k
  12.   el: '#app',5 }1 I* P* i  S2 o% K! W
  13.   components: {
    , _; e4 D! O: Q8 Z' H( N
  14.     // <runoob> 将只在父模板可用
    * O6 k  {) |4 l3 Y; _
  15.     'runoob': Child
    2 `' Y/ h* g/ J
  16.   }) d: |3 l/ C! a1 V* P  l% @
  17. })
    0 ]) A! ~6 |0 N8 }3 J
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例. @7 }, [; L3 d( W4 E
  1. <div id="app">1 B/ i2 K( V2 Y2 Z
  2.     <child message="hello!"></child>& B( p2 \4 Q' g/ v- n# h
  3. </div>
    ' w' g! K4 f4 G4 }6 p' J5 b
  4. , B$ X- i# I" e; ]+ g
  5. <script>
    2 G2 }: v5 `1 V9 O9 e  H
  6. // 注册2 |  V5 l" Q5 n+ m+ @9 m$ G
  7. Vue.component('child', {
    1 d3 p" I6 c, N1 l: R. U' t0 g1 B
  8.   // 声明 props; O! A( J# _; a# {+ h7 |9 `
  9.   props: ['message'],
    8 \* `" Z7 `% P- b+ g3 O& z! n+ I
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    " _3 q$ q  g. X* o: o
  11.   template: '<span>{{ message }}</span>'% g1 u% K0 ~: Q3 L0 c# n+ _
  12. })
    ! v0 F: [) ^9 F; k/ m4 n
  13. // 创建根实例% r; x3 X) |2 w" k7 J3 ~& \$ C9 ?8 Z' P
  14. new Vue({
    6 H6 c: j/ g1 w! P9 J
  15.   el: '#app') {  j7 `; C; C! z0 w/ L: C
  16. })8 J9 z" J$ O% i
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例/ i1 s4 s  P8 p* }
  1. <div id="app">) l4 m: q  p5 v- H" T
  2.     <div>" I$ }8 R- i) U' g+ b; @
  3.       <input v-model="parentMsg">
    . V5 v6 W. f, _- o) v/ D1 m) E
  4.       <br>6 C0 R4 O' U( c/ E, C( X3 X3 X
  5.       <child v-bind:message="parentMsg"></child>
    3 c* `: g/ z. P
  6.     </div>2 j( d- m/ p! |% u$ w0 @
  7. </div>
    $ a3 g3 Z4 N' W
  8. 3 `4 b/ t6 Y* q, B& p# \
  9. <script>9 }5 l% z4 d! T' t. n6 M9 _; w: \
  10. // 注册
    $ H! J, L; t7 M2 m/ n' q, o3 P
  11. Vue.component('child', {; m$ j% t/ {. B( ~5 u* a) C
  12.   // 声明 props
    ) H7 ~# y# q+ E, L7 H/ r
  13.   props: ['message'],% a- y5 M6 _7 D" T6 q4 C
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用0 n4 P$ d" \- K. r3 l
  15.   template: '<span>{{ message }}</span>'
    # S! Z, L8 J! [2 x' B
  16. })
    . R/ Q6 D1 e* |. m! S
  17. // 创建根实例, I" q2 c7 G0 ?/ `" _9 G5 x
  18. new Vue({
    % m: n+ _3 y% T7 ~9 p
  19.   el: '#app',
    * E: a! i  }2 H. f; c$ P% \; {
  20.   data: {6 h# n+ Y  K( L: j. @7 U
  21.     parentMsg: '父组件内容'4 [, D( Z+ t7 L1 E# m" N" l/ u7 [
  22.   }7 |9 x. i/ |$ |) V1 O, N
  23. })
    5 l5 [  ?# B% j6 |
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
7 v, ]+ t" l" @5 O9 ]+ T" s% o
  1. <div id="app">8 q* ]# I, T6 D
  2.     <ol>% ?! i6 a- k% M+ o& L' t9 t0 a& M2 w
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    1 E& [# e; i( w) z6 R5 j
  4.       </ol>; g0 U8 F8 |( E% y7 W7 M" u- d
  5. </div>
    ; R, ~' l6 o# r

  6. # F- s1 j5 L7 s7 [, E$ r: Z
  7. <script>- I. j5 B7 \; S- N3 g7 ]# k
  8. Vue.component('todo-item', {
    ( ^" J5 @% T, |7 c( J
  9.   props: ['todo'],
    ' q/ R' ^7 Y/ T9 D1 A+ t9 E) }
  10.   template: '<li>{{ todo.text }}</li>'
    8 v  p- X, T4 g. \
  11. })8 T8 X' B0 ?; U# O( E6 D( `6 G
  12. new Vue({
    $ {* u- `) }/ E, `5 a+ A$ `4 h$ J
  13.   el: '#app',
    1 A' Q  h7 E5 p4 ?
  14.   data: {
    . `2 J3 T, `7 l* s+ k7 P2 y
  15.     sites: [# M! {2 V" q% s0 l6 u9 R
  16.       { text: 'Runoob' },
    3 M7 T: l: x3 ?+ ^- b5 b9 C, I
  17.       { text: 'Google' },* P+ I, T  f; Z8 L7 L& s
  18.       { text: 'Taobao' }
    ) o1 b2 ?' @$ \  Q. O
  19.     ]" |+ _' m1 Z; E' Z
  20.   }6 K6 g% ^" ]) u# p4 P9 Y! ^  h7 {
  21. })
    * t+ a/ q9 [( O9 ]1 [# D8 U; }
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    # G  \' u  s* g, w1 {  T) Z
  2.   props: {
    0 T, c3 S! ~# ?0 t5 W4 \; C
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    8 N- E! ]& H2 H6 q7 g
  4.     propA: Number,7 I5 F8 G0 g2 `
  5.     // 多种类型
    5 k2 I1 J0 |. d: y1 O$ Z1 h
  6.     propB: [String, Number],3 E/ b8 ^6 r7 G) e
  7.     // 必传且是字符串$ c3 C- k4 p; z4 `
  8.     propC: {) r- `7 ]: r" @8 {0 X8 F3 T
  9.       type: String,
    : Z( e0 ~- G4 u& f6 Y
  10.       required: true) C( M" q4 i; j4 |2 [, G8 G- B
  11.     },8 s0 X' I$ m8 G$ ^/ m9 s: y* T
  12.     // 数字,有默认值
    * X+ W8 z! K, t% K, e7 G
  13.     propD: {4 E  y2 W% @, O: K
  14.       type: Number,
    1 P# r  }; B% L
  15.       default: 100+ v8 U9 ~) ~) r) y! D
  16.     },& j# I% J# g7 t$ B/ ]
  17.     // 数组/对象的默认值应当由一个工厂函数返回; U0 n8 Q# z3 p9 K, K" x* A- t9 J. l0 [
  18.     propE: {) L2 i  s+ n$ p& i
  19.       type: Object,
    6 t( C5 q- t5 c! C& y4 A
  20.       default: function () {1 K& J- u; {9 U/ [$ J; t/ B) _8 p
  21.         return { message: 'hello' }
    6 E$ l2 d) y% a% L1 ^" {; y
  22.       }7 |5 B0 s4 }2 H3 C! @* D
  23.     },
    + S/ i, K- L* Q: Q1 p; x
  24.     // 自定义验证函数
    0 R* ?/ y2 I) S' w
  25.     propF: {5 K5 v) L% U/ a9 b
  26.       validator: function (value) {! R- G2 D8 W) D
  27.         return value > 10- S+ G+ }7 H9 S' m$ {
  28.       }4 R5 L' Q* Q1 ~7 v% U% L
  29.     }, I4 F, i3 A( x) }' M
  30.   }
    ; `9 p3 g. }" }5 [6 Q6 V
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    / w7 b; U4 p4 b. y  b5 Z
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件! Q5 x( ?8 U7 Q9 I* {# z
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
* s# I1 `9 v# U4 s9 B$ @/ T4 E
  1. <div id="app">
    2 O+ }3 a) i1 N4 i0 X7 j
  2.     <div id="counter-event-example">9 e2 `1 o6 {. _4 [/ _+ ]
  3.       <p>{{ total }}</p>9 @  x+ \9 H; x2 l+ J$ C
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    6 W" f+ z5 m& p1 Y8 M
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    . k/ |! O+ r0 x5 _; w/ b# D5 H8 T
  6.     </div>
    7 L* W  Y3 _. v9 ^  Y
  7. </div>
    & }* j4 K. E: @" |
  8. " n! M4 Y& p  j! u1 j1 |& J: N
  9. <script>" J3 i3 [5 t$ J; i9 z
  10. Vue.component('button-counter', {
    / X* p" c  R+ V# n2 d
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    # ^8 u1 V$ V& \8 j" s+ V: ^% J& c
  12.   data: function () {
    9 X( O7 F. [- X: i
  13.     return {. b* O5 t! D5 w' Y* X0 K( n, z& X
  14.       counter: 0
    , S: K( m, U1 P& ^# V
  15.     }+ s* j" d' P$ M1 J/ t
  16.   },& T5 ~( e: n; B" G- K3 K  W
  17.   methods: {3 g0 o. N4 I+ Q/ f) `
  18.     incrementHandler: function () {
    : d, i* {- k0 n2 ^  z' a8 {
  19.       this.counter += 10 m3 L0 S0 o$ j! V) i0 l
  20.       this.$emit('increment'): E0 i! F8 l% j% w- |) K
  21.     }
    . |& U. Q6 i$ I$ O+ J0 k- d/ K  t
  22.   },! {& z# N7 H3 j; ?+ D6 i
  23. })
    . q6 H+ r; ~6 B2 `4 P
  24. new Vue({
    * ^7 u- a& f5 z- Q2 @
  25.   el: '#counter-event-example',# r7 h! K* u; P' D
  26.   data: {! O& I7 X! ^! h& h
  27.     total: 0
      k5 Q6 {6 h  `% b5 X  X
  28.   },
    3 }+ L$ u: k5 ^/ K
  29.   methods: {. {, ~4 e% \( i) e8 G8 W
  30.     incrementTotal: function () {
    3 `7 ~+ A( G5 F! P+ R- `! T
  31.       this.total += 1! V9 V% w  w& r) b
  32.     }
    ( |/ {; e! d" o3 s  C7 F5 l' Y
  33.   }
    2 t1 c; }  ?: @" D+ T1 e
  34. })$ L5 n# y5 K' P; M
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册3 j5 q* p, k; O8 y1 i1 Q4 F
  2. Vue.component('child', {
    5 [: j! G& A. l3 h! v- m
  3.   // 声明 props# C0 V, b/ j: A; x. G
  4.   props: ['message'],
      ~& c2 b" @7 R; m+ _" d; ?
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    9 W' J% U3 n' d& }2 D
  6.   template: '<span>{{ message }}</span>'
    9 o* Y- r& n, @  ~% Z) u
  7. })
    ! }* z! H/ m9 s) l
  8. // 创建根实例" ~) G# y8 a* Z6 x: l" p4 B* h
  9. new Vue({5 C( q6 k$ U. p  h2 e/ D
  10.   el: '#app',
      K, S& m/ y2 Z4 P7 `& x: ~
  11.   data:{+ U6 k0 G. W7 C  v
  12.     message:"hello",
    ( `- X& P; R1 T1 u. h; N6 O
  13.   }: F, O3 k) n) G6 o& o4 r) k9 _
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {( \" g8 _$ w5 n/ [' M' L- l
  2.     incrementHandler: function (v) {
    5 t, `7 q# k, m& A% @" S5 N, s3 d
  3.         if(v==1){
    : ]$ q2 O6 @% j! P- f
  4.             this.counter -= 1
    * g+ X5 U5 M! t: ~3 l4 ^
  5.             this.$emit('increment',[1])! {9 b" t; T; O2 r
  6.         }else{6 R0 [, ~+ F* W0 w1 V4 d
  7.             this.counter += 1! A. e0 N0 J4 y! P; [$ l9 p
  8.             this.$emit('increment',[2])
    2 n* C( U, M" g6 n' L7 X
  9.         }
    / \. b5 D' u+ l; l* j4 Q
  10.     }
      X4 P# A+ R" X! i  [
  11. }
复制代码

5 }* s2 b1 r8 P' M. K
$ c3 Q2 Y" w/ `! G) \% y
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-8-4 14:07 , Processed in 0.057896 second(s), 22 queries .

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