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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 12744|回复: 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,并使用它:
, J+ L% C9 n/ S) C: A2 g
  1. <div id="app">
    : Y" \& L9 H1 m2 h0 |% x$ A$ n' p
  2.     <runoob></runoob>
    $ {+ I. F/ a/ n4 [' t
  3. </div>
    ) n/ z0 v/ p  x; e; j- h

  4.   }* e& k! l9 E3 y1 _: g
  5. <script>: Z: r: M, l" k: ]
  6. // 注册
    ( R4 r2 S3 T2 V$ g
  7. Vue.component('runoob', {/ K! E$ n' v  h, U- S
  8.   template: '<h1>自定义组件!</h1>'! m) X# n8 P/ b0 q
  9. }), z9 W: k5 f  Y1 u8 D: K
  10. // 创建根实例
    3 Z0 B* u4 H. |
  11. new Vue({& G* I5 Z8 s/ S( ^
  12.   el: '#app'
    ( L+ O3 e( c# D, F0 p
  13. })
    7 \/ l0 u8 _/ h4 N/ A% Z
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
4 C5 G1 V* l" n: g: z2 X" k
  1. <div id="app">
    ; A: d9 R5 _5 h) {/ }) v0 D
  2.     <runoob></runoob>
    3 p$ T4 v& e: R$ H
  3. </div>% |( M" p) b& J" w# ^6 b4 U

  4. & {& x1 [" ^+ T" M; ^1 L* Z
  5. <script>
    ) p% j; ^- {& j- s" m+ n; X+ C  y
  6. var Child = {
    0 q. y# y& U+ G! a
  7.   template: '<h1>自定义组件!</h1>'
    . |5 W7 }( Y. q+ h# m6 Q5 e
  8. }
    ; y7 C+ `& g: D' [: c
  9. " R: F8 a2 [  z. D
  10. // 创建根实例, ]& \# \) o9 L. J* t& y! H# S
  11. new Vue({
    5 b+ f, K) B# t, D7 z4 N& s
  12.   el: '#app',$ d! q0 L/ o& B+ z* O  Q( _
  13.   components: {3 U& V1 p4 p' Z% w8 Q. |
  14.     // <runoob> 将只在父模板可用
    ! g7 }4 _  Z7 P! q2 n8 k, w6 E& v& ]9 P
  15.     'runoob': Child
    / P5 h+ i* l# P9 u& X6 ~# Z2 @
  16.   }
    ; ?% w! ?5 ]  Q
  17. })7 {/ k! q6 F4 _
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例- O3 |4 A  I, @8 b7 p2 y( d! s
  1. <div id="app">. Y* A7 X2 C& u- n5 r
  2.     <child message="hello!"></child>
    * o9 x) D0 i; [$ u
  3. </div>
    6 g% \2 W7 L+ f, p) m- Z) V

  4. + ^6 }% m) b! C8 s
  5. <script>
    : N# v% F  \7 ]1 z% m+ l
  6. // 注册
    3 _+ g) r, X7 S. X' a
  7. Vue.component('child', {
    ) y4 G' H8 {" b; S
  8.   // 声明 props
    6 [1 g4 M* R9 v6 f' c9 I8 h
  9.   props: ['message'],+ n9 u- u; K& f5 p" K
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用6 o, ]- G6 V1 N: |# Y2 M
  11.   template: '<span>{{ message }}</span>'
    8 `0 d! t8 [$ ]4 _) d& B% X- j: H* L
  12. })
    . z  \. I7 n- r% R
  13. // 创建根实例
    % h5 j+ K1 s; F
  14. new Vue({
    7 G" @" J: \, k
  15.   el: '#app'5 L1 \! H/ k& p0 z- l2 R& `! r7 I
  16. })
      G( `6 F+ z2 z; D$ f5 {
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例2 x4 d- \/ \$ J0 j
  1. <div id="app">
    ; C& F" h: l9 |' y. }
  2.     <div>
    5 Y, E4 K& o* v( l8 r) S, L0 U( P1 k
  3.       <input v-model="parentMsg">
    9 O. [( R: r7 }' G! a
  4.       <br>4 d/ q3 V% D3 g; F
  5.       <child v-bind:message="parentMsg"></child>
    : B5 ?8 N, o; A: c4 S. Y. ^
  6.     </div>
    $ m* r; S9 ^8 R1 E0 m! _! |
  7. </div>
    ' e) W7 r& T* n1 x
  8. . I% ?/ m; H2 i% C8 `5 D6 T7 o
  9. <script>
    : |* u5 S- p/ a# m
  10. // 注册1 h3 W7 s! e  D+ r' _7 K
  11. Vue.component('child', {
    ) h5 y4 L, C- V
  12.   // 声明 props
    * h$ h* e9 r+ U1 t2 s; o
  13.   props: ['message'],
    # V3 m6 y/ q. b) N9 ?
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用$ x: a- d: U. u# ^) l9 z
  15.   template: '<span>{{ message }}</span>'
    0 X  f/ U( {4 k
  16. })
    9 G. D6 ]& {6 x' W4 d. a7 M
  17. // 创建根实例5 p  u, Y$ e) s+ y0 U
  18. new Vue({( k: G& y: }9 ]3 J7 r8 c
  19.   el: '#app'," A7 n& B6 B7 s8 ~, O" T1 ]8 Z3 j
  20.   data: {5 ]& H- l7 c, m. U
  21.     parentMsg: '父组件内容'1 {& z. |, F0 G
  22.   }2 e! A3 h0 q' r
  23. })5 j- Q6 m: j! U( u9 _
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
' p9 _$ ?+ r3 N: [8 F
  1. <div id="app">3 c! ~% Y( z# Q& u: s, i% u
  2.     <ol>" k! ~4 ?6 ~! G0 O0 p
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    $ I$ k! z% t% M0 y  z( f
  4.       </ol>- }+ q' @  f, N; O; b) m
  5. </div>
    / v6 _6 K" z; T& m
  6. & M% N, B) G6 L' P0 W* A% F' g
  7. <script>  q+ d7 s* l' a; }+ N) N: F% p% G
  8. Vue.component('todo-item', {
    - W$ i2 S0 N& Q$ V0 f1 W, B! _
  9.   props: ['todo'],
    ! Z2 ~0 R4 V# f- y3 A) _1 O
  10.   template: '<li>{{ todo.text }}</li>'
    . P) c# ?4 s/ m+ w; ]* r* j' S
  11. })
    , f1 _# B2 h( w, x
  12. new Vue({  |* S! T3 @4 Q( _8 K7 ?
  13.   el: '#app',
    + _/ M" x& E" f  k
  14.   data: {! N' m3 W. U: |: S: v( G  B
  15.     sites: [
    / r) y' b' h7 [5 e0 G7 |
  16.       { text: 'Runoob' },
      i; o% \/ R& i2 L
  17.       { text: 'Google' },! V- A* ?; B7 U, B8 H) Z* [
  18.       { text: 'Taobao' }
    9 X: t1 a) j/ }5 o% O, A8 }
  19.     ]
    2 h0 Y1 k# n' j; ]. L
  20.   }9 A! ?- r3 u- a  ?% m
  21. })" x4 b* L- p7 g. |* F1 Q0 l7 p
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {5 J; J; d8 T: e% K8 G1 v
  2.   props: {
    ! d3 ]8 s* d! b3 n$ N
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)% }& `5 W% _5 B5 s
  4.     propA: Number,
    " f2 d/ S3 U  U6 J0 z
  5.     // 多种类型
    9 L# A/ Z' f0 m% q5 F) A! B# Q2 C: ^
  6.     propB: [String, Number],
    3 T! C/ x# m) h, P' k$ o
  7.     // 必传且是字符串" U: A% A9 U, m/ ~, B
  8.     propC: {' w( ]5 F  v# J' Q1 v0 e- r: {
  9.       type: String,& y7 @& _. l  u: ^; K2 T) }
  10.       required: true9 g* m( q- b& `; F/ H
  11.     },8 Y) O4 Z( H4 o" g; \
  12.     // 数字,有默认值' {: w0 A6 j* L+ B8 K. ~
  13.     propD: {
    0 [5 K4 n. h6 y4 F" Y$ h2 f6 b- |, m
  14.       type: Number,' o0 L3 w  W0 W  T0 p
  15.       default: 100
    ' w7 Y5 L! w* B# `: f
  16.     },( u- b5 {9 U0 d$ S7 G
  17.     // 数组/对象的默认值应当由一个工厂函数返回6 Q, @4 G( R1 c/ X' e! T
  18.     propE: {8 n2 L2 j, [& Q# W5 o
  19.       type: Object,
    # D4 N" V  e1 }! h! V( Q
  20.       default: function () {
    & B! ?: S3 h7 E! J1 d% f0 ?3 h, V
  21.         return { message: 'hello' }
    ( ], C) @2 a' Z
  22.       }8 h2 {, R9 M# R- i6 q1 E6 N
  23.     },
    / n% R+ @, x# F( ]
  24.     // 自定义验证函数
    6 {. H% A; ~! P2 m7 m
  25.     propF: {) s8 M6 i% ^" z
  26.       validator: function (value) {
    * i' z  E. T* V$ E
  27.         return value > 10
    1 @) ~8 X# b) q# d& }* c
  28.       }
    ! O4 b/ s8 l8 x( H
  29.     }# Y/ f9 q; X1 E4 C
  30.   }
      k% s/ Q8 B, p5 ^' u6 P
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array4 e; k/ p# ]4 D- y' D- y
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件& q# l  Z) l& s4 l9 v
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
5 F! ]( k8 O. e6 C5 G. F
  1. <div id="app">
    3 j+ P0 F6 Z0 m1 b6 l! }
  2.     <div id="counter-event-example">
    0 ]" C. O, r9 g# `0 k5 @
  3.       <p>{{ total }}</p>5 m5 v. _) j6 T$ K! }0 x  Q4 f
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    / L, G2 \# {2 {4 x' P
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>" k! I1 v. t+ c. d8 O6 z& a8 K
  6.     </div>
    / g; s, ?, T' H0 h
  7. </div>; d5 P$ k: O( f# C0 I/ K
  8. ! E- u- a& u- n
  9. <script>) U9 d. m' B) G5 _" P; L. r
  10. Vue.component('button-counter', {
    3 ~! E/ s4 P/ T2 y
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',6 ]! h# [+ c: }" R; `, X3 k
  12.   data: function () {( Q1 z" i* _0 }5 h& v/ m  W3 O
  13.     return {
    8 S; y5 z$ N  V) v$ H4 U
  14.       counter: 0
    1 T2 ]. {0 w0 |$ U' U7 b$ w
  15.     }! e) I- N. J$ y; p
  16.   },
    9 }: ^8 d. E. f, ^" p( x; O/ G
  17.   methods: {
      q3 N: C- W9 P
  18.     incrementHandler: function () {: v9 g; j, g, K3 ^9 y* U
  19.       this.counter += 1$ Z$ j+ ?) ^0 s8 O
  20.       this.$emit('increment')
    9 C8 j/ |' ?: o8 R
  21.     }
    / v' M2 A, m8 v6 ]+ G; G& r
  22.   },% s& E) {( J* c  d6 K3 }
  23. })! F6 M2 I' S. y2 V/ d' T9 v0 ~
  24. new Vue({
    . Q" \1 m2 a" _! x
  25.   el: '#counter-event-example',
    - g5 Z. P% G4 N; m8 v
  26.   data: {8 d( M4 S5 u1 D6 I4 J8 d" l. R
  27.     total: 05 I6 q8 n! n: r6 b' ^' U6 L
  28.   },
    1 I( `6 i" ^! F' n
  29.   methods: {. n" _9 N; q& x( x
  30.     incrementTotal: function () {) K$ ]- N: S8 A0 Y
  31.       this.total += 1+ e/ u& ]5 f' e9 O4 `
  32.     }
    " W% P" Q  X2 `8 v. X2 y0 d8 f# g
  33.   }# E7 i/ ^3 |& J2 z# r) L
  34. })- D9 F# _* S) S& l' w
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册5 I! A- M/ ~. G# |& I* Z: t( _% w
  2. Vue.component('child', {
    8 T: J, i& ~, a1 B8 [2 Z# k2 b
  3.   // 声明 props
    % p; ~$ ^) T; B  R' f8 V4 ?  I' h
  4.   props: ['message'],
    / E9 I' }+ ]# G4 P  L% l4 K/ ?
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    2 C9 D+ ^1 g" p0 Z
  6.   template: '<span>{{ message }}</span>'
    - R; j, F2 c" z3 I9 v
  7. })3 G2 _3 O1 L# L7 g4 w5 y: G
  8. // 创建根实例3 I! S$ H& r2 ?
  9. new Vue({
    ; f5 R0 d5 z0 i. C" E
  10.   el: '#app',6 ~. P# \5 ^" q
  11.   data:{
    9 b) `; j' k) h0 R- u* d. \0 l1 i" w4 U6 A
  12.     message:"hello",5 f$ r$ H& K3 l( o. p
  13.   }9 Z- d- `+ |# V( V) B
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {4 y/ L+ A8 n1 o3 q+ ?9 l
  2.     incrementHandler: function (v) {* g4 p; S* R" J: l( t, q
  3.         if(v==1){7 @! R! \+ Q( E# N" F, T
  4.             this.counter -= 1, f+ R% p% c$ Q$ ~* _* v
  5.             this.$emit('increment',[1])! i) R+ [3 C$ C1 q* q  I+ v; D2 t( r
  6.         }else{
    3 ~" E, K: ]$ b9 u# ^  J: o
  7.             this.counter += 1
    . v, K1 t* p+ c9 x9 o; d# t
  8.             this.$emit('increment',[2])
    ; u" v& j. I/ t- g0 j1 k
  9.         }7 T+ d/ S1 O  D1 ~2 }$ |9 X; N
  10.     }
    * W5 @2 L7 C' }5 E& V$ T
  11. }
复制代码
8 [: g! l. E3 N( e; D) Z  p

% j6 K  T; }. J# n/ q% q
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 11:01 , Processed in 0.147540 second(s), 22 queries .

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