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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 12775|回复: 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,并使用它:
' i1 m) V3 L9 ^* ~3 v; Q% m- N
  1. <div id="app">$ P7 g+ D5 _4 Z7 u7 y# K" a. E
  2.     <runoob></runoob>& e  K; ^1 _8 Z, R) r6 ~. E
  3. </div>
    7 u; u1 i0 p# s% m2 x

  4. : b# @; `" G/ ?7 L6 M: W# S
  5. <script>
    * \  `- A( M6 S* |8 ?* _9 a, n! T/ Z
  6. // 注册: Q8 E! B7 Y2 i+ r( n2 b
  7. Vue.component('runoob', {
    ! t0 A/ N  }0 A  u
  8.   template: '<h1>自定义组件!</h1>'# ]3 e/ L* y0 j* f4 H& B+ D2 \
  9. })8 V; x1 J, \" \% s- E* z5 [
  10. // 创建根实例  C# z, j) x1 e9 G/ T& [
  11. new Vue({
    & ~" Q( q; g. m* F# L% ~
  12.   el: '#app'8 Z. l: j/ ]9 D; V7 O9 {, h: R  u
  13. })6 x7 l4 Q8 r# K7 n2 P8 S8 C
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
* t( o5 o" l6 w) }1 D3 y% J
  1. <div id="app">
    % J2 _& [% g( M6 U8 ?
  2.     <runoob></runoob>  i# f. N4 t, B) f( M! ~# L" X# M
  3. </div>
    7 J+ j# `* C, r5 _; R

  4. . N! S% _9 k0 C& e6 |( ?
  5. <script>; u7 M( A$ ]8 f9 f( Q  u( n3 o+ X
  6. var Child = {( W3 X" N. t% x: [+ B& Y, [! K
  7.   template: '<h1>自定义组件!</h1>'8 c+ {! p$ L, [9 c; x
  8. }! _* _$ J) P7 H) n# f0 b( s! L; J2 X& N

  9. ' \! \' I& |6 K9 n
  10. // 创建根实例" F- b& n8 L% r( q; Z
  11. new Vue({
      z4 ^1 `9 L" U, P2 h3 n
  12.   el: '#app',7 }, Y7 F- s, M  F% L2 ~$ S8 t9 V+ L) o
  13.   components: {. P2 E: A0 S: P0 F0 I; A* H: h5 |
  14.     // <runoob> 将只在父模板可用/ p! ]5 v7 O* u$ [6 A
  15.     'runoob': Child
    4 a8 w8 U& c4 Z  h
  16.   }3 o; |" B5 z% g2 i
  17. })$ Q( l- e2 h+ O
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
/ j: P" b, h) r2 P3 A  k
  1. <div id="app">: X6 N  g- z. s3 ]! d& T7 Z3 R
  2.     <child message="hello!"></child>
    ) I$ W/ R  ?. H- X  Z
  3. </div>( g8 d6 p" _  t

  4. 0 [7 G/ a3 o. G
  5. <script>
    + L% c# `+ r- ?( r5 q4 W# J6 Y2 E
  6. // 注册
    ) g* f# t5 z. m( L7 ]& T
  7. Vue.component('child', {
    ; g# b4 |& S/ @  q- c
  8.   // 声明 props" q9 t; }; }5 x6 P" ?% t- o
  9.   props: ['message'],2 i6 I! v( O# y
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    2 D. m. z( Y5 u6 S
  11.   template: '<span>{{ message }}</span>'
    3 N* w6 X9 f" L
  12. })5 d/ p  i- b' [4 e1 p
  13. // 创建根实例8 k* |  b4 b6 q. ^% b3 A  {( w2 A
  14. new Vue({
    9 b; `; B: m7 c. Z' o: ?
  15.   el: '#app'4 F! `. E" ]8 k) L6 V
  16. }): W7 ]+ ]$ w1 f' `4 \5 n0 y4 a
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例9 j7 i- {  O+ @4 j* L% N
  1. <div id="app">
    ; R" p6 L* c# V. t
  2.     <div>$ y1 D1 Z5 y$ Z
  3.       <input v-model="parentMsg">) t7 L0 z$ E$ k$ N
  4.       <br>
    ' E8 h2 Q( q9 k8 c. g
  5.       <child v-bind:message="parentMsg"></child>- K( J6 F2 z: f
  6.     </div>( `3 U2 F( h6 e- G6 h. S/ Y6 }) s
  7. </div>
    " P# H) ~5 t! M5 D4 }/ O) v: X

  8. ! Y- m$ c& v! Z) v6 Q* `8 |
  9. <script>
    3 L! t2 Z2 f9 F2 d5 l& d; V+ e
  10. // 注册
    $ h3 M- R$ j7 R1 ~
  11. Vue.component('child', {0 ]& w. l+ z; v( v. b) ?% l
  12.   // 声明 props+ _; ^! Z& l2 f! o: ~5 C
  13.   props: ['message'],
    6 J5 F- I+ G+ h' u- k
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    % f# B" o. e* Y5 \, Q( n; ?3 L
  15.   template: '<span>{{ message }}</span>'' A2 W' N7 H. Y* Z
  16. }): N; J9 |0 |( J" v; N! y& c
  17. // 创建根实例
    3 p( R6 p% k: ?  y& k
  18. new Vue({8 ?+ M: O  g# k0 d6 G5 U% L3 l2 @6 m
  19.   el: '#app',6 a& a( m. T6 h' S% d# A( ^+ w% J
  20.   data: {
    ) h; J/ [; C0 S* z/ r4 w
  21.     parentMsg: '父组件内容'2 q2 M) |8 U/ M
  22.   }6 t  a9 B2 f; q1 k
  23. })
      V* m; J3 `9 g8 I9 R* y$ P7 o
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
2 i5 n# }% I/ O  X. ]3 n5 L& m
  1. <div id="app">
    ( A# B! l/ \1 r* [' Q
  2.     <ol>% i' n6 O$ K& I- L
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>) K/ @' `. e" s5 H. H
  4.       </ol>1 n; C6 \' H4 o, G% Q* C
  5. </div>
    # a5 v" [7 R4 {- E6 ]1 \; ~6 g
  6. + m8 ?, Y  `9 j' M: p3 @* ]
  7. <script>
    5 K5 C9 g' S- F- Y! n" Q8 E
  8. Vue.component('todo-item', {
    ; H! v7 y. B1 P3 D$ E& b# R
  9.   props: ['todo'],0 f( y" c3 k3 Z4 V: E4 K
  10.   template: '<li>{{ todo.text }}</li>'
    + d3 c/ D7 M6 C" l$ _* v
  11. })$ \7 t: a$ G. Y* B1 ^# k
  12. new Vue({9 v, ~5 ^: |0 o. x
  13.   el: '#app',
    - j) B8 r8 ^9 U6 f: k; u
  14.   data: {
    : Q" b! Q3 Q" C4 O1 k) U5 ^; r9 k
  15.     sites: [
    6 ~1 F9 ^. @3 V
  16.       { text: 'Runoob' },7 i8 D8 M: i) Y$ |$ P
  17.       { text: 'Google' },3 S: j; }7 X$ Q% g6 h* g' ^# P
  18.       { text: 'Taobao' }
    & D! x# w$ x, l8 Z
  19.     ]
    + T0 ?" {+ E( Q+ `' h( p4 o
  20.   }7 c  M" j4 J% v9 ?0 {6 C  {
  21. })# x7 z8 q( U% ~# t. q% }
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {  a' ?  T3 g9 j3 U% C
  2.   props: {5 J& S# o: ?- M4 _" j7 E; D
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    - Y& L" v+ u$ I7 @" v( Q6 O% ~
  4.     propA: Number,9 T3 T3 w5 ]$ X- p6 D0 Q
  5.     // 多种类型
    0 ?# T* Q5 ?0 S: q
  6.     propB: [String, Number],
    ' e2 d- `/ _" U: l& k* ~6 M
  7.     // 必传且是字符串+ k7 x. v3 @! Z0 N& O
  8.     propC: {$ U8 ~; B1 v1 ^% w1 ?, z" T
  9.       type: String,' \+ l- X1 w) m" a+ t
  10.       required: true
    $ b+ D' Y  ]' L) X
  11.     },
    8 p% S8 C% K1 ]2 G5 p$ P% k
  12.     // 数字,有默认值2 m$ L: u2 E4 w
  13.     propD: {: T4 }! d5 O5 W1 N
  14.       type: Number,
    3 a2 Q' m9 k8 n
  15.       default: 100
    $ w9 ]7 }9 s( D( D% n) ~
  16.     },9 k* G2 ~: t0 m" ?& v: S9 \' L
  17.     // 数组/对象的默认值应当由一个工厂函数返回* u4 c: D8 e: L. v5 e6 D: v
  18.     propE: {/ q8 X; {* G. C( j9 _8 t, C
  19.       type: Object,
    & u6 E& Q" H3 x, C
  20.       default: function () {7 f5 J( U3 R7 U- T; g2 q7 J
  21.         return { message: 'hello' }6 F* f( n- f% H" j. x
  22.       }
    / }- s/ T! [+ E# F1 B9 n" L8 I
  23.     },
    # J+ M* G: |" I2 b; R. u  O+ e3 T
  24.     // 自定义验证函数" V: O( W* c; I- \3 P$ g. t
  25.     propF: {
    1 b& D1 i5 y6 c: e
  26.       validator: function (value) {, S- d9 l8 S" P; B# S5 K
  27.         return value > 10
    ) \" C$ v0 K$ T' x: ~
  28.       }
    % }) ~( I# O4 f3 ]( e
  29.     }
    * p5 y% c4 x1 v( O7 g$ v8 `$ w
  30.   }
    2 n) Y! N3 X9 ~8 L) T2 ?7 M4 Q
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array/ s- Z( p) q2 e4 p
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    ! {: _& A* U& Y# p  U
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例; |3 o4 \* {8 R  Z5 n3 a4 n) h
  1. <div id="app">
    + c( R2 y/ `: Z/ ]
  2.     <div id="counter-event-example">! Q# K: A( _, m. ?; E
  3.       <p>{{ total }}</p>
    & U7 }. D, D% [6 e& C
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    ' ]- H0 w* ~" O4 B1 m$ j$ H
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    . u$ r" k0 s7 ~# }; _% d
  6.     </div>
    # h4 H3 G3 Y  M( B
  7. </div>
    + A& p# b7 U% o" [8 l: @
  8. % y' l: t* i- ?" l+ C
  9. <script>8 R# z$ z* c, [( }6 d+ u+ @
  10. Vue.component('button-counter', {0 l0 A' M% h/ U0 X+ h% _' C
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    7 ~7 D4 q' P) q
  12.   data: function () {! E! n4 g9 i! |" X  J2 ?' c! N/ @
  13.     return {4 @# f8 o6 t( K: {& Z
  14.       counter: 0
    % |+ v, R! g' _7 @0 b
  15.     }: X( k  g6 q1 N# V& r1 [9 ^7 a+ ~
  16.   },
    ) u3 e& O; X+ {
  17.   methods: {
    * O, j+ j! z4 S# p7 p3 S7 G
  18.     incrementHandler: function () {
    3 V8 d& k4 W, w# x' H7 o# R
  19.       this.counter += 1- L* b( |$ x% j) ~) M: |, e
  20.       this.$emit('increment')
    # z& d3 ~9 F2 S% r5 k
  21.     }  ?  x. }# e) u
  22.   },7 a* @* V( [0 z' R8 b% G( e
  23. })' Q9 `4 w4 l: a
  24. new Vue({
    9 ~6 [/ b6 H4 Q3 q: T$ K# g
  25.   el: '#counter-event-example',
    : n. Z% h5 K# v" b# U/ p$ p
  26.   data: {
    6 l+ b3 [. u' J1 F$ e: q% e
  27.     total: 04 F9 {9 t1 o- E/ A( P; r
  28.   },
    / Q- ]/ D$ e. H2 K- o* H
  29.   methods: {4 [7 s2 `* N7 X
  30.     incrementTotal: function () {
    ' s" g9 M7 V- z+ f) ^
  31.       this.total += 1
      T/ X8 Z/ o9 b4 u3 s
  32.     }
    ' s0 w& ?( N$ B& a  e7 I9 A
  33.   }. _+ M3 @2 |# x/ q! D
  34. })2 `+ E" {% ^4 p& n; E- P& _3 j# _! o, d  }
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册5 u; Z( L' J. |: x! t( O# {/ @
  2. Vue.component('child', {
    6 H1 H' N& C8 F3 w& z
  3.   // 声明 props
    - [% w& R0 n) d$ ^
  4.   props: ['message'],
    - @1 `2 N5 m1 S- V
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用! n1 Y3 {& w/ S
  6.   template: '<span>{{ message }}</span>'7 V) R* G8 V: ?  ~3 M
  7. })
    % {% f  c, k! W7 Q$ z5 o4 F
  8. // 创建根实例
    . A4 `/ v" n0 Z+ U) P7 x
  9. new Vue({
    * f! W; _1 d& L( b0 J. f2 [: M  |+ Q
  10.   el: '#app',
    / p' f5 X' @) ^( {* W, F
  11.   data:{7 H3 p* \0 ~; i
  12.     message:"hello",' {- w% D/ R8 F" h5 h
  13.   }  I) a: u0 E/ B1 N  i
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {7 b" E1 [, r2 q+ L7 m; a$ S
  2.     incrementHandler: function (v) {- d9 @, b3 f6 F6 z
  3.         if(v==1){
    % J# y  w& h. R2 K( d
  4.             this.counter -= 1
    & r8 ^+ \3 ^8 u3 o
  5.             this.$emit('increment',[1])
    : q) W* P/ p( \/ W$ M! J8 K
  6.         }else{
    / w( ^, g4 z4 z* I; j; q
  7.             this.counter += 1: `( v3 V: p  m. s8 A9 ^, E
  8.             this.$emit('increment',[2])5 \" p+ H) L# ?0 Z2 Y% e6 `
  9.         }% _+ F+ K! N5 m4 H/ ?4 u# L% L5 d8 F4 Z
  10.     }
    ' Q3 @0 R1 H0 Q( @4 ~8 p: _% Q
  11. }
复制代码
0 H, O) L; x% l+ `( a

" H" Z# n+ g- @* l4 a" C
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-23 02:35 , Processed in 0.125637 second(s), 22 queries .

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