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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 12756|回复: 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,并使用它:

4 w( j( H0 C) ^" Q
  1. <div id="app">
    % C1 {0 ^0 f- b# ^- m
  2.     <runoob></runoob>
    4 }) C# Y) e6 }4 l( s
  3. </div>% y" n. {8 Q8 d0 T1 ^- E. _8 u
  4. 7 _, j9 V/ Z% _* I& c
  5. <script>8 I; h+ g* y5 @* w+ j
  6. // 注册7 c' m: E# I8 V7 F) I4 @
  7. Vue.component('runoob', {
    7 @$ z. Q. X8 d) U
  8.   template: '<h1>自定义组件!</h1>'
    . ]8 p) W9 L% v! N* _
  9. })1 M; V( `! O+ n
  10. // 创建根实例3 q; B- r' o, ~' Y- {3 F
  11. new Vue({: V0 V) P* F0 A& G" x$ r; t
  12.   el: '#app'
    9 V8 w% v. Q/ v% O
  13. })
    1 o- ~# i% e$ Q- R5 W) b/ k
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
" Y2 @5 N6 O! s: t
  1. <div id="app">
      O- p* e" ]& E# k+ s
  2.     <runoob></runoob>+ k5 J- }: |$ z: Z  g6 c
  3. </div>- e. A0 \2 a3 `0 C, E9 q9 u

  4. # x3 _+ C+ |6 W9 U* W
  5. <script>
    " G& n7 a# _! }- f$ T
  6. var Child = {* Z' \( e) T  H/ g/ H' A
  7.   template: '<h1>自定义组件!</h1>'
    : K; V8 \6 y# ]1 j% Z
  8. }
    / y$ j  V3 m6 [
  9. 9 `0 {- Y  x1 k+ }
  10. // 创建根实例
    % O" p9 X9 ^5 |
  11. new Vue({+ U) q/ R' W" C: \" Y
  12.   el: '#app',8 K& q8 X+ t& ^
  13.   components: {. n: n* s6 D5 L( l) s
  14.     // <runoob> 将只在父模板可用
    9 o! ]4 W7 I% O2 ]
  15.     'runoob': Child
    ) @3 n" K7 Z  J4 w3 p+ p
  16.   }
    4 w1 O' G1 R, Z& }3 r# J
  17. })+ T9 j8 q4 F/ c4 H9 [4 J4 s. I+ C* a
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例" }9 J5 h+ j' p1 I. C4 r" W
  1. <div id="app">
    7 z. V( v- t4 i$ Y% M* v6 G
  2.     <child message="hello!"></child>
    1 \7 _( _& M: n# ]9 M. B$ B
  3. </div>" g4 j7 ^. T; q+ S: A

  4. 2 T) \: y' @5 `1 p- h! `
  5. <script>% \- W$ H; D' y7 f# O3 x% W
  6. // 注册
    2 D8 T# r, j# R' n
  7. Vue.component('child', {
    + @  X% o1 {+ c4 j; ?1 M: p! W, f
  8.   // 声明 props
    / f2 Y: T6 c. }+ K( G
  9.   props: ['message'],
    8 A- m  W8 r8 b* E) A- C
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用1 m; o9 y- g& f  s1 l6 l9 P
  11.   template: '<span>{{ message }}</span>'
    % W- o% c0 Z9 [# V6 S2 l$ e( e
  12. })
    3 b* z2 u) y* j0 j) e2 p* h' y" R% y
  13. // 创建根实例
    3 v2 S  A9 {3 k
  14. new Vue({1 ]7 F. l1 g, c% H0 i  Z) X# C
  15.   el: '#app'
    " O, X& L- L0 Q2 g0 }1 @" f1 A% N
  16. })
    " c9 S6 ?) I, `! b
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
& z  o% A, u! K+ e
  1. <div id="app">
    ; U4 O2 h) d9 f: b
  2.     <div>9 b! q# e; g( S
  3.       <input v-model="parentMsg">
    : v7 n6 f* }" U" j! m
  4.       <br>; C9 v. z% H2 a; x+ n# H7 C/ G2 G0 v9 I
  5.       <child v-bind:message="parentMsg"></child>
    3 p1 _, Z% r. u( U) j6 P, C, w
  6.     </div># }- c1 v9 E# H
  7. </div>
    6 W$ `2 s! {" i0 N; l7 V
  8. * a6 l% [1 \8 [# r) x% F% a
  9. <script>
    6 F9 f4 `  g! ~6 ^
  10. // 注册
    ' V/ h' q& X; [: b# C5 }
  11. Vue.component('child', {
    $ D! H) X" i" [7 C9 K
  12.   // 声明 props2 f; P7 W8 c/ y& u% f* X8 T+ E
  13.   props: ['message'],
    5 s$ t/ z! ^/ J4 Y$ Q
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用: F0 K+ H: [% y0 R. }
  15.   template: '<span>{{ message }}</span>'
    # A! q9 w  {2 z
  16. })5 F- l. r/ K& C6 U% m
  17. // 创建根实例
    , R' l7 k6 ~" Q& s
  18. new Vue({0 n3 O. S" S- o# f: t; B6 @/ b
  19.   el: '#app',
    3 V  w+ e- l' E) A2 t8 O' g
  20.   data: {  {; P. O& y& n; |" B
  21.     parentMsg: '父组件内容'
    3 W. I+ E$ g  u" k% V& ^2 O
  22.   }
    2 G. o( Y0 A+ |2 d) t) O! G
  23. })% R/ Q6 m0 X/ J5 E: L: j
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
* d- F( w1 q+ f" c, x
  1. <div id="app">( N+ V% b& s# d" U+ G: s0 _1 a
  2.     <ol>
    ( N2 d% l2 L: D
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    " @* D8 k7 s0 ]. ^. |
  4.       </ol>
    * I( M" e8 H# T8 X: r/ r
  5. </div>3 X" M! i# i, L0 f. A
  6. : t& A+ \( `$ S9 j6 `9 A8 X5 Q
  7. <script>' l, [$ i+ j8 }+ F8 z* @+ }
  8. Vue.component('todo-item', {
    & j* u0 k6 S7 e6 P0 g
  9.   props: ['todo'],
    ( U4 X* Z" K& y8 ^) i
  10.   template: '<li>{{ todo.text }}</li>'8 L& J9 B2 X; O
  11. }); e' G9 q# @! z6 d
  12. new Vue({! V& W0 B1 W' W2 d4 k( @
  13.   el: '#app',
    ( C0 K0 `' n# y% |4 |
  14.   data: {! C: z) j# U/ O0 d3 g
  15.     sites: [5 ~( d% K$ X3 e& ~. H& n. b
  16.       { text: 'Runoob' },
    - g# h: ^- r' h2 E7 }/ ~
  17.       { text: 'Google' },
    ' U7 x: A3 ^7 n" {
  18.       { text: 'Taobao' }/ i) d5 \5 z2 L, {& J/ Z+ b- n* \; b2 U. j
  19.     ]! B- L, j0 U8 C
  20.   }
    3 d5 R- `/ c7 h
  21. })
    / w9 j- f, _0 |  G" l+ K- w4 _" [8 u: U
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {4 L, ~( Q* W; `- a0 i0 f" S* k
  2.   props: {( M( X+ H3 I4 U
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)2 r0 g, V7 D; D
  4.     propA: Number,; h& {$ ]3 z! [; F& y: V
  5.     // 多种类型
    4 R- J$ t2 Z% K. V
  6.     propB: [String, Number],
    / R, Z" ~+ E. V! W) O0 a" f! I
  7.     // 必传且是字符串
    6 \  g' W2 w, S% V
  8.     propC: {8 s- e( x9 _2 j5 _& E
  9.       type: String,
    ) @) h. M% d1 |) g6 {+ R2 X9 O) F
  10.       required: true
    , C0 p) f! ?- B8 `8 l
  11.     },
    0 v, \! J$ v8 s: a) u; T
  12.     // 数字,有默认值
    " w; X% w, b0 Y, t& S; i  H
  13.     propD: {
    5 n4 f. O& r4 E' D" X& a  K6 q
  14.       type: Number,, p, t. P! R9 m# ^
  15.       default: 100
    # h7 W6 y6 j- E5 G2 K
  16.     },
    ; x1 D3 Q7 r0 A/ ~- _
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    % L, d8 |- O; ]4 _5 e! k2 i- c
  18.     propE: {
    3 f& U3 A  ]! r) V% i4 Y0 L
  19.       type: Object,# m2 W) w$ _" V' `
  20.       default: function () {% L2 \& L; Z$ |. g3 V9 V
  21.         return { message: 'hello' }. x( g0 z+ i. t  D
  22.       }
      i" P+ u; v7 Z9 Q, s1 {' o
  23.     },$ a1 {( @. H  l
  24.     // 自定义验证函数( V$ E" o7 y& I/ J
  25.     propF: {
    7 d6 [' J, V; u- L; |
  26.       validator: function (value) {
    . {3 P; ]0 s; b% p# l/ ?0 [
  27.         return value > 10, m% u7 [( |, P
  28.       }
    ! x* v, H3 e3 W  ]: q
  29.     }: f* v" J9 c9 y& r
  30.   }" k! J+ @( C6 {3 K( H0 C0 S* n
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array+ O  [9 U( I  Z7 N
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件, B8 W8 s6 Z6 v. C2 A# t
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例2 y: D' H' [4 A9 M" w* U' K" \
  1. <div id="app">
    / o3 Z4 P2 S6 G1 d! p
  2.     <div id="counter-event-example"># Q4 \8 v3 ?4 P) z' x
  3.       <p>{{ total }}</p>/ e0 e! v$ s1 d. A0 i4 Q; m' ?1 p
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    ) s4 U2 K/ R' B0 t3 U
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    3 R% L+ R; T' ?3 f* P
  6.     </div>
    # z0 y7 {+ G! K
  7. </div>% P4 \" k- r/ V: b

  8. 4 B4 G6 V; b$ U+ K/ m0 j$ G
  9. <script>
    4 N  A& a$ v( b0 G8 o9 f/ P0 {" w+ |- W
  10. Vue.component('button-counter', {
    2 t& _- A9 |) B, ?0 f' h" i& `
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    # R  \- Q1 V( O
  12.   data: function () {
    9 U- n& R$ L4 o* {- p2 I5 V
  13.     return {
    % e  Y7 V/ n* L- h+ e4 u# a
  14.       counter: 0& s/ E& b2 ]" z% C9 R2 Y
  15.     }
    5 }, z' \1 O1 ?! Z; j
  16.   },& g, J4 a$ r* K# Q1 k8 A: x6 B5 P
  17.   methods: {) r- q0 I' c1 W6 A: d
  18.     incrementHandler: function () {
      L3 O: x/ w  b) W2 c) f
  19.       this.counter += 1! @, e  Z6 e; F+ P
  20.       this.$emit('increment')
    , u3 I8 W6 E: a' M2 ~# ~
  21.     }
    ! \6 X. h3 d, }8 X* f) W8 l
  22.   },8 x% J" _; q* v1 F1 r+ p- E
  23. }), k& H3 y9 @/ a! M8 j  R: }
  24. new Vue({
    / ?2 P4 l8 R- A3 k
  25.   el: '#counter-event-example',
    : \3 P6 {/ g$ W4 e& u, V: V' n
  26.   data: {
    & \# c7 Y, Y% k5 E( u# ?# J
  27.     total: 0. @. v2 t% {; C, g! v, L  m
  28.   },
    * W  q0 A8 c, f7 v; [3 P
  29.   methods: {
    4 W0 S$ k8 u: k, l
  30.     incrementTotal: function () {$ @9 C; C  e) \* G- t3 H: f" @
  31.       this.total += 1
    * O- T7 o; @6 G* t& }( K6 Y
  32.     }
    1 V) }# W% e8 a8 X- J7 v& F
  33.   }# q0 _& l5 {- J3 T
  34. }), h, F: G7 d# `' k' J
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    0 p) a* Q3 |5 L/ X9 y
  2. Vue.component('child', {' S. T1 ~0 S) g5 D6 N2 Y
  3.   // 声明 props$ J7 I+ I' M& c% j
  4.   props: ['message'],
    6 ]& V9 g- A7 A2 v5 {
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用$ T5 J5 \7 |; V- n
  6.   template: '<span>{{ message }}</span>'2 l4 {% `5 V1 o2 |, U: R1 T9 J
  7. })
    : Y% b& Y  g0 D
  8. // 创建根实例& }/ c* }5 c! V$ H& {- b+ A% m; u
  9. new Vue({
    ( k8 F- E. _" p
  10.   el: '#app',
    1 A; E/ }% F, b2 {
  11.   data:{
      i- M' `( _- u9 x( m/ B
  12.     message:"hello",# ?3 W1 i; f. `2 `: B
  13.   }
    % j$ Q, ^0 r, j, v* b- E: f
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {7 L! t$ g5 B7 {, s1 u
  2.     incrementHandler: function (v) {8 F1 X, }) g1 D  _$ T1 Z2 _  C
  3.         if(v==1){
    ; O& B  i5 l! }  u4 V
  4.             this.counter -= 1
    ; p' @/ l, r4 K+ B# w# L
  5.             this.$emit('increment',[1])8 j8 F& O& F2 |; Z! O9 D$ G
  6.         }else{
    + _( B0 |  ^( P/ m% L. o
  7.             this.counter += 1
    " Y  `7 p( k  Z" ^8 [
  8.             this.$emit('increment',[2])/ @5 o% i1 U6 \; |
  9.         }5 B; s: Q8 Z5 i7 x9 j  K
  10.     }3 X$ ^5 ?4 d6 s) G: s
  11. }
复制代码

+ `9 i0 |: u& X! ?" d
9 ^: Y2 M$ v4 Q% }5 f9 Z
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 15:51 , Processed in 0.142581 second(s), 23 queries .

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