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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15833|回复: 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 O- `" T/ m, q: G
  1. <div id="app">1 i% d4 D% T# ^) K- z
  2.     <runoob></runoob>
      k" Z) s  \! {' @3 P& I, G1 ~8 u+ b3 a
  3. </div>' V7 C: D" h( V( Y: X$ `! g, T
  4. 7 p4 e4 L6 r6 Z4 E; x( ^
  5. <script>
    4 R0 `6 r5 M. V! f" T# r( q! }: q
  6. // 注册# f$ H5 k1 l; S% M- }% r
  7. Vue.component('runoob', {
    6 {" [* J- n3 j  [/ g. C7 k
  8.   template: '<h1>自定义组件!</h1>'2 ]0 n( v# [% u" Y; k
  9. })/ C# Y! \# M9 E$ L
  10. // 创建根实例
      G1 O5 d3 p# e8 \3 E
  11. new Vue({
    ! T& S9 D3 ?* F+ a$ T/ @* Z
  12.   el: '#app', {5 Z1 d, ~" x% I5 I9 @  n
  13. })
    0 K  R7 D1 E0 u5 Z, x
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

1 |/ X3 }' Y$ j! ?
  1. <div id="app">/ T6 [8 v( |4 L- k# E4 s, z
  2.     <runoob></runoob>- T8 Y) \8 N; v5 F
  3. </div># d; `2 |0 S4 h0 w. }

  4. 4 _7 \# V4 f4 C3 [
  5. <script>4 G7 o" L; }7 t. t6 K: X2 E
  6. var Child = {. ^( L4 _6 m" e) p3 u3 b1 M
  7.   template: '<h1>自定义组件!</h1>'1 C4 v" }5 `, o4 ]( b0 l( }
  8. }& }, k7 i4 l7 B. _" J* ^/ t9 H
  9. # j0 d/ s* ?) ?4 U! e
  10. // 创建根实例
    ! k; D" C* ?% Y
  11. new Vue({% B' K* [( f# q, _1 Z/ p4 }
  12.   el: '#app',; L4 D* S% h7 I2 `% m
  13.   components: {6 H; Q6 @9 p, U. Q
  14.     // <runoob> 将只在父模板可用
    % p; O$ u1 ~1 ^
  15.     'runoob': Child% `' U" F5 x' u2 ~
  16.   }4 `5 U  q; n& D" K! ]$ V. \
  17. }): U6 `" G$ @5 h; J0 \0 @% b8 J$ z. V* I  h
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
: d* ^& t% ~; c  C
  1. <div id="app">
    ( F# H' ^- H8 d8 b8 g" Z8 g! W
  2.     <child message="hello!"></child>. @5 \. v. ?# a) m9 Y
  3. </div>
    / R6 B" u& W4 U+ g

  4. 1 i* P9 x, D5 F1 t
  5. <script>
    6 a0 f0 b! [' d; e/ }$ o3 Z
  6. // 注册
    . K  W# R3 j, P' s% V7 a. q
  7. Vue.component('child', {
    + [$ P  k5 o# P1 n1 t: N2 w
  8.   // 声明 props) C* c+ x# W0 b* P
  9.   props: ['message'],
    8 W9 j( t9 R% K* R' j% }
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    6 F. b( Z* Y# D/ W8 @
  11.   template: '<span>{{ message }}</span>'
    / y5 g& X8 B5 ^9 A! Q7 n
  12. }), n6 X- {2 w6 ]3 ]
  13. // 创建根实例
    $ x) h' i' j) p3 }5 f
  14. new Vue({
    8 _. g' ^* M* v2 h& |' u% @- t
  15.   el: '#app'7 \/ e1 C$ P3 j+ l
  16. })
    5 ~# d$ E9 s" v2 t$ V/ ^6 f
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
+ U5 |0 o4 r% ^" R! @. g) F, x
  1. <div id="app">( Y+ p! H% z2 Z
  2.     <div>2 Q: X% X5 n4 N. O& [7 b, Y! Q
  3.       <input v-model="parentMsg">4 n; {# p' E2 F% g
  4.       <br>4 Q- L" K& p" j
  5.       <child v-bind:message="parentMsg"></child>9 u( [( T! X6 r3 y+ d
  6.     </div>& P- \# l% S) `% Y* N: K
  7. </div>+ k( p: w" I) u9 J! C5 x; J6 M. P

  8. 4 A) z4 z7 h$ Z  z4 u$ l2 W# B" G
  9. <script>7 ~/ Y! E% J/ @6 ^6 ^
  10. // 注册7 c* ~$ D7 W8 w
  11. Vue.component('child', {9 N5 O7 h. w0 G; E- g0 s
  12.   // 声明 props6 h+ V: x2 ?+ v' k3 c+ K( h' G
  13.   props: ['message'],  \, \9 R( H( N" c1 m" A5 X& Y
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用6 M2 T; [3 Z; p
  15.   template: '<span>{{ message }}</span>'$ C0 b. s: p, q; i& z" e; h
  16. })( Z2 I0 `8 Y5 {6 M! E
  17. // 创建根实例
    : w' [5 U2 M3 l5 N! N% Z8 E
  18. new Vue({
    3 [, h+ Z( R* r' d. Y1 M* z* g
  19.   el: '#app',2 v0 ^: [" ]) N+ C7 N* g6 i
  20.   data: {
    ) ?2 p$ N) H1 f
  21.     parentMsg: '父组件内容'
    3 x3 _: K# B1 u8 T. o( D1 X9 p
  22.   }. c$ W3 l5 c* U. M$ o0 Y
  23. })5 Z! Q- ?" R  t  M- H
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例# s9 X% q1 e5 e  a; q
  1. <div id="app">
    ) E) z$ o7 e3 }
  2.     <ol>
    9 {4 }: Q6 f# C; t1 e" p/ Q
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    2 X+ K- ?5 Q/ n: B' [/ _
  4.       </ol>( @3 ]2 e* L4 V" ?
  5. </div>$ K' V4 O/ A) g) |2 H
  6. 1 ~' ^, u" w% z: `
  7. <script>
    , s, n2 n& h5 N, i4 h* a' z
  8. Vue.component('todo-item', {, Y4 \% x- j' C* m9 q9 ~: I$ E" l
  9.   props: ['todo'],6 v' b* V9 j% e/ H
  10.   template: '<li>{{ todo.text }}</li>'
    + l% C  k3 G/ a2 K: a
  11. })
    % F* B& m' c5 p3 P3 a# k
  12. new Vue({
    % r3 O. [, K* e( ?: `
  13.   el: '#app',7 F2 [2 m( }* `! M# {- ]
  14.   data: {  o4 H# |' p7 q
  15.     sites: [
    * l+ c+ ]4 W6 v
  16.       { text: 'Runoob' },
    2 V7 q! {# R( f" I2 g
  17.       { text: 'Google' },) p9 r" \, J* s( T+ K9 f- x) _
  18.       { text: 'Taobao' }
    1 c6 x. m. j2 N/ B+ w8 M+ c" c
  19.     ]8 H6 _: P" k& a
  20.   }
    7 k5 G/ o0 C: p0 w# s
  21. })  g" d" T8 t" ?
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {! H, A, j4 p0 _- ^- K8 {
  2.   props: {
    2 z( V  O' O# M: V. T
  3.     // 基础类型检测 (`null` 意思是任何类型都可以): k% K2 R$ N" R
  4.     propA: Number," {+ X& @1 K8 s  ?) c2 l
  5.     // 多种类型
    8 R' v; M+ M& e4 t* W2 Q; g
  6.     propB: [String, Number],$ k2 Q6 [/ c( q- |, [
  7.     // 必传且是字符串
    ( ?% b3 o7 A: S/ F" r" y
  8.     propC: {
    # c! L: d! I: H- ~* X
  9.       type: String,
    8 G7 p: S7 S* g: F, R0 g8 |; \3 ^
  10.       required: true
    ) W. k" S1 _& e0 |* {# M; |3 p
  11.     },
    6 H: U/ W# a; I  E7 h
  12.     // 数字,有默认值6 B& p+ }* M8 {1 v0 x. o3 D( ~- `  L
  13.     propD: {( V5 \8 b) T5 B( r( y9 O  ]) F7 d
  14.       type: Number,
    # K; O* X( A/ W( z% K( c5 R  X  ?
  15.       default: 100
    5 I9 F# E4 x  U  A, a' _
  16.     },- v! `+ ~/ r5 ?
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    + D0 Z4 o7 c# b: D% W' R: r
  18.     propE: {
    ; J8 m* A" a0 F
  19.       type: Object,
    * b6 U/ ^% e" p
  20.       default: function () {" J1 _  f7 L  P1 E4 @; X- ^- e
  21.         return { message: 'hello' }" v5 g  g$ k7 S. P& ^5 D) a
  22.       }, K6 [; j0 k! r7 e8 I% B& W$ E) f
  23.     },
    ( K$ s: r, N6 C8 w1 O% G8 v
  24.     // 自定义验证函数  r7 S/ ^/ E! S9 R  h* O5 C
  25.     propF: {
    6 s2 B+ a* z; f
  26.       validator: function (value) {5 ]0 K) e% N2 J
  27.         return value > 10
    0 x# J# G$ H& t
  28.       }
    0 e- v, J/ ~7 J0 V, A6 y( U
  29.     }
    8 @5 S7 ]: M$ n. J" Y: o6 g
  30.   }
    * w9 o0 O8 J) O6 ~9 d
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    ' x& _6 \: c$ k
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件8 _) f- _# O8 w! K* I
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例2 e! q' `$ K  W) g1 x& G3 C
  1. <div id="app">
    : O, h/ p- \5 f" Q8 q9 W
  2.     <div id="counter-event-example">
    8 L6 D" C9 g3 k7 H
  3.       <p>{{ total }}</p>3 ?) A( k) l8 @0 }( `
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>9 m7 b5 C1 F- t; Q
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>5 k6 O3 w4 K0 W
  6.     </div>
    ( z; a+ G& m! z) Z. Z+ G$ S6 N
  7. </div>
    & y8 t; @1 d9 w4 S4 o  s

  8. / w% u* g5 p2 s: ?" w' l
  9. <script>
    ( x* ~$ D% d) T3 R
  10. Vue.component('button-counter', {
    , W9 k5 }4 |1 w$ r
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    + v( x) `5 M, e; S5 D9 u
  12.   data: function () {
    6 N! B% `* e& w( y
  13.     return {
    4 m. C! |) D% G2 Z" h* n
  14.       counter: 05 V" n5 ?- V( R( T: c% j1 ?- D
  15.     }2 A) `7 J1 K; @
  16.   },3 P4 b! g# T, @' h! R! d) u' n
  17.   methods: {! h- J3 C2 C9 J  N. i5 T
  18.     incrementHandler: function () {" {7 x8 w# P$ U
  19.       this.counter += 1, K3 ?& B8 N' a0 Z+ _9 E
  20.       this.$emit('increment')
    - L' a3 ?% N* M, {
  21.     }6 I2 t5 I3 o( @) p
  22.   },
    ' Q# l0 x3 C7 g2 l7 u+ O6 D
  23. })/ U4 M- ~. \$ r2 @, W6 P5 ~$ N; i  d' F
  24. new Vue({# S! m% w  M# z: u# J+ E9 |
  25.   el: '#counter-event-example',, A( l' G1 w0 G* u7 C
  26.   data: {
    9 f. Q8 n0 U# j! ^% ~- c" z
  27.     total: 0
    ' a4 G; z/ l% n8 ~6 X
  28.   },
    ( X/ |! B7 u. o: V' d. b+ B/ p: x  A
  29.   methods: {  o6 c- n* w6 l4 O, C# b
  30.     incrementTotal: function () {
    ; l8 M, N: v# |' @; {
  31.       this.total += 1
    6 ^$ F5 J2 {/ u( K7 H# h
  32.     }4 U+ V, \! D5 y2 j9 [+ M' c
  33.   }. |7 y. I3 O! P
  34. })
    . M7 e. s+ r3 H- }7 v7 ], a& x  K. v
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    ! T/ B* _. S& f* u/ X+ e3 [) G
  2. Vue.component('child', {
    2 M+ x7 O' y: T9 W: C3 y" \
  3.   // 声明 props' L0 V- N" P) T& R; T. t
  4.   props: ['message'],+ d2 @+ @  G! B, U8 Q5 Y$ Z3 l
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用" ]4 S- n8 K# H
  6.   template: '<span>{{ message }}</span>'
    + C; X. u6 \( X' _# }$ K0 p8 S! ^
  7. })0 X, P+ d# B/ S) H# O9 I) z7 ~8 O
  8. // 创建根实例$ T7 Y6 a7 l; U! _: r+ `: T7 A: I: z
  9. new Vue({, Z5 c+ W+ A  D4 j% d7 q+ J( d9 K
  10.   el: '#app',
    & Y" z0 a; ]1 i: u+ Z- s; s
  11.   data:{
    # M+ _# x. @# E  d$ P$ }' G
  12.     message:"hello",0 A* _1 V6 @: j2 e+ s/ [  ~
  13.   }( k  J* u) h: Y6 e8 r
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {) t2 E4 [% {* X, z' ~5 u3 P6 t  r
  2.     incrementHandler: function (v) {& \: T6 w# m( j: Y& Z8 Q9 M. m
  3.         if(v==1){
    4 o) G# p' `( l; w& D' [' P
  4.             this.counter -= 1
    4 g6 O* q" y5 q( E: c4 o+ X1 v: a- }
  5.             this.$emit('increment',[1])
    0 W2 O7 Z" X% n0 ^' j) O
  6.         }else{! V1 _( C5 b2 U/ V1 F
  7.             this.counter += 1
    & d, r  B' Q7 F7 M7 L
  8.             this.$emit('increment',[2]), u3 d! x4 V: i& b
  9.         }+ |! o1 t: \: ^( |( o4 w3 M" y; p
  10.     }* F' U8 E- G; l$ j3 M0 q! a" ^( I8 @
  11. }
复制代码
- b; p2 r" K* Z7 c
! l! R- t' V' S. Q' `4 ?
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-20 03:25 , Processed in 0.111647 second(s), 33 queries .

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