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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 12767|回复: 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,并使用它:
. S' o& c5 [$ c0 C& v, j# ]; e/ D- k
  1. <div id="app">5 g& f1 U# p3 }$ u& l# b1 ]" f8 l
  2.     <runoob></runoob>8 ^( \+ n1 V3 t* X
  3. </div>8 M" w- N9 ~0 y! s( h
  4. # ~3 h5 D+ J2 T3 M
  5. <script>  R7 d, _' u- {9 b$ N" ]
  6. // 注册
    5 g- f! Z' e' U- t3 q6 M* _
  7. Vue.component('runoob', {
    . p/ t& _1 F8 f: f" b
  8.   template: '<h1>自定义组件!</h1>'
    5 j, F+ G1 Z, S3 P# |1 n
  9. })
    8 r0 j& i: ~9 c: _
  10. // 创建根实例
    3 Q2 Y: f; [' K+ q$ G  R  r
  11. new Vue({/ B/ E  Z* y5 u# C) }0 ~6 l( F
  12.   el: '#app'
    1 o$ g! @0 i/ d5 I6 u
  13. })
    : ], b* W4 J; j# P
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

" L8 I, `2 Z5 Y. j" V2 L6 F
  1. <div id="app">
    * _; r6 I: O; i. T+ f
  2.     <runoob></runoob>% c3 f9 |! f3 }$ c- N
  3. </div>
    & G" @2 t1 |1 i1 z, [% F* c' W
  4.   W" }0 q) ^# N
  5. <script>
    6 M; }! X; }9 d" @  D
  6. var Child = {
    & [* n$ T( {% I$ A) J# r# F5 u* `
  7.   template: '<h1>自定义组件!</h1>'
    4 l; S$ ~, v# i$ R" i
  8. }
    + b% i( B3 T3 ?, k
  9. : Z5 |7 v* |1 X3 w% e
  10. // 创建根实例
    / I# \0 ]* f7 M  X* J/ i
  11. new Vue({
    ! U1 V4 s2 r6 s. X* a0 f( r
  12.   el: '#app',4 W+ M3 j; }4 f. X& X
  13.   components: {
    ; V! o0 e2 N( A$ j2 U
  14.     // <runoob> 将只在父模板可用
    2 T+ e( [7 }* q- X2 a# k9 W$ Y2 z
  15.     'runoob': Child+ k0 p' Z* T) }$ ?' k
  16.   }
    % O- @& }. r" l4 d1 r, j
  17. })
    % F; C" T6 Y- N+ b0 e; [
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
# t1 f9 C/ S) u+ k+ J
  1. <div id="app">( u" E8 `3 Q, s" I$ n; }1 u
  2.     <child message="hello!"></child>
    % k: ^  O. u) ]0 p8 X0 a
  3. </div>2 [3 d  Y. @0 \, A1 ^

  4. - _/ q. ?) u; g) c
  5. <script>
    4 h- |' S6 s$ A9 ?- h: z( p
  6. // 注册
    ; x2 w6 V" [  o3 U
  7. Vue.component('child', {
    1 E( H, d% E/ l
  8.   // 声明 props, U, ?+ J2 V; Q9 p. |9 D1 V  T
  9.   props: ['message'],6 G: s+ ]/ W0 R/ |0 ]# ]
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用0 n' ]7 @& `; j) }$ v4 ^
  11.   template: '<span>{{ message }}</span>'
    6 _/ g" F% r/ h* O0 {* L4 V3 R6 y
  12. })
    & K* N8 P4 O% F' s1 d9 q
  13. // 创建根实例! L7 W$ `0 d+ B# I1 G- u$ J" ^
  14. new Vue({
      p' f2 a8 R& O1 m1 n
  15.   el: '#app'
    , G' h0 ]8 I  {; |' w- ?
  16. })4 j4 j9 q  K# G, M
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例: O7 ~, y9 \: v/ k' q+ V* K
  1. <div id="app">
    6 n& X, d8 g/ |
  2.     <div>
    4 x$ ~& Y+ X" I2 P8 O
  3.       <input v-model="parentMsg">' P: Z! O: v7 d4 l4 h4 n/ g4 w6 O
  4.       <br>5 `3 [2 U0 X& T2 Q# h& g/ a4 B( G
  5.       <child v-bind:message="parentMsg"></child>
    : U1 L" ^/ a' R5 e. P% K5 ^
  6.     </div>
    $ B& m" w8 O; _' `! u
  7. </div>) p9 Z9 j' @/ u9 `5 n

  8. $ \: U/ A4 @! R) M) Z% g5 p& \
  9. <script>; J  Q: n2 E" Y: O
  10. // 注册) q* h2 `$ \) N9 Z* y$ ^
  11. Vue.component('child', {0 |- p: o2 M1 p7 I# c0 R1 X/ u
  12.   // 声明 props
    ( ^6 M# [9 }# h5 i# @
  13.   props: ['message'],! `  W0 F. B& K# R# N
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用  n7 A( t4 r7 u9 L. n2 @+ V# r
  15.   template: '<span>{{ message }}</span>'
    - q' E7 x9 K- l
  16. })- _- S1 X: f5 @( z; j6 z& i
  17. // 创建根实例
    # A' ^, z' z2 I7 |
  18. new Vue({
    ; j" r3 z- Y5 }: D
  19.   el: '#app',. F6 c5 W: v: Y- W' B, j
  20.   data: {
    9 K' y3 S3 \+ j1 b  e
  21.     parentMsg: '父组件内容'5 g) P2 m6 L9 l/ y* d" P
  22.   }
    ) \& j% y  A% s5 N7 y
  23. })
    8 r# X( {: f. @6 D, ?
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
! G4 P5 Z* S: q( {. V2 \" V
  1. <div id="app">% G! P/ |* ^+ Y1 K
  2.     <ol>- p5 g( Q, t3 o  m+ R  p& t$ g  q
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>% Q% _8 s# X# p( z- Y" y
  4.       </ol>8 Q( V  E; F) P& Y0 s7 g' {) Z
  5. </div>
    % f& Z) B6 b" \7 i5 D8 o; K/ \3 ^

  6. % S% r) ?+ g; U. F" ?7 b7 S& v! C' u
  7. <script>
    2 e7 n8 B) O- U
  8. Vue.component('todo-item', {
    # y& }2 S; y, X) m4 b
  9.   props: ['todo'],
    / a" L1 d& K  Z9 k
  10.   template: '<li>{{ todo.text }}</li>'- S0 b/ ?, b0 j" P. {
  11. })
    ' v+ Y- {6 b$ g# C" h; i
  12. new Vue({& W  U% p% V; P# z* n3 |- q
  13.   el: '#app',
    3 F9 Z: _, q3 s) Q1 G3 g7 _# r
  14.   data: {* b6 v$ X( l5 {! y( y. u
  15.     sites: [
    0 }" d+ E4 @" U8 m' H
  16.       { text: 'Runoob' },2 U5 ^: T! ]' b; B
  17.       { text: 'Google' },* r, J3 E! E1 C" y
  18.       { text: 'Taobao' }- ?: Q1 ]3 I) v) |1 P
  19.     ]0 o9 a' T2 @1 R: j( c
  20.   }/ {& N2 W! F. y$ q: s" b$ z
  21. })
    + A( b% n" |# ]
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {  Q; \  T- v8 ^9 i( M# {7 @- _
  2.   props: {2 _+ I$ {% A* T- J8 U
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)8 B- B; L9 B& m/ \0 c# M
  4.     propA: Number,
    ; l0 Q- [% ^$ ?) H9 `" M3 s; V
  5.     // 多种类型
    % x4 B8 Z: p+ w! f2 M
  6.     propB: [String, Number],' M& m3 p5 s: P  ^
  7.     // 必传且是字符串' g; B) y+ o4 o7 ]5 d4 q+ c$ j
  8.     propC: {
    ! ~5 o8 V& T7 n& Z, o" O
  9.       type: String,+ e4 m0 c$ a# d7 P  x% f
  10.       required: true+ `4 D- Q& _4 I0 X. }, {
  11.     },
    # C9 H% v9 m% i
  12.     // 数字,有默认值+ a$ m7 r- e8 C* a/ ^* V
  13.     propD: {
    5 D" V# A% \/ l+ V: `
  14.       type: Number,6 Q' ^' y$ x5 r: E1 v
  15.       default: 1005 H$ c+ D2 l, `- }2 s, ]4 G) V
  16.     },8 \# a, ]5 g& S: K2 }: Q* H( g. A/ k
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    % f4 R& {# u2 E8 J) n4 c
  18.     propE: {
    , H. }# a% S% n* ~6 q" C! s! v
  19.       type: Object,
    4 A* S* r2 y) s8 a5 H5 I
  20.       default: function () {6 V. Q6 b5 |) q9 K
  21.         return { message: 'hello' }
      i( i2 D, u3 A
  22.       }' d. K% m+ z. I! z4 E
  23.     },
    3 v, h! V1 B1 N+ X
  24.     // 自定义验证函数
    / A5 @- W* ?% }4 P, \
  25.     propF: {
    7 v1 n: x% i: [2 K4 E+ p9 L' E% i
  26.       validator: function (value) {
    : {3 T- C' v  ~' g8 |
  27.         return value > 106 c* `2 H4 C0 U2 f" X) P4 O" L
  28.       }( ?9 V# o* V( @  W
  29.     }
    1 u7 `7 l; E, Q) X
  30.   }
    $ \+ J. _& h3 k
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array$ `; m$ ^/ B8 L; c
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
      ?+ @' {; F. k* J: N) ^
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
# `( s' u, O) Z7 F* Y' T
  1. <div id="app">$ K/ y, p3 @9 p. |
  2.     <div id="counter-event-example">
    0 K  {  d3 y  h; M2 }$ [
  3.       <p>{{ total }}</p>
    . z7 ^: X8 ^, e
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    ' x+ }: D3 }0 R% C) m/ X
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>0 g/ Q0 D% Y1 M1 H
  6.     </div>0 b# a3 H8 ]/ B6 J. w( f0 x9 W7 G
  7. </div>* G7 y' w' t  `7 P
  8. : [+ o' o2 H6 _$ X6 S+ h
  9. <script>' [7 s8 K' {7 ^) k: m
  10. Vue.component('button-counter', {
    ; {. ~- Y  s9 W' j5 S4 C2 _( z9 ^
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    6 m  x9 o: T8 w6 i$ g
  12.   data: function () {' s9 P7 z+ c& ?- y, k2 h+ _' p
  13.     return {
    ' ]5 ]" S5 P  ]3 ^
  14.       counter: 0
    / r  c$ D* V" D( v9 x
  15.     }
    " U' w# b9 C. w# l1 X
  16.   },( @2 @. w! B- ]8 D
  17.   methods: {/ m1 c6 s( O  G! e
  18.     incrementHandler: function () {
    ( X  s; r( h+ ~4 l
  19.       this.counter += 19 p, T% _! `( F# h
  20.       this.$emit('increment')
    : O- Z: t" R* M3 W4 {! n- T
  21.     }. V1 B2 ^& h$ b  I& Q
  22.   },/ ]! R0 c& C3 ^6 C) M# i
  23. })
    & A! Z8 l3 k$ e+ U( |; @4 N) }5 y3 ^- x
  24. new Vue({" C+ w* R1 k* R: t" Z6 Z; b. P
  25.   el: '#counter-event-example',9 s2 z( D6 |( f% ~7 H# i' u
  26.   data: {
    9 M4 W% j; H/ y7 m2 V+ ~
  27.     total: 0
    ; k4 ^7 {- R. [& \% V
  28.   },3 ]/ L2 ]8 e3 X7 f
  29.   methods: {
    , L( L6 `$ G, \- j% B3 u
  30.     incrementTotal: function () {* D: g4 F- p* @9 l; X3 _% o5 w
  31.       this.total += 1/ `# ^; a; \) h$ l9 E2 a
  32.     }
    7 ~/ ^8 ~% O- X2 L
  33.   }3 C, I% @. a3 Z: J9 ?9 _& l' u; F
  34. })$ v0 [: F3 b7 D& O" f' O
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    8 S2 T5 j) ~: Z
  2. Vue.component('child', {& Y! J2 C$ w; C* b
  3.   // 声明 props
    * J! f/ Q2 I( V5 v1 f/ ^( @
  4.   props: ['message'],
    ( @, s) r" w. k- I; E1 H# T
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    2 @: Z- p$ g2 \
  6.   template: '<span>{{ message }}</span>'9 T( Q, ~) j  b- B
  7. })+ `  m$ |  D' z0 a* b
  8. // 创建根实例
    7 L2 j# t4 ~) \: B* b
  9. new Vue({
    ; i5 Y5 G2 W# [4 ?6 E( b
  10.   el: '#app',
    ( {0 }) F5 U5 N2 a1 T0 f6 L0 a* d
  11.   data:{
    : L/ D1 p" M& w/ r7 {
  12.     message:"hello",6 E* H, g& D, T  `8 S
  13.   }5 u+ T$ N- y! h  ~. m: o
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {, h* i3 d* \* @! w7 G- n1 H& \
  2.     incrementHandler: function (v) {
    - J* I- N6 y: ], h. p4 M* `
  3.         if(v==1){
    % b0 g+ o( s5 O% ?
  4.             this.counter -= 1
    0 \" B" S6 q5 ^' P1 m
  5.             this.$emit('increment',[1])2 Q- y5 F+ e4 W# K( i
  6.         }else{
    + j, i0 k0 W1 [. u  Z
  7.             this.counter += 1
    8 o4 B0 b6 j) q; R. {
  8.             this.$emit('increment',[2])
    2 t$ F) V$ R' `, t
  9.         }
    ( _0 f; [2 M; s' C. E( W0 Z4 r
  10.     }* e8 x: f$ x+ o) d* C
  11. }
复制代码
; Z( `: O- y6 f7 k

1 [, S/ R6 n' p  f3 Z" l* I
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 21:04 , Processed in 0.161068 second(s), 23 queries .

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