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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

7 [8 X' E1 L9 b: @8 m% g
  1. <div id="app">
    * v6 a9 z, S; p; e; @
  2.     <runoob></runoob>7 R  s3 S8 h1 s8 N! s# w9 \, v  T
  3. </div>! Q/ d' z! E7 L# C% o  D
  4. * \7 ?+ L8 h9 W, |3 z
  5. <script>$ x: m+ J* }4 {8 o  Y1 T5 F3 J
  6. // 注册) E. {  n& j/ L8 S
  7. Vue.component('runoob', {. |: |, c) y$ P" v  |& e! Z$ n
  8.   template: '<h1>自定义组件!</h1>'+ O- P# }' t+ K# G; w. q+ x; L
  9. })
    * t3 n; K; [) E
  10. // 创建根实例+ z6 V8 p/ D5 b9 u! f. c5 k4 T8 @
  11. new Vue({
    ' C- U8 @, G  R, C! N
  12.   el: '#app'
    1 k6 F* D: R# N4 I" m" r1 T7 i$ s- `
  13. })
    ' `" o5 G0 E% z
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

/ i9 k, A; H/ ]( u; T; S1 d
  1. <div id="app">6 c5 V. A- T7 O
  2.     <runoob></runoob>
    ! N; y* g1 b0 `" ~1 W- r
  3. </div>
    + f) r- u2 z  L+ @6 A
  4. 5 D. K% }9 X3 B! ]
  5. <script>
    ' D! \$ B. W1 @! w. \4 u
  6. var Child = {: X6 `/ b) W! l: O/ O
  7.   template: '<h1>自定义组件!</h1>'
    $ y" S: U( \( ~/ }6 e& F5 K
  8. }1 U7 ]6 I: y; U$ u6 l

  9. + x7 z0 Z3 [' U0 p8 U' ]
  10. // 创建根实例
    9 Z! q/ w1 B! M
  11. new Vue({6 E" J8 n) s( s/ T8 `2 c
  12.   el: '#app'," Y8 ~6 ^4 q1 k' z2 i( v. F8 m* A
  13.   components: {
    + l8 X- P3 D" C$ `
  14.     // <runoob> 将只在父模板可用
    7 d; T4 [3 a( o/ s) G( T
  15.     'runoob': Child
      f3 Y' y: z+ w* N( ^; h
  16.   }' \' N- K) |- F! H7 P
  17. })3 n# I. P  b% w, W1 F
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
( i3 P' @; ^# ]
  1. <div id="app">$ l- M( w: g: f0 ^% \
  2.     <child message="hello!"></child>9 C! m  p2 n/ i3 k. M8 X6 x3 J
  3. </div>0 {5 t. F5 i4 u4 [0 J

  4. 4 I1 T7 e5 n. }- K' I0 a8 E
  5. <script>$ ]- d1 J3 T5 N$ |( G9 M
  6. // 注册
    ' C) H$ F- O& i: D4 I, h% X/ e
  7. Vue.component('child', {' v$ D' \+ v, M( |7 f
  8.   // 声明 props' {9 n- [8 }. i( v
  9.   props: ['message'],. c4 d, G6 \) o+ a
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用$ H4 p/ ^" w" _+ S
  11.   template: '<span>{{ message }}</span>'
    ! i3 s, y1 _  ]2 E# T/ l& F( T
  12. })
    $ I- E+ j# H- J% K# ]
  13. // 创建根实例# ?" R4 ^6 ~5 V4 h( m/ T0 H  C
  14. new Vue({- [+ p! u3 E) o6 W
  15.   el: '#app'
    9 K6 j, R' o, L0 \) o$ @" N- L
  16. })8 o4 S5 P/ G# X/ y
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
* X  h: g3 D  a( @- X3 e
  1. <div id="app">8 P! }0 c; ?8 W$ \" t
  2.     <div>* l7 D( O! T: |7 o# }
  3.       <input v-model="parentMsg">, }9 t+ Z& j/ M  I5 k7 Q) }
  4.       <br>
    $ z7 l/ |) {+ [, c6 m. Z
  5.       <child v-bind:message="parentMsg"></child>
    2 d. ~7 {/ s  d  P* S
  6.     </div>
      C/ I" x7 S8 n- r5 `) |
  7. </div>
    5 z( P; X; z2 i$ s8 R" l' C

  8. 0 {6 q9 S' z* I7 ]! Y
  9. <script>( [- g+ S& u, D2 {" C) ^. B
  10. // 注册( z, h% J! ]0 S6 ~8 B+ R- H# Y) S, X
  11. Vue.component('child', {( q( D# [( \# t8 ~1 V
  12.   // 声明 props
    5 X4 i9 g" [7 q7 j( Z; `
  13.   props: ['message'],
    * E6 p( R6 j5 D" n
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用2 L) A" s, E4 c  a$ p+ h, q) ~9 g0 |
  15.   template: '<span>{{ message }}</span>'  q: W! e% K6 G2 {. m: O- G
  16. })
    - b$ J' r/ i! v# U
  17. // 创建根实例, i$ s# R( Z) C; e* F0 {# a4 P
  18. new Vue({
    + k, B: w; a! X& _4 C5 l6 H- H
  19.   el: '#app',# Y# O2 w2 \8 S7 f' e3 B; s
  20.   data: {
      j0 w6 u' e" J  X6 u: B$ |
  21.     parentMsg: '父组件内容'' M) r# U) j; o( D9 e
  22.   }3 S, F+ r) b2 m
  23. }); V$ p' a( @) p  r7 W* f. a
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
( u8 }9 a/ C) _+ [' d5 M  x' O/ W
  1. <div id="app">
    . D* H) J) ^- U
  2.     <ol>
    ; u5 \. T7 }, X9 d: L% L7 a7 J
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>: E: {. @' w% n2 U, v0 {
  4.       </ol>& ~2 a2 }+ N# {! ?7 @) Q: ^2 Q. X
  5. </div>
    / o* P+ r3 X# n, O$ M/ T
  6. 6 U3 g2 f6 Q: E- G( J( T
  7. <script>
    4 X7 v6 Q6 W1 y* x1 Q+ T
  8. Vue.component('todo-item', {6 D* |8 P) X8 j. U
  9.   props: ['todo'],8 \! o3 ~) A4 |% Z/ l- _3 t
  10.   template: '<li>{{ todo.text }}</li>'* O( K$ D/ ~$ U5 T2 R
  11. })% K! ?, K6 ]6 T5 Z
  12. new Vue({
    6 X1 J$ @% s# Q# F
  13.   el: '#app',4 K- v6 V0 b+ E2 k5 \  ]
  14.   data: {, z6 Q6 _* K0 C- O
  15.     sites: [9 t9 \/ m. K- \
  16.       { text: 'Runoob' },- u9 B+ n/ s3 W! A$ ?/ E
  17.       { text: 'Google' },! _1 o3 \7 r/ Z5 z& @: H
  18.       { text: 'Taobao' }
    " g1 A7 @5 `/ s% H
  19.     ]7 g+ F8 {; y' a2 Z
  20.   }! T/ `- Z) M7 c' f& o
  21. })& i. ^" t) f; M/ d( H5 F, T( M
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {. W  \& G+ C" g) H) o
  2.   props: {
    ) K! H+ d9 x* d
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)5 ]  Y) T2 R/ ]9 Y
  4.     propA: Number,
    & r. o# D1 c0 k! k
  5.     // 多种类型  g/ w* |: s- c7 e; ]
  6.     propB: [String, Number],
    1 k# h0 K* p* Y8 N, ?% M
  7.     // 必传且是字符串
    , V- y: b3 `) E
  8.     propC: {/ L( _  U: ~$ t0 ?* Q  c( _4 j
  9.       type: String,' {: _. E' ^: u1 Z  @  f9 X
  10.       required: true
    % ]3 n0 Y/ y! X6 ~8 O8 U" H
  11.     },
    ; ^. [% }! W) \# g
  12.     // 数字,有默认值, W$ @1 ^; p+ ~5 x" T, N3 E6 u
  13.     propD: {! V! l" j# _8 t# Y1 ^7 ~
  14.       type: Number,
    , }! V) X- i1 y( Z; b: k+ m/ U4 R
  15.       default: 100
    1 |  D% H5 F; n8 N! {3 l. l
  16.     },0 u1 B+ |1 h* A* T0 P8 m. F
  17.     // 数组/对象的默认值应当由一个工厂函数返回9 J& j6 x& ^) z
  18.     propE: {
    ( J6 z' w6 k" x" \, s
  19.       type: Object,
    - N, u  x7 J) F) L4 J* J; [* m' _
  20.       default: function () {' x6 z$ U( ^: ~* W& r$ V
  21.         return { message: 'hello' }7 F; U) B/ G$ z% d5 o2 i
  22.       }% j4 s, f3 `! [' u) ^* M+ s* O! M
  23.     },' V" R7 Q5 v* ^
  24.     // 自定义验证函数
    . H$ P; ]- S+ j* Q3 \4 w5 S( U7 d+ W
  25.     propF: {
    4 b3 y9 \* v- W" u2 h( O' E
  26.       validator: function (value) {
    * m% o" d* O* n" P) D
  27.         return value > 109 \# g* T# m- _& @) S5 }4 T
  28.       }  `" L1 z" h8 E+ J6 L8 L
  29.     }
    : b$ N6 l7 |. V8 Z7 t
  30.   }
      u1 B9 |5 T! K
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array$ E3 u6 l5 U' `/ i
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    2 ]1 m. @% Y6 I0 ]0 D% T7 M
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
5 g  M  A- P: v4 L( i  ]
  1. <div id="app">
    . b( N, N; C  d0 D+ Q
  2.     <div id="counter-event-example">/ e6 I0 z" i, t# F& W
  3.       <p>{{ total }}</p>$ y  n, u1 g7 }' k  a5 W& N, m
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    " P9 q# y. I1 _) K
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    1 @$ [( h" t/ U+ y7 s5 @
  6.     </div>7 `: s: E4 ~9 f6 P5 @' Q. G, ?
  7. </div>1 K; N( S; T- N0 i0 e; o+ p

  8. & t) Y/ A# V4 X$ T" l5 v+ Z
  9. <script>4 y7 y2 Q8 W5 F+ A. I
  10. Vue.component('button-counter', {
    # K8 \( I4 Z* l* R' {
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    / T2 I$ k0 q8 Q6 ~
  12.   data: function () {+ @' b1 k% h2 S6 @1 k
  13.     return {
    $ N1 b  \* ?0 q( G
  14.       counter: 0
    6 u0 Y! P: H' Q8 B0 ?( P* X
  15.     }7 Z2 r' B' {# l  _
  16.   },
    7 X$ d8 \) E% h( x' o
  17.   methods: {
    5 ]" e/ a, y8 @- o# f
  18.     incrementHandler: function () {( Z& L3 n$ m, J$ @2 {: c0 j, o
  19.       this.counter += 14 s# X8 q7 J0 z& t. ]4 ?
  20.       this.$emit('increment')
    8 x, u7 V' g5 [
  21.     }( W# F' t3 i3 K, I: e9 p9 Z
  22.   },& g1 k0 {: ~& l, k% V
  23. })
    $ t1 m7 W$ _; a  S3 R+ X# J
  24. new Vue({
    ) B3 \/ L/ i4 v% R" h
  25.   el: '#counter-event-example',
    , p# D9 f: y+ l$ H2 X& I. B
  26.   data: {
    0 Q8 ~; s* G$ l3 T
  27.     total: 03 d- Y* `/ ^5 o0 {* a5 O, H
  28.   },
    8 F* q8 R0 J5 e% q/ Q5 u" S# ^6 `
  29.   methods: {
    , N7 [: T% l$ ~& L7 }+ P% R
  30.     incrementTotal: function () {$ X. l* [  P; ?
  31.       this.total += 1
    ' U, d% u1 a$ |- H% F$ p9 X& D
  32.     }
    % r9 C9 c0 M2 I& i( s0 n
  33.   }
    1 Z0 Y) k8 r, y8 |5 O$ n
  34. })
    % A; ]5 m' I4 N  X4 D
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册0 v2 l1 S8 S, s
  2. Vue.component('child', {, C# r! r0 v" _8 T5 O
  3.   // 声明 props! G( u! {5 K/ o( `6 w& a
  4.   props: ['message'],
    ' u' N4 V# `7 q- G! v& l! v3 z- Q
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用/ p; [$ ]8 f" _8 I" E' \6 `
  6.   template: '<span>{{ message }}</span>'
    ( A' z' n0 a2 _! O& U
  7. })# T8 [( @8 A0 T4 ], l
  8. // 创建根实例
    9 o% m$ G' h+ z7 i6 }
  9. new Vue({
    , y- y9 }- Z4 u( l, r
  10.   el: '#app',
    2 ]! g3 f$ Q# R' b" c
  11.   data:{" }2 g0 m+ D6 X; B3 n, b
  12.     message:"hello",- f: J/ X: e% d
  13.   }: l9 @% E* c$ T1 v! W7 o: K
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    ( g% O. G) G: S5 F" I
  2.     incrementHandler: function (v) {2 U3 t0 A3 ]6 g- X
  3.         if(v==1){
    1 |2 E$ v$ F! y9 b
  4.             this.counter -= 1* J2 D0 Z8 Z- T- L9 D
  5.             this.$emit('increment',[1])
    $ P8 H0 \8 l1 q, y+ [1 x
  6.         }else{
    / F6 \& h+ k- ^  Y+ N3 H  }
  7.             this.counter += 1
    " j7 e! J. b5 k* M: F! W
  8.             this.$emit('increment',[2])
    , m; [7 }3 E( T, b2 b5 c
  9.         }
    . t8 v' w( v, x+ j6 n
  10.     }
    7 B7 E, V' W% m9 {
  11. }
复制代码
# |) ]; S: j& R# j/ ^* E! ^% V% n
  V3 c. ~. x) C$ a; S2 K/ T
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-19 13:41 , Processed in 0.169830 second(s), 22 queries .

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