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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 11086|回复: 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,并使用它:
" C7 g" d9 z! h: S8 A- ~
  1. <div id="app">
    0 E+ H$ i: y* G5 k, z: U2 q
  2.     <runoob></runoob>
    . p5 }) n  S: d6 j( F
  3. </div>% H: y2 L0 a9 a, F8 _. u. [
  4. ! l; f! d$ I2 R# K& C/ ?# Q. h
  5. <script>
    9 H+ H. w5 {3 x$ u
  6. // 注册
    " B; I( x, }1 [$ y. j
  7. Vue.component('runoob', {) c% Z/ J2 L8 H0 y* [6 r3 `' v
  8.   template: '<h1>自定义组件!</h1>'  E/ n. o$ {# R# P8 Q/ c1 G: [
  9. })
    $ o, F4 e4 Q( t* i9 ^4 u3 H+ T
  10. // 创建根实例
    6 J! t) N6 U8 i( ~
  11. new Vue({, E8 D. o8 M4 X# ^- @8 }
  12.   el: '#app'
    7 v1 t4 e% k& y
  13. })4 F/ g# L! z$ o0 ^' }
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
* \. V0 w; W/ B4 k7 d, T: ?& X- V
  1. <div id="app">  j3 Z4 T0 p9 E- x9 W
  2.     <runoob></runoob>! j* Q# i5 O; D3 l& ?+ q0 h
  3. </div>
    ( s1 B: w- s5 h/ y6 @) l4 R

  4. & u2 f6 @8 f3 p# o; \7 e1 \
  5. <script>
    % j8 W8 G* n; M4 r0 }
  6. var Child = {5 z" |0 U+ ]0 |0 h0 E% U
  7.   template: '<h1>自定义组件!</h1>'
    9 x# g. h7 X. N
  8. }  Y- j1 K9 u6 w; [& `2 a6 ?

  9. + A$ ~# u8 l+ @) G  t
  10. // 创建根实例
    ) j" Z% t) ]) s  D7 H" x7 H9 F, ~
  11. new Vue({6 Z- `" C4 C! u  o- f4 @
  12.   el: '#app',7 ?9 F/ H( C$ ]$ w: L
  13.   components: {
    4 Y" d/ z8 E* b& z8 ~. l
  14.     // <runoob> 将只在父模板可用
    + g" n) B! b& p! e
  15.     'runoob': Child+ C0 ?) @  X$ N( E) ]
  16.   }- I, |, W6 u7 N, _! l) }
  17. })1 w6 ]8 r/ U. l
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
! x  C. m& c8 b3 T% x
  1. <div id="app"># d# p4 r9 S# O( [! P: s
  2.     <child message="hello!"></child>
    . n3 b& j$ x( W+ e' V1 Y5 l9 Y
  3. </div>. X& b/ f5 _1 n# l& G

  4. 3 q" j) o) q# r, B
  5. <script># n  a. n3 y1 W& W9 _
  6. // 注册' W& H0 D/ N3 {; i$ y" v
  7. Vue.component('child', {
    ! ~% h8 J. R$ C! ?
  8.   // 声明 props
    & k" M% x* O1 g
  9.   props: ['message'],
    # a6 f: f- |9 f  b* O6 n0 V1 W* Q
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用9 ?3 K( p2 I9 f6 X
  11.   template: '<span>{{ message }}</span>'! |0 X( h/ K3 c% e5 C0 ]% f2 l" |
  12. })
    ; B3 ^3 o" T' [6 v
  13. // 创建根实例) T2 Y) b" h$ @( ~7 w
  14. new Vue({
    - [# v7 t; p! Y
  15.   el: '#app'. q: v$ ^, ]- S1 p
  16. })
    1 F2 r2 L/ r" T
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
3 }$ I8 c1 }6 r9 T
  1. <div id="app">
    5 g' L5 f' ]# b( n, M; J* ~
  2.     <div>4 q; d! b( p6 l, E2 W0 c0 V
  3.       <input v-model="parentMsg">
    ) y8 h! C9 F3 @  \8 e& y. W! b
  4.       <br>7 W1 T2 S  v+ |! j' y- }
  5.       <child v-bind:message="parentMsg"></child>
    ( @! ?6 Q  z% O  ?
  6.     </div>  r$ u- j: B% R* A4 ]7 y
  7. </div>5 Q7 u3 p6 y0 r5 E4 R# m# h
  8. ; n# Z, o1 e9 C; D
  9. <script>; p/ ^7 `) J' p
  10. // 注册
    ' r- F/ f! ?' V* `# X" d
  11. Vue.component('child', {
    . n" R3 F) k- T+ a1 ^
  12.   // 声明 props5 h( i% d% v" ^$ }9 u. o
  13.   props: ['message'],
    ( t1 z; K5 L, {- a2 n' _
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用! z5 t/ Y1 Z% ~$ ~& w1 S4 V5 R
  15.   template: '<span>{{ message }}</span>'. q! K& ?1 F4 z# o
  16. })
    3 v6 N% p6 x$ H% P4 ^
  17. // 创建根实例! E6 |4 @3 B+ d
  18. new Vue({
    2 z  A6 [( T4 |, l
  19.   el: '#app',- ?% a5 \) ]: ]: R
  20.   data: {
      H4 Z% c8 m) ]  \7 s2 c
  21.     parentMsg: '父组件内容'
    ( z/ b+ z; U, D2 Y7 q/ n
  22.   }$ ], n6 H: X( l. t0 O/ Q
  23. })4 @' ^! ~& g/ H  W, j! D- ^
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
# A) w' H/ ~- v$ O( s) f
  1. <div id="app">
    & e2 A( C+ m/ J" }3 H; a* ^  f% ~. P
  2.     <ol>3 P$ c6 P4 t: S/ s+ G+ `8 Q7 G" f
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    " h/ `, x8 y3 _- [0 f
  4.       </ol>
    $ b( y  i! r' W0 g
  5. </div>6 B0 U1 m* M3 O: l; }) B! y- Q
  6. 7 b' ]3 L7 E5 M. S) c, ~  }
  7. <script>  P" t2 s- R( p7 Q0 [/ V1 E
  8. Vue.component('todo-item', {
    ; c4 Y7 c5 u' A) |4 i
  9.   props: ['todo'],
    # s% s4 D7 y0 }7 m
  10.   template: '<li>{{ todo.text }}</li>'; i* N' r9 w% v0 z
  11. })
    ! t6 I* U* H. v5 Z: s
  12. new Vue({
    - A, i% K* a# }: ?5 Y0 h, E
  13.   el: '#app',
    - Y# @' U" ^! Q+ ?( T8 y) z1 m
  14.   data: {# f3 k4 @* J) c. C' v2 J4 X  q/ R
  15.     sites: [* N& T% |& ^2 Q& s# o% M  F" q
  16.       { text: 'Runoob' },
    ) q0 N2 C' r' ~
  17.       { text: 'Google' },7 }6 w' y. [0 X3 O2 K3 o3 G6 b( w
  18.       { text: 'Taobao' }
    ( R* g% C' c4 ^$ u
  19.     ]2 N) g0 N# v' G; C  q
  20.   }1 G4 H+ [$ K1 i) ]/ S, J
  21. })
    3 v6 I% ]3 C4 k/ h) _4 f8 n
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    , x2 P# O1 t  D2 B
  2.   props: {3 |, y7 e) j) P
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    # K1 C0 b2 t7 _- {- r4 Q
  4.     propA: Number,
    * V. p% A- Q( T& ^+ K9 J, ?
  5.     // 多种类型
    + ?, i: u. }) h- T# a
  6.     propB: [String, Number],/ y0 v  O% ?3 e  B# O' B# W
  7.     // 必传且是字符串* F) o" c1 j) p% n
  8.     propC: {
    % f) A4 a4 t/ e
  9.       type: String,  U2 j4 R1 y8 z5 L
  10.       required: true
    8 ?$ E5 f, Q( b  y7 n& `4 d
  11.     },
    6 b& ^. W! J8 C% i) ^7 I( Z4 X
  12.     // 数字,有默认值
      G" y1 _$ {  U' V: k2 |; A8 I
  13.     propD: {  H9 W* f) x6 ?6 d6 X5 ?
  14.       type: Number,# p6 W  m/ @7 }, \) N
  15.       default: 100
    6 A2 G! ~- d- j: }1 f: q% X
  16.     },
    5 l0 a1 o6 _6 J+ z
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    , m& t7 x% N8 |' t  ~
  18.     propE: {
    + m. R" d% K, y' P" U3 {3 Z# Q3 ~
  19.       type: Object,
    1 S" r# `" x3 |. p$ S
  20.       default: function () {
    - r9 I2 ~8 b' _! d6 e  @- P- _
  21.         return { message: 'hello' }
    / r% G; x8 Q* E) D* N
  22.       }: Q4 C( w1 ]1 f# m+ W: t
  23.     },# l3 F+ j2 H0 g8 b7 \9 D- j) S# v
  24.     // 自定义验证函数
    " ~; O' M& w7 R2 G* @: u
  25.     propF: {
    0 x0 L# m, o, V. [
  26.       validator: function (value) {
    " B8 b4 o/ {2 f# i7 n' {. w
  27.         return value > 10, D6 W/ G0 @: y5 o1 W* x# r# a. |
  28.       }5 ~, y+ i  x: t/ q3 H0 ]
  29.     }: w5 _  A, `4 x$ h0 U( Q; u' b
  30.   }
    % I. Q  i) ]1 ~
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array. ?) n' j6 P; r( k3 [; @
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件8 P8 c; R% O% E& U7 z
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例3 D+ X4 E* `2 d3 _8 S+ f/ d
  1. <div id="app">
    3 u( h/ ?! R1 V3 u  o+ t
  2.     <div id="counter-event-example">' M4 Q0 F3 S) V
  3.       <p>{{ total }}</p>( V0 m7 ^# `+ F5 j/ |- L) ]/ \
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    7 s6 m( \7 X; |. b: J& B( k
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    " G' H+ e0 U- h7 w) o8 x
  6.     </div>! R9 c+ z3 t0 g7 D* B$ }
  7. </div>
    8 ^$ y* x1 O' Y5 W% Q8 [, g

  8. ' l9 L/ {8 u: u$ j2 o
  9. <script>
    + M9 E+ A4 k: H  [% \+ b4 Y
  10. Vue.component('button-counter', {
      N* d/ J4 J4 F
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',8 q2 y" S% R# J" l1 T& N" V- M. k! L
  12.   data: function () {& c7 b  d' Z' L3 N8 U
  13.     return {$ t: _1 }0 [9 g
  14.       counter: 0
    6 C0 L) q; c# z2 d
  15.     }
    1 ?3 z. s9 k0 ]  [8 C& C
  16.   },! @; ^8 x0 f; [* r6 c
  17.   methods: {
    8 p  Q1 N! {, L3 H1 l1 X
  18.     incrementHandler: function () {
    , S% e. T2 `( Z; N+ V
  19.       this.counter += 1
    4 P7 p- i0 q1 k4 w4 U
  20.       this.$emit('increment')( M# c2 \- w- X4 n9 V% N2 I( `0 J
  21.     }6 q( R' y% W3 q; Z8 w8 i* e  ~
  22.   },' L* E4 _& ~0 p3 [) l
  23. })
    5 s0 U2 s2 Z0 ]
  24. new Vue({
    , }# L0 s4 b4 L; f) t, D2 a3 y
  25.   el: '#counter-event-example',
    . y3 n# h7 T  H+ I: ?4 X0 A( H% K
  26.   data: {
    % P; n6 @( L6 b- O
  27.     total: 0
    : a5 r! E7 q/ h( Q
  28.   },
    & [/ b) @# W7 R
  29.   methods: {
    * ?* Q3 ~. B: p
  30.     incrementTotal: function () {
    * p. \. k; y- [* h5 A
  31.       this.total += 15 h6 V5 ?9 L: v$ J) O5 q) L
  32.     }
    + k8 z  U1 ]2 L# o, ^4 @4 J
  33.   }
    8 g4 C: Y7 E; H, x: I
  34. }), s/ S3 b4 Q& j. f. b: Q7 |
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册% b4 M% O$ S1 E$ H. K- p. H
  2. Vue.component('child', {7 [& X( A2 J/ h- `
  3.   // 声明 props& w  y5 j' v; M! J
  4.   props: ['message'],
    7 M  ^0 `) B4 S1 M# X& z) ?1 A4 k( x9 ?
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    1 O+ M3 o0 B5 j1 H1 y
  6.   template: '<span>{{ message }}</span>'8 S/ [3 C5 j: \) C/ N
  7. })& [6 d" N% m# G" y* Y7 a) u/ ^/ T
  8. // 创建根实例
    & |. W% I: h# m& l
  9. new Vue({8 `( X+ T+ O# [4 w% e) @2 {
  10.   el: '#app',2 X* P9 I0 q$ I$ D3 u
  11.   data:{" B: u) B$ v  Y
  12.     message:"hello",5 a! C+ @2 U# n2 G- v5 w0 Q. Q3 ~/ z5 y
  13.   }* C  P4 ^1 P9 C1 d9 F( h2 O% p# p3 ~
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    7 X; D8 v% P! V; T+ a
  2.     incrementHandler: function (v) {& r, ~  u7 ^5 t. q+ ^  C( d
  3.         if(v==1){
    : d+ r' m% y1 W  U& Z
  4.             this.counter -= 1- Z7 o4 W2 K" w( _& f: \
  5.             this.$emit('increment',[1])
    ! U4 a  e# R( k$ q# S
  6.         }else{- o) W* M4 Q5 q( N7 ^
  7.             this.counter += 1
    1 [( |& j7 P" P$ Z
  8.             this.$emit('increment',[2]): Z  Y4 v1 }) S- b6 q
  9.         }
    + }5 g  B% v  ]- \
  10.     }
    ! D( y8 P3 @: k% }" |- x/ o* g
  11. }
复制代码
0 b) ?7 G0 P! @/ m

1 T+ E, h# z& i4 [) f2 X
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-19 12:07 , Processed in 0.128575 second(s), 22 queries .

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