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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15837|回复: 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 L* R7 P* j0 T
  1. <div id="app">( q+ W$ Z' {  w! f4 C) r
  2.     <runoob></runoob>; b: S/ [5 \6 q9 B4 ?0 C/ G# z6 t7 p5 }+ \
  3. </div>
    / ~8 u1 E; l5 }) v% g  O
  4. 9 U2 e$ ^/ f9 o# |$ i
  5. <script>
    0 |1 q" d# U5 g, ?3 E1 o3 U
  6. // 注册
    1 d" X. R7 J: N+ c
  7. Vue.component('runoob', {
    9 `  F) C2 }: }; U3 h% W
  8.   template: '<h1>自定义组件!</h1>'
    ; N' F' T2 F, g/ h% m0 }
  9. })+ J$ A8 p' I7 Z2 J' ~
  10. // 创建根实例" c- A* |. ^" `7 b: t+ K; r, h( v
  11. new Vue({1 @9 q5 m3 |* F, [# z9 u' Z
  12.   el: '#app'
    ' e) [3 _' Z& q1 g0 v6 _  M$ E
  13. })5 a" u( D5 v9 b3 |' N0 e% m
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
" h- m8 g" ~8 V  I9 f6 K
  1. <div id="app">8 B$ t" n  F2 U4 X/ H
  2.     <runoob></runoob>
    " h  ]" v2 K# ^
  3. </div>7 L; i6 y6 k5 v7 C
  4. 4 s9 U, v& N3 a$ X6 E$ A
  5. <script>- ?. r3 \  B. {* @7 R
  6. var Child = {- {) ^8 I  i. _4 M1 f
  7.   template: '<h1>自定义组件!</h1>'
    ! Y2 ?# M* i8 x! y2 b' @
  8. }
    $ s3 P; \" L) i! ]- M5 k+ l5 Q

  9. 8 f& y0 E; B# c5 L6 a4 u! f: c; c7 m; K% f
  10. // 创建根实例
    / \9 N& E0 ^" B8 _% o; ~9 \6 v
  11. new Vue({# K: K: v  H: o: v+ |$ F
  12.   el: '#app',
    8 R! E+ K. e# P; f1 K
  13.   components: {
    ' P. p1 e( F0 \
  14.     // <runoob> 将只在父模板可用: R' s( Z* V0 S6 q6 I# g5 W
  15.     'runoob': Child
    / [+ ~( R( @* I% V) O
  16.   }) Z$ G8 z) n% ~+ I  B
  17. })8 ?$ e- l7 T+ i1 q/ t
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例5 Q( t/ z; e2 T% `" o" l+ @
  1. <div id="app">6 a: I, d2 z5 R% D4 p' n  Y
  2.     <child message="hello!"></child>
    ; ^8 B0 t' {9 `2 h, W3 q1 `  z$ a
  3. </div>
    - V9 S3 r6 @7 \2 M. u, @

  4. 8 ^; Q- T+ V* I9 X' c# |, ^
  5. <script>
    2 W. ~1 L! Z( @) ?
  6. // 注册
    . w6 `4 Z8 B: `2 ~/ }7 g
  7. Vue.component('child', {8 K1 k) |4 e' s% o5 m1 O' G7 J
  8.   // 声明 props1 @) T) a, K8 H. q7 s
  9.   props: ['message'],% w/ S) B7 \& I3 B+ l
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    : t. Z$ Q& J7 ^8 m  R% C2 @+ G5 i
  11.   template: '<span>{{ message }}</span>'
    * Q: Z6 p1 L3 Q* k9 v0 V7 Q! `+ w
  12. })
      E) r5 _7 y1 A, i& G% G7 H
  13. // 创建根实例! ^# e- t  I% y$ ~( Q  L7 l# T! `9 R
  14. new Vue({
    $ m  ^# ^( u" o0 }: B
  15.   el: '#app'
    4 c/ W& G" i- ~: g% s$ n% {: H; \
  16. })
    3 w9 L" ?. e$ b& U2 C0 o! E7 V
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例$ W( s; v/ x( ]9 Q$ \: a
  1. <div id="app">' S. E' j5 f5 n9 V8 M
  2.     <div>
    , n. w) H/ N9 a% e2 {
  3.       <input v-model="parentMsg">
    0 f7 b' C2 @2 S7 i; S& w# q. M
  4.       <br>
    * m" U: v. a2 h& t! B1 _' n
  5.       <child v-bind:message="parentMsg"></child>
    - I& d2 p+ x3 k6 P, N2 a+ j, f% S9 l; J
  6.     </div>
    1 f" u0 L% i0 I" V- S
  7. </div>& x, h% R, k+ ]! g  _  P
  8. 7 U- p1 M% E, Y) j
  9. <script>
    3 S: _+ i4 t' A& c
  10. // 注册
    1 E$ ^6 F) S5 \# g" H
  11. Vue.component('child', {
    * X3 v  o, Z0 M9 K, r
  12.   // 声明 props
    , [' V3 X' u: m& q
  13.   props: ['message'],
    / d9 i1 ~5 q7 H1 T" }! O
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    / A4 C" r5 H( w5 |3 L6 ~& b+ C
  15.   template: '<span>{{ message }}</span>'& K& {6 j4 Y4 f. b0 A# W
  16. })
    $ _( a0 C4 Q. Q! T: K
  17. // 创建根实例
    - p/ u, L- a3 a" N+ t- g
  18. new Vue({8 u- {; {" G5 l' x0 Z2 z# P
  19.   el: '#app',) Z9 p( S6 O' N+ m$ V  x$ K
  20.   data: {6 i5 w$ j% f& P% S" k+ P3 B; o# S. b
  21.     parentMsg: '父组件内容'
    6 G3 K* n$ h# w3 o7 ^  D3 z
  22.   }' b2 U, L4 {  E7 i8 e
  23. })4 X8 N# c7 Q; V6 L% i
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例8 B  a( Z# B0 {# `$ A  T
  1. <div id="app">
    & @6 u; f+ K" ^, @  V( ?
  2.     <ol>
    0 C/ y6 X+ [3 e& f0 f* E, ]  j
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>0 H' T& w# X; f0 d8 K
  4.       </ol>) f0 F$ G% a6 C; ]: ~0 @
  5. </div>  m, y& G3 R& p( J/ i/ w
  6. ) ?( |: J+ Q( N" s
  7. <script>
    3 ?6 b* h! ?6 r! k  [5 f
  8. Vue.component('todo-item', {
    5 }# n; O# E  k; }
  9.   props: ['todo'],
    " u' U1 j  Z: d2 _4 y
  10.   template: '<li>{{ todo.text }}</li>'3 s; Y2 j) u; g+ o
  11. })9 J' x$ X/ T  r9 u0 G, Q1 P
  12. new Vue({3 d  O5 N7 m, @) K2 o" f3 Z$ @$ ~3 ~
  13.   el: '#app',9 \% h3 ]0 [) K
  14.   data: {; H1 p) N( b: C& C2 p3 J1 u- t
  15.     sites: [
    $ v3 N' j5 g' T" d9 U
  16.       { text: 'Runoob' },
    8 A6 s) }% y. Q$ T2 }# e
  17.       { text: 'Google' },# Q. K& H8 ~* s" ^7 S5 t
  18.       { text: 'Taobao' }6 f$ m, j3 d, ~' E
  19.     ]
    2 C! `( d3 x6 Y6 G  A
  20.   }( I$ }) Y. E% c" k3 L
  21. }): [1 B3 u: X* e; M- r- N
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {6 ~3 O6 D9 @1 G6 B" Q
  2.   props: {* s+ G& c) F3 A
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    $ `# I- S4 q8 G9 a! Z) b
  4.     propA: Number,
    " ^7 R  Q. c, [& |4 L. `  B6 v6 L
  5.     // 多种类型
    8 [6 G" ]* F4 x9 H6 m/ ^
  6.     propB: [String, Number],
    / O6 E+ y1 \9 H8 H/ U& U
  7.     // 必传且是字符串6 @; |, I; d5 V" U3 M  b
  8.     propC: {7 c* \$ `9 i: h. P8 @: Z
  9.       type: String,( ?7 M/ K5 }% S4 Y1 D$ f
  10.       required: true% X) s0 m+ }- v! t2 L1 ^
  11.     },
    1 `% a& D6 U8 `* H, ~/ ~+ f9 v' O
  12.     // 数字,有默认值; R1 F8 H# {# z2 J6 T
  13.     propD: {
    4 s) d% Z3 W! N$ E- O0 T
  14.       type: Number,7 y- H% d- L  q$ {; p& f9 J" B
  15.       default: 100. _: ^; I$ l8 N$ k, L5 j- [3 G- }
  16.     },$ [. t" ~; i: U7 U# Z$ d5 r/ E
  17.     // 数组/对象的默认值应当由一个工厂函数返回  ^2 _( U) p" ]& @. L0 N! u3 i
  18.     propE: {
    & W1 T3 C1 J# j; x
  19.       type: Object,/ Q9 W" a$ Q5 O+ `; i3 q
  20.       default: function () {
    5 X" H% P+ H0 `. y. \9 ?3 j$ _
  21.         return { message: 'hello' }) X  w* G( J- t8 ?* D9 ?8 T  U
  22.       }
    " d/ w" C% l7 z: i
  23.     },- T: P: t  |/ @- ^* A3 x
  24.     // 自定义验证函数0 ^  w6 ]% k& D/ Y1 {
  25.     propF: {/ o3 e6 W$ ^% a1 @! n
  26.       validator: function (value) {
    5 q7 f0 o4 u; _4 m: V
  27.         return value > 10
    % y% Y! v! Z) |' h7 \3 b
  28.       }
      d5 G- N, @" d. j2 T9 h. h
  29.     }% t, R1 o7 c' Y4 K) |; c$ B
  30.   }4 ]& c* O4 x+ J
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    / y9 a6 e% j* o/ v: z( W1 u
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    + V& G0 t% T/ u: \2 o( ?% d
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例7 l$ g0 X" n! n0 `% ]
  1. <div id="app">
    , `. }# h( q' T" Y% s0 X9 j0 g
  2.     <div id="counter-event-example">
    9 |$ X+ [6 o% m
  3.       <p>{{ total }}</p>
    9 A1 A9 d9 z- D, j! e
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    : k: P9 t) O6 C
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>4 v7 b4 o: I) h4 }" Y# d
  6.     </div>
    3 T# e9 N" [2 y8 f- t- _- \, K
  7. </div>: F* n% B4 j( f: L

  8. 9 ?: i7 p3 S5 @9 F, A7 H5 o8 e/ |
  9. <script>
    ( W! `5 ?+ Q( G
  10. Vue.component('button-counter', {
    5 o7 G* v- b0 y8 H4 |% k4 d, R2 p. H
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    % r; o& N) ^1 P
  12.   data: function () {
    ; }/ L% x% i" i: t
  13.     return {
    , R4 x6 g$ n' D; m, x9 \! R
  14.       counter: 07 ?2 c& d% g, P# M9 _
  15.     }1 h& T( m! q# g0 H
  16.   },. e  Q1 ?0 K# \9 J" ~" ?) ~
  17.   methods: {
    0 g+ N, y4 ~3 {( `3 p
  18.     incrementHandler: function () {
    $ O2 h7 S) ^* h8 p
  19.       this.counter += 1; c1 N% F7 G! v: W# y
  20.       this.$emit('increment')5 ]- D" J. U3 i' n0 O
  21.     }
    - T2 ^' D, g) o4 \* u
  22.   },
    9 n( Y# A* e+ u
  23. })) ^0 i% A* z" ^2 v
  24. new Vue({
    + z" \' h+ j+ ^' d0 F+ X3 F
  25.   el: '#counter-event-example',
    ! y) n* u1 \6 o+ E+ G
  26.   data: {
    . y, H/ u" m" O1 d- f; G
  27.     total: 0$ R2 q" |$ h1 s" n
  28.   },2 p% {6 t$ J' Y' j
  29.   methods: {
      E* s7 y) I9 G/ F$ ?6 H  \1 F
  30.     incrementTotal: function () {" ?& h2 P2 \/ h+ `% O
  31.       this.total += 1
    6 {7 Z- J* F, B, D
  32.     }
    1 O0 ]4 @1 O) x7 w
  33.   }
    ! a* x; e6 \. c/ ]
  34. })
    : l( K  ]) H) z. V4 R) e6 m+ r
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册1 Z* U1 Z& z2 b9 V* H8 {
  2. Vue.component('child', {  [5 g: z( G6 n
  3.   // 声明 props% n. ]! P) h9 V& K5 o( X4 P5 }
  4.   props: ['message'],
    ( u/ H5 _) r0 _3 U
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    8 Z* b( v/ W  |, W# ?6 t2 H4 \; V
  6.   template: '<span>{{ message }}</span>'7 `4 U7 s0 l6 B6 y
  7. })0 X$ l0 W) ?0 t; T( c& @! K* @
  8. // 创建根实例% g7 c- D5 \" s# \$ I
  9. new Vue({- s0 O8 C4 T9 t/ O- L& [0 i
  10.   el: '#app',
    * a# q8 J% }( c! n5 F9 ~
  11.   data:{2 v! y' p9 _! X) d
  12.     message:"hello",8 O. a) i' d: o' E3 i5 A$ ]
  13.   }( r0 D: Q( T+ [5 ]2 S
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {5 E  m. ^2 q8 i5 B
  2.     incrementHandler: function (v) {
    9 I7 m9 h- y- D# U7 h6 Y
  3.         if(v==1){: r8 H+ ?- ?/ K0 h4 c- F
  4.             this.counter -= 1
    6 S: Q+ Z% ?6 x: H3 }$ U: D3 h
  5.             this.$emit('increment',[1])9 P) w5 G  X% z& U
  6.         }else{
    ; E0 s5 _' _, ]; k* L9 R; x
  7.             this.counter += 13 Y0 ?6 L: ^9 Y( O: Z
  8.             this.$emit('increment',[2])" t% N. s, l3 m/ I$ S8 e) f
  9.         }* t1 J3 w7 }: q7 a" U& ~. I+ w
  10.     }
    5 l4 I" v7 x6 Q; w4 V+ M, ^: A3 K
  11. }
复制代码

, A6 W: a+ g! i0 U$ a3 ]8 M
/ }1 B0 X8 m2 e
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-20 04:18 , Processed in 0.066642 second(s), 23 queries .

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