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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15351|回复: 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 o- a8 [8 \0 b4 b" c7 h
  1. <div id="app">
    ' U7 p7 ?( K0 Z8 g' I
  2.     <runoob></runoob>
    . L% R# m$ A8 R+ c. ~3 J. h( }
  3. </div>1 z5 _) ^+ C- ^- c1 Q
  4. 2 d1 c. \, }- o. |7 ?; X* ?
  5. <script>
    * M( o4 J. h. k& ~
  6. // 注册, \" I/ e4 q8 p
  7. Vue.component('runoob', {6 _/ F. d; |8 J, e$ S
  8.   template: '<h1>自定义组件!</h1>': v% M. X) z8 n& R& K
  9. })
    9 n' Y  f8 A& @- z! @" G2 I
  10. // 创建根实例# X7 i+ K3 T5 N
  11. new Vue({
    9 F9 S# d6 X% }% g) s' z9 f
  12.   el: '#app'
    2 v# y7 G: r; z; |* {
  13. })
    2 z- \+ q! m8 B( ?
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

: V/ T9 B# h+ Z. @* j
  1. <div id="app">
    ' `( N) ^0 P. C% h* r3 @6 x: O5 p5 H
  2.     <runoob></runoob>
    ; c4 J% m0 [& N4 G
  3. </div>/ u$ T) N0 Y* z: q2 m

  4. 1 Y) f& }6 \. G# [# s5 O
  5. <script>/ @4 ]& r; i# b/ ^, P
  6. var Child = {; c. H, ^) q; w0 r5 ?' D5 }
  7.   template: '<h1>自定义组件!</h1>'
    8 Z; ?- @! K( q' U  v! S
  8. }: l4 h# P* Z) R

  9. & X) O; e; R$ U- E+ _, @
  10. // 创建根实例3 f* q) X: e- [% L& S' d$ M1 W
  11. new Vue({
    5 b- q/ n, l4 y. Q* T0 q3 Q9 G1 L
  12.   el: '#app',
    2 V' @$ Z" x1 h4 L) H- C) F* C- i
  13.   components: {# j6 s4 x% Z6 s6 I8 p9 O
  14.     // <runoob> 将只在父模板可用
    / B7 |4 _* W1 O. J+ V) x
  15.     'runoob': Child
    ; G5 M+ k- J% S& ~$ [2 `
  16.   }7 L  F3 n2 y" z9 {4 ]1 W
  17. })$ R' P: R! k4 T: k3 s/ |3 }: x
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例# X' Z) x. `) ~" t
  1. <div id="app">+ r7 S& l8 n. S1 b; _$ `4 j
  2.     <child message="hello!"></child>
    4 z% y  y. J- M3 B7 ^3 a
  3. </div>- r7 w6 d! i# E, I( T
  4. & ~5 I2 I  j/ z' p  o% X: L( o
  5. <script>
    / A% c+ O* s! C8 k4 r# L
  6. // 注册+ J% S, w$ L  Q' v3 k4 L6 A6 l
  7. Vue.component('child', {! T! E0 u& T9 h% V0 g; }, a7 b
  8.   // 声明 props! |. p1 T  c$ |/ ^
  9.   props: ['message'],
    ! D4 u& T" p7 }: |1 O& L
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用8 t$ I/ }( T: G+ S* i
  11.   template: '<span>{{ message }}</span>'
    ) [, c) f1 V1 r- i" d% o
  12. })6 }5 c1 A' G7 D) s
  13. // 创建根实例* d: U4 S3 c5 j: R& d# g. R/ {
  14. new Vue({" e8 K6 [! q5 D
  15.   el: '#app'
    $ s  W# O/ n3 C1 k4 M2 ]
  16. })
    ! }$ q* ~  h5 y7 F% R
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
: {8 M# ]# f8 R5 o- j' l/ g% m6 g
  1. <div id="app">5 N% r* n" O$ s6 q; o" W$ q  E
  2.     <div>
    " A! K) }4 H8 Q6 }8 i9 g( b" b
  3.       <input v-model="parentMsg">
    , O5 W; w$ j* ?# F& |) E' r( J
  4.       <br>- q; ^4 |* p8 g* I
  5.       <child v-bind:message="parentMsg"></child>  V9 ?( p+ m" ?3 }7 R5 @% I
  6.     </div>
    + r8 P5 P8 N) |7 h6 K
  7. </div>
    8 ^3 M1 C( Q6 K% B1 L

  8. 2 D7 w5 @. l) F; X
  9. <script>2 e" `% {+ {( N, b1 y! c. w
  10. // 注册$ e+ j8 d4 R4 c, ]) u
  11. Vue.component('child', {4 q3 g8 n9 R* B, ]: G, _
  12.   // 声明 props
    % x" v  M6 ?' S
  13.   props: ['message'],
    2 W# m, {! Y! ^# F1 z2 H
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    . ]3 a2 |& m) f
  15.   template: '<span>{{ message }}</span>'
    " m- X* C0 \3 }; u! ]! H
  16. })8 z$ G4 {: z9 w' A$ Y3 e
  17. // 创建根实例
    * ~* g0 K" m& S: U. X$ w* O+ H
  18. new Vue({$ i' x" Q# D/ e
  19.   el: '#app',
    ! |5 X- x& J, q; j. y
  20.   data: {
    ; e2 u$ t0 I" V+ o+ T% }
  21.     parentMsg: '父组件内容'
    ( b3 p# S! J! ?  ~- X
  22.   }% S  G0 E1 L8 N4 e
  23. })
    9 o: A, @2 e: U. B: P7 V
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
2 _5 k0 x' b+ H
  1. <div id="app">: D  @: @, X4 V2 C) W  N
  2.     <ol>
    + ^) i, l. T" {, b  F
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    ) G# K# K: Y" U4 N% \4 }  d: Q- X
  4.       </ol>
    0 O( M& Y: o3 u; l2 {
  5. </div>9 C% Z+ i+ f# d' o# ~
  6. , {7 e6 a2 a+ _' }3 k# m
  7. <script>3 |# a" v7 G( E
  8. Vue.component('todo-item', {
    " m. ~8 B, w2 r3 j$ ]
  9.   props: ['todo'],
    & e/ q+ U% z3 g" @% `
  10.   template: '<li>{{ todo.text }}</li>'$ x! b4 b, ]1 W3 i
  11. })
    , _3 u# p$ e# T! v! d' @, b
  12. new Vue({+ ^  o. j0 V0 P  h* G" x! O6 u' J
  13.   el: '#app',4 O; r6 X. E( i: B
  14.   data: {
    3 L' ]5 ~# m# ^# X
  15.     sites: [
    , s  C2 D3 b1 G  b( z# [7 J
  16.       { text: 'Runoob' },; z  n8 F" M$ ~; ]& m) t' W
  17.       { text: 'Google' },; H; v, G% P; ?1 \* {
  18.       { text: 'Taobao' }
    4 O3 p: j0 U& ~
  19.     ]
    1 h! C* b5 L3 W" J  j
  20.   }
    % P- a, D) l2 v1 I7 X0 I( X
  21. }). ^/ D' Z5 o4 l1 v& f6 e2 {
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {, k/ \  k5 `2 D$ i7 d
  2.   props: {
    9 q0 B5 v" u6 d
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)6 m( [- W3 {8 e3 N6 |7 W" h! W
  4.     propA: Number,
    & M7 ]+ B2 f1 s% v: q
  5.     // 多种类型; Y2 J- e8 V6 e$ s* }$ u
  6.     propB: [String, Number],9 J$ `' F9 x- ]
  7.     // 必传且是字符串
    4 l9 l% w8 O/ R- ^6 i, W) z
  8.     propC: {
    * z1 M1 L. @  L, W8 Y/ B! B$ P
  9.       type: String,4 C/ C6 f* I, N# T
  10.       required: true3 T  g/ S0 [+ f! C2 u
  11.     },
    4 X- K' e0 E  B0 l* m( b
  12.     // 数字,有默认值
    4 |, |: M7 U+ M$ F  s* ?" V! N
  13.     propD: {2 M3 g3 S* |! ]. W2 ]7 F
  14.       type: Number,: @# g9 z& k5 A$ O) C4 Y% a( c2 u# X
  15.       default: 100
    + r3 d/ O: y$ T/ _5 Q5 x5 m+ E9 U
  16.     },* L" O. L, J$ R# C
  17.     // 数组/对象的默认值应当由一个工厂函数返回  i0 s- \. w1 d8 `
  18.     propE: {% j) s$ `) c/ |2 ?# @2 o
  19.       type: Object,9 [% G6 r. Q* _! }6 \# ^8 S
  20.       default: function () {
    ! ]  C3 ~$ R; ?8 V
  21.         return { message: 'hello' }
    / o* Q6 I8 h+ P6 D$ Y+ |
  22.       }
    . O: k5 I: q% G0 C% W: g* I3 a; U
  23.     },
    + C& p: y- I8 }* G$ q
  24.     // 自定义验证函数* w8 S7 k8 P4 x: R- h, Y# @* a
  25.     propF: {
    ; v* k; B$ _& L. y$ ~5 `$ g
  26.       validator: function (value) {5 X  P  A. n) \+ w( W6 U* Y
  27.         return value > 10
    3 s1 t6 P6 h6 P+ B! `' ]/ ]
  28.       }& H/ ^1 i) D6 ^
  29.     }
    ' O8 x& |# u  P
  30.   }
    5 y2 F3 L2 K3 x! X. \  J
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    " j# {# `/ c! O9 ~7 u
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    8 n! G& `. r; A1 x; m; R5 D
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
6 x5 a5 X; r; |9 |
  1. <div id="app">& c, S9 M7 l& Q' A7 r, L" n
  2.     <div id="counter-event-example">5 @8 c# g$ b/ {9 F  V( D- p$ {
  3.       <p>{{ total }}</p>
    ) \/ M  F, ]6 @7 T& O
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>2 F& G1 I5 v/ q( A
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>4 C$ u  A: L8 U, L- D' ]6 e2 t
  6.     </div>
    3 B9 A  A8 i& w1 d' U3 _
  7. </div># }- H7 m/ Q' e* Z
  8. , Q% m* _" r+ h: }: |' ?- W' P
  9. <script>$ g; M7 L) S: c
  10. Vue.component('button-counter', {+ z' @( S: K; e9 h
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',- W3 h- l' k) B8 y2 [# m; b0 b" T, Z
  12.   data: function () {
    : ?  n' J  b4 d
  13.     return {7 e/ _2 i* g) `4 |, h' v5 @$ W4 A
  14.       counter: 0& [" k0 ]$ v  o& U8 h) |5 n% C8 v0 K
  15.     }
    * Z* C! h8 H" m/ D4 Q
  16.   },! f8 I- w3 A/ f% n$ h9 _
  17.   methods: {7 _. T, i; o$ k# t
  18.     incrementHandler: function () {
    / ^5 Q0 H9 p8 n6 ?. r+ Y
  19.       this.counter += 1
    , D9 v/ a* M+ c" j4 A' t4 f
  20.       this.$emit('increment')
    ) B0 P4 q) F& \! O8 F2 T
  21.     }
    0 W1 ?3 a! l9 v9 \/ m+ w2 q
  22.   },
    5 A" G6 X. l/ B  [9 y! `" e  O
  23. })' x+ a! ?1 B( U
  24. new Vue({' q2 K& b; r9 j1 `0 F" H* v. l0 H5 W
  25.   el: '#counter-event-example',9 \* p+ P5 U/ }9 Z6 s, G
  26.   data: {6 A2 O: f+ z! l/ P
  27.     total: 0
    ! t) _  r- a  @5 J0 h  Q3 D
  28.   },
    8 W$ L7 d& j6 {
  29.   methods: {1 z; e# ]( F& u% V* }
  30.     incrementTotal: function () {
    , T  a8 o: M  k- C  v' L- }; f9 B
  31.       this.total += 1& V) K! i; u7 o2 w, p+ D2 k
  32.     }
    $ G0 w+ d1 Z( i- o
  33.   }
    % P, I+ h4 |' {- }* [  i0 i
  34. })
    ( v2 L& L/ ?7 M, M* x
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    ' H% Z9 |8 O% l* M7 ~2 Y+ p) P
  2. Vue.component('child', {1 @$ G# m3 I. w" R% Z4 N6 W5 G
  3.   // 声明 props
    , n; D3 o5 X7 i9 F" M) N# v0 W+ B
  4.   props: ['message'],: R- q. V8 ^. g; L% j8 J
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    " P* O  Y: H  v* r
  6.   template: '<span>{{ message }}</span>', e  q) L8 ~# i
  7. })
    7 [+ z+ }; s$ u: A3 A* g7 Y+ F1 i
  8. // 创建根实例
    : W( E' w% F+ k( p! }4 E
  9. new Vue({" K- P4 t( Y1 D5 G6 W: j: L' I
  10.   el: '#app',* ^: R+ r5 ]- v2 H( E  W
  11.   data:{9 K. Q% B  S6 \
  12.     message:"hello",
      d3 s4 l2 N4 |$ ^& F  U4 V7 n
  13.   }/ C8 h5 t9 X" ^0 D! H4 _- g! s
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    ; U" l3 i' N; u
  2.     incrementHandler: function (v) {
    & }9 ]: J1 W4 d% n; `
  3.         if(v==1){
    : o, V5 K$ A5 P- J' S  ^
  4.             this.counter -= 1( F# }3 l) N$ ^6 I% V) i
  5.             this.$emit('increment',[1])
    0 H7 j) B( \* ^) N  |6 [
  6.         }else{
    # ?4 n- P& |* v4 e
  7.             this.counter += 1( e9 N, \0 l5 W$ }1 {3 s0 Z
  8.             this.$emit('increment',[2])
    $ r/ p' x7 F1 _* p
  9.         }
    9 C% ]! ?4 e$ c8 q6 C. {/ ~
  10.     }
    ( p" L- V" a$ P% V, @: \: _4 Z4 R3 p: H$ n
  11. }
复制代码

7 p& b7 B' b; _- Y! b6 j0 R- w- I. L" O  s, ~, i; J7 ?
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-16 18:14 , Processed in 0.076457 second(s), 22 queries .

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