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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15644|回复: 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,并使用它:
8 h; J# H( M$ g- g/ Z, x
  1. <div id="app">* ~' I6 X( r! e5 Y7 f% a
  2.     <runoob></runoob>  g) H4 ?# @; N
  3. </div>- N# q8 [/ J0 P4 R6 A8 U" l$ |( S) I
  4. + S8 |9 s/ l. k* y1 Q' t
  5. <script>5 g. A( R: k+ v7 T* w
  6. // 注册1 p  u, y# p# [  {3 G: v) Q. g5 o( B
  7. Vue.component('runoob', {
    1 v% X2 v; J6 O5 l
  8.   template: '<h1>自定义组件!</h1>'
    ! K6 J% y8 G" B$ ]7 \. M9 X
  9. })" _) [, P( c: S7 k7 [) \% Y
  10. // 创建根实例
    ' ]% S' y7 i: ]& K/ t
  11. new Vue({, U2 Y, e* j% u7 K  m6 f3 N3 E
  12.   el: '#app'
    ( Y$ u" h, ~/ m. h, ^% |
  13. })
    : U+ m2 Q0 V) ^# j, V8 w
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

2 h" S5 v* J" Z, Z! Q& q7 s* ^
  1. <div id="app">( \4 l0 p% J4 _" H2 U
  2.     <runoob></runoob>! A$ X/ J4 [7 p/ R
  3. </div>$ A! J5 ], L" ^  Q- C
  4. 5 R1 n2 d. K7 h
  5. <script>
    5 |' Y( Z! A4 H4 n3 \) G
  6. var Child = {
    + p, ~, B5 b' K, z; e
  7.   template: '<h1>自定义组件!</h1>'+ b7 |$ G" r  V2 v# B, r8 x/ O2 Q. {* ?
  8. }
    : d  ]3 M# F( N) K  c
  9. . [+ e4 S2 O! P0 d' G& \' W
  10. // 创建根实例
    * s) ]( A+ S  F, |# \3 U
  11. new Vue({  b/ P6 k8 J+ h4 U* \
  12.   el: '#app',$ u8 m! N( R+ Y( Z
  13.   components: {5 O4 B8 i! d" g" X0 c
  14.     // <runoob> 将只在父模板可用
    2 @" l5 P& F* _9 \( c: V0 w
  15.     'runoob': Child) y" _2 F  S  k6 q# T; D. N* H$ v+ R" k- ^
  16.   }3 ?5 ^9 {/ T3 W. r; l
  17. })8 K4 l, I0 @. T! W8 f* d- x9 d
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
' [* A+ S4 x* w2 ]  l
  1. <div id="app">3 P! Y# p3 ~9 O
  2.     <child message="hello!"></child>
    " N  G$ L: _" a: b7 W( G
  3. </div>9 A0 i" P$ J, y2 T$ G

  4. / B9 J3 V4 S2 ?9 q2 }
  5. <script>
    ! b' N: }8 }; ^
  6. // 注册! {" O' }! }5 h/ ?0 P; S) r
  7. Vue.component('child', {
    - {& K$ n) w9 ~- _, d
  8.   // 声明 props; s2 I* \( j( O8 [  z; V  a+ ]
  9.   props: ['message'],8 [8 _' m3 }, {/ w& {& R
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用- L$ h6 ]% B' O; n$ t& U$ t1 @  S
  11.   template: '<span>{{ message }}</span>'
    ' t; ?6 H2 c. a" V3 c' N/ s8 l
  12. })
    1 w: A- c# C2 J3 `$ t5 F
  13. // 创建根实例
    & Z: O: r' _3 c$ k" T
  14. new Vue({7 a2 G8 K  ~% R
  15.   el: '#app'
    ( g! ?; M0 F6 `' U# I. W! M$ p' m' ~
  16. })
    5 t8 a* L6 n7 H# U
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例( H! v- N/ z1 ]. s0 }" r
  1. <div id="app">. Y# `7 U, N9 q. ~" N9 q
  2.     <div>2 }+ }% z, k/ Q6 B) i) U5 ^1 n
  3.       <input v-model="parentMsg">5 b1 J2 T! K' \3 v( r2 r
  4.       <br>
    ) K5 `7 x$ d9 x# B, I  F4 o. U  q0 _
  5.       <child v-bind:message="parentMsg"></child>
    6 F0 P! K& M9 c! M4 I2 z
  6.     </div>! _$ l/ a  X$ ]2 C) }' f1 {
  7. </div>
    * n* x* X/ q& W% ]5 b

  8. 3 }7 c% f, J7 W, L
  9. <script>- P# h. Q( s  c& Z8 n/ T. J  L
  10. // 注册
    % i  O& T4 l( b& R* W
  11. Vue.component('child', {+ y( D4 Y) ]2 z1 J
  12.   // 声明 props
    4 p6 Q8 G6 W! U6 Z
  13.   props: ['message'],! J! G; u# W  w6 Z$ k2 M3 M1 M/ p
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用0 S( A$ z3 e( _1 x
  15.   template: '<span>{{ message }}</span>'9 N- T! ~: \4 y8 X5 ~
  16. })
    ' R7 l% F, `: O3 P& J" b* V: D( p
  17. // 创建根实例% Y3 N2 {' ~- y) p
  18. new Vue({' k; V* L7 t. h3 m
  19.   el: '#app',! Q& j! D3 d9 k' j) y( L
  20.   data: {
    ' c, _- ^7 v5 f- z  f
  21.     parentMsg: '父组件内容'
    3 ~+ M$ B9 m% t8 P0 p
  22.   }
    ( j8 M/ I' V4 ?* n" _, x! Q' z
  23. })( g% J" P- ?' C7 b2 }9 F
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例9 R/ y( q2 K. d( K% Z5 A
  1. <div id="app">
    7 x6 E3 z( o, B! ~& D6 l$ A8 W" \
  2.     <ol>
    ' v: H( Q( f6 q# s8 I# i! S0 K/ T" [
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    1 v, E) r( R9 p
  4.       </ol>' a4 x4 u, _0 g% X0 Z
  5. </div>
    " u' o5 B8 O' i
  6. 5 m7 P% o5 I/ |; K) X( C5 R# X
  7. <script>0 l5 X* d: q  S3 d5 i$ P) P' o
  8. Vue.component('todo-item', {8 k5 D& ^, j: ^3 L9 O: z  k
  9.   props: ['todo'],
    ' m" a1 c3 v9 V' n' F$ b  \  E& H
  10.   template: '<li>{{ todo.text }}</li>'
    ; R0 ]' c' a" Q9 ~
  11. })$ F5 `4 |: n6 [; F
  12. new Vue({
    ) K; a; Y% ]' [/ b1 j
  13.   el: '#app',
    3 l& N9 F1 u. w) X
  14.   data: {
    6 u/ G! _/ H. P2 z; e
  15.     sites: [6 k: D8 t2 R2 K8 j
  16.       { text: 'Runoob' },
    ' ]' R% X/ X5 `9 p
  17.       { text: 'Google' },6 ]  `/ f% E" `2 h) G2 \/ X
  18.       { text: 'Taobao' }, M" S0 }5 d) k. Y
  19.     ]
    6 w9 m- |$ V, F) Y7 E! B
  20.   }  z) q1 m: K" W3 y. h2 g
  21. })4 m  _* b1 i( h! D/ X7 O6 U5 O1 P% T
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    # F# `: \5 C! z, y% Y
  2.   props: {6 |: K6 `: p0 y9 E" H! H
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    7 G! G! Q  E. b1 u' o2 B
  4.     propA: Number,
    3 W$ D& ^; B8 E% C) K* D5 {- u- T
  5.     // 多种类型$ b2 G6 x; Y! n/ j  s; q+ D9 V
  6.     propB: [String, Number]," ~- x/ \3 Q% }: W. h) ^
  7.     // 必传且是字符串
    ( S9 x3 I+ _6 x, Q) o+ a, I5 U$ X
  8.     propC: {; _/ X4 I' g! \
  9.       type: String,1 T  Q+ B9 x4 R1 a
  10.       required: true
    % T7 x( [' r# v1 T% i* {
  11.     },
    * A3 U5 b3 Z3 `' D1 l1 \, }
  12.     // 数字,有默认值
    2 J9 m+ J) @$ v! ]* Y( K
  13.     propD: {$ ?8 Z, N! T9 g- S( k! u
  14.       type: Number,- _5 b: P% O6 O: j2 B( x: \
  15.       default: 100
    * l7 t. R+ P9 a( Y. M
  16.     },' A) k5 U5 `; m# t, ]* X3 c1 `' ]
  17.     // 数组/对象的默认值应当由一个工厂函数返回: B! Q5 z7 g$ X
  18.     propE: {
    : c6 U8 |1 s4 w* d' i7 E9 ?" c
  19.       type: Object,: b4 _7 d8 i$ |2 k3 W( U% d9 H7 T. e1 x
  20.       default: function () {  c! M/ J1 `; I" l/ ~: w/ P" K
  21.         return { message: 'hello' }
    0 G/ C4 t" C; W6 |
  22.       }
    ' k# \9 G5 s. Z7 ^
  23.     },
    0 `) [: U8 a( b' f3 }; G" g- ~: d
  24.     // 自定义验证函数
    6 w( h0 r, {/ Q7 W- M( x
  25.     propF: {; D7 g, U8 G( F
  26.       validator: function (value) {
    ; c6 m  Y- |0 L/ K
  27.         return value > 10# @& Q4 v) I2 Z: E3 r
  28.       }
    # P% [8 _2 L/ A3 r7 |: [
  29.     }9 _+ d! U! P. ~3 o- N& a3 y
  30.   }  g% {& U, X, v& \0 y4 Z7 V$ `- m
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array& H: S+ d, A1 `" |  R. j, n
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    9 v8 H, M! _/ O2 g% b% r  X
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例5 C2 L' r! N- k, d
  1. <div id="app">/ S2 w# e% y" M7 N! q
  2.     <div id="counter-event-example">
    & k5 o& @" T, Z: G# x' ~! N7 r9 ~
  3.       <p>{{ total }}</p>
    # t6 l5 z4 ]# g0 {
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>. f6 Y( W6 K+ B
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>: Z% [5 T" g" j+ ]6 x5 g: W
  6.     </div>- c2 D. d- b" f: d' q0 A1 }
  7. </div>
      W9 g; s! h2 i7 b2 u% p
  8. 7 R! D5 @7 j2 H, y9 k6 N
  9. <script>
    7 u9 e0 I; S% e" `9 M9 H; J
  10. Vue.component('button-counter', {9 W) `: y; r& [' O- s
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    : g( P4 K' h3 p$ q0 B4 C9 W
  12.   data: function () {
    " j% {$ d# |3 p6 C" ~
  13.     return {
    0 s7 V" t: Y5 E& y8 `/ U+ i( Y( e4 a
  14.       counter: 0; O" q$ u' K( R0 \! N" L0 o
  15.     }; f& M- n# F7 P9 A! e9 p& J5 [; c
  16.   },
    ) F* F% c) y# C  Z! G& U# [4 v
  17.   methods: {
    5 I7 {6 d' n8 F
  18.     incrementHandler: function () {: P9 r2 h) [& |% ]- }
  19.       this.counter += 13 e9 d" Z  {. _3 q
  20.       this.$emit('increment')$ q, f7 F& ^, U( L0 l9 @, s- H) B- x
  21.     }
    0 Q9 {0 N$ _  Y6 x' q5 l1 j2 p! W
  22.   },
    ( {  B+ |( q. ^& H" o( V0 `
  23. })
    , C! R3 H( h, b6 K3 z( M! o% p# v4 d$ E' U
  24. new Vue({
    7 y+ N; s; b2 p/ M
  25.   el: '#counter-event-example',1 z: H& z# Y7 l  {: J* r" Y3 c8 g
  26.   data: {
    " j- I8 C- E: j9 Q: o
  27.     total: 0* T- \4 Z* R5 z
  28.   },
    8 _) L$ F$ a) F- z- T7 {
  29.   methods: {
    . H# t! v. `! N# G
  30.     incrementTotal: function () {
    & G- E! c% o# ]: A8 V
  31.       this.total += 10 I( w: B! Q2 I5 Q
  32.     }: @8 h! a, ]/ K- |) ^* E# w: M
  33.   }3 P3 Z5 a# W+ f- i2 H. Z$ \
  34. })
    " y/ q4 ~" [' O
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册+ p. E( k9 [: M2 X  X4 J
  2. Vue.component('child', {- L% _/ A8 T5 s+ F. @
  3.   // 声明 props7 [6 p& @- z8 _  m" l
  4.   props: ['message'],5 x- R% j1 ~" S+ l5 G9 E
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    " s, L7 L: |% S, _  s
  6.   template: '<span>{{ message }}</span>'6 ~6 U: @! N) s# Q$ P: C
  7. })( W8 S1 l" [9 ^8 d
  8. // 创建根实例
    $ |9 F' u; f4 P" ^
  9. new Vue({
    . A  C. v9 L) K2 \5 }
  10.   el: '#app',# y6 q& S4 r; p" B8 ^
  11.   data:{
    % ~- Q' V* j  X, S; ^1 U
  12.     message:"hello",  Y0 A1 K8 X- s: ~  m
  13.   }
    3 C5 W9 s/ [+ X6 d1 W
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {" C8 j3 ^9 s. o: S" ?
  2.     incrementHandler: function (v) {
    ; |% e- m( B$ d0 h; u- \
  3.         if(v==1){
    6 B1 ]+ X" x) h7 _' w% i1 l
  4.             this.counter -= 1
    9 C4 t& [  q9 B5 x
  5.             this.$emit('increment',[1])
    # a) @4 }0 W/ G4 c) |) P6 b9 J
  6.         }else{4 K" F7 A( @  S# P8 _0 n
  7.             this.counter += 18 i# y: `+ i$ N/ B; F' j
  8.             this.$emit('increment',[2]); |6 [$ m1 L+ U4 L
  9.         }
    1 s7 P0 }4 n$ M! W# J
  10.     }" b0 q/ q9 \$ z
  11. }
复制代码
+ n7 r" P& T/ }, A

  j5 x5 P  }  E" ?: L# Q) h
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-4-30 19:03 , Processed in 0.065991 second(s), 22 queries .

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