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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15838|回复: 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,并使用它:
! f% n  ?4 ^0 v
  1. <div id="app">2 y0 M7 g0 l3 W: n! ?! \
  2.     <runoob></runoob>1 u, ]% \* F/ W2 D' N# v
  3. </div>
    - ~* A' J) J8 q. ]0 P

  4. . Y- m" O3 Z# I0 c
  5. <script>
      O# K9 k" }% R
  6. // 注册
    ) P& v. u: R) n/ H6 |; x
  7. Vue.component('runoob', {
      j$ q: _5 N0 `! Y/ v1 r; ?1 \
  8.   template: '<h1>自定义组件!</h1>'8 Q2 {: ?+ }/ M* l, s
  9. })  E9 D- g! J( C  P1 a) a0 j
  10. // 创建根实例- {9 |. D+ I9 q7 z  p
  11. new Vue({5 }: w1 f9 Z0 c3 I1 G( d# |! T: @  _' X
  12.   el: '#app'3 s8 o& w* s; R! g7 R* B
  13. })& t! }0 N& o! ^9 G6 H! o
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

0 c3 Z: O5 `5 i. T9 ~
  1. <div id="app">
    * {0 J+ Q7 x0 A  L
  2.     <runoob></runoob>
    / h* C1 h9 p7 C! z" j
  3. </div>' ^$ z, f0 X6 ~* N6 ^8 N
  4. # ]  e' N5 B* W0 g+ ?! T+ p
  5. <script>
    + x% V1 T& l* ~7 M. a
  6. var Child = {
    $ k& u, A7 p& G) o3 I  x
  7.   template: '<h1>自定义组件!</h1>'
    1 B0 e4 _6 U- ~0 A" M" g
  8. }
    " l& D! Z9 S! i: `" M; I8 s1 ^! U

  9. . f! _" b: v5 I9 x* s+ ~) h
  10. // 创建根实例
    4 ~$ \4 Q2 F  m+ K8 [- R! d, f
  11. new Vue({+ {: Q% w! C2 l+ [, T
  12.   el: '#app',
    8 p6 G% b& U( g% M2 `/ E
  13.   components: {
    ) q" a. A/ F% k1 E; _
  14.     // <runoob> 将只在父模板可用4 `" E: f9 I$ ]' _3 c5 W$ X* T9 x
  15.     'runoob': Child, O; `4 k4 A$ G3 p, q! {2 h4 t& i
  16.   }
    $ c. |' l7 r# _3 }' W- b  q9 _
  17. })
    7 K% L. H* Y* C; o9 P* ^& ~
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例. e$ F/ `2 z* K) C' L) X, O
  1. <div id="app">
    . @$ r& [" T2 ?0 @5 }; i+ i
  2.     <child message="hello!"></child>
      h) {) }: [, \- z6 a
  3. </div>
    ' t, C0 e# v5 x' y! N0 O2 G

  4. ' a7 {0 `: K. |% t
  5. <script>3 J3 x' B! }# J# d2 W$ j
  6. // 注册% c* p' g: x. J
  7. Vue.component('child', {
    & r, }! j  J, K1 k) M4 o
  8.   // 声明 props
    ( P: p3 c. [% R: l  B: `" c; j; ~
  9.   props: ['message'],; N- C, P3 F- C" i2 n
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用' n1 r6 l* K5 e4 L
  11.   template: '<span>{{ message }}</span>'
    ! n2 c8 R) a& |  X
  12. })
    + @6 e4 T- q! v7 C/ \8 p$ \
  13. // 创建根实例4 C. _. K; q) e4 W9 P" z+ a. c: N
  14. new Vue({
    7 Z) B+ b) L' |4 F/ O; B
  15.   el: '#app', V. ^, d0 U) A8 x
  16. })
    * ~- Y/ X$ \8 j$ C, e' P" B: D
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
8 {, q  r( _. m( p. \
  1. <div id="app">. y* W4 z# R4 ^% g3 N6 s
  2.     <div>% ~9 Y% O' W+ _3 n' k& t  c) O
  3.       <input v-model="parentMsg">
    & U3 s% R* g3 x8 w
  4.       <br>/ ^2 F: K& d, s+ N
  5.       <child v-bind:message="parentMsg"></child>$ w3 \1 n* ^+ {% B# p
  6.     </div>
      G) W% P- G2 z) _+ N) T
  7. </div>3 c( Z" |6 K- g- l) S# ~

  8. ( Q5 M% K! c, `8 W
  9. <script>% B$ N, v/ ]2 ?% j1 [2 i! O3 e
  10. // 注册
    % G; u' Q2 s, f' G' G! {
  11. Vue.component('child', {3 K% u7 z4 K6 S+ H& s7 [, ?5 C. r6 O/ S9 ^  O
  12.   // 声明 props) |, x# G9 M7 T0 s# D5 f$ Y
  13.   props: ['message'],$ {# w$ b; k9 t& k7 r
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用' Q* d+ Z) |/ M
  15.   template: '<span>{{ message }}</span>'
    9 C: e9 H- M7 @
  16. }). h9 Y( p6 }/ G
  17. // 创建根实例) @4 @, Y* x5 l. S; V" ^
  18. new Vue({
    , [8 e# i9 V! E  Z4 f7 t4 p1 L
  19.   el: '#app',
    7 W1 A/ L: k: p1 |3 Y1 H+ X
  20.   data: {5 V* U; b$ N+ ^2 c5 U9 D3 q
  21.     parentMsg: '父组件内容'9 W% w  d) z, }) p) x2 D
  22.   }  R( I& i/ W' U' T" F
  23. })
    0 `+ M  o# @1 R% r2 H- C) j
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例. D- _* B! {/ |
  1. <div id="app">: r5 g4 G' s( F! B
  2.     <ol>
    ! Y  {. U2 h; o
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>5 F! t- K$ k' Q3 o& u
  4.       </ol>/ U& V% X0 u4 s" G7 K
  5. </div>
    & M: G6 D" }0 J6 f
  6. 3 G+ b9 n+ b6 f6 Z  w
  7. <script>+ ]9 N2 s% |# Y; Y  W+ J
  8. Vue.component('todo-item', {
    , o8 V& h4 G- w$ P
  9.   props: ['todo'],
    / x/ E- S  y6 X5 J" N
  10.   template: '<li>{{ todo.text }}</li>'( ~8 G! O+ a$ F9 b/ ^9 U
  11. })
    7 P1 B1 d7 P/ x. Y" ?; E+ S
  12. new Vue({
    - |3 T. m3 E2 h/ P3 L2 ?1 C! t0 |/ {
  13.   el: '#app',
    8 ^+ V& E" n! q9 A9 y. ~
  14.   data: {
    & `/ ?7 o9 b, H+ j7 U( C1 }' ?3 w
  15.     sites: [  U* C' N( o0 Z2 x0 n! {# g
  16.       { text: 'Runoob' },$ s3 h# m4 r% L. ?
  17.       { text: 'Google' },: E4 i, q- h8 d0 [% u
  18.       { text: 'Taobao' }! ^/ f7 _0 e* E
  19.     ]
    ! ?$ R0 }2 ?7 ^' A+ i# |5 C. x
  20.   }
    * n. C, U/ w3 j
  21. })
    ) H- ]' s1 x2 t% u" }) V; l
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
      A! H  ~/ G# c9 |
  2.   props: {
    6 y4 p- E0 r; [. T
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    ; ], I4 k0 M, n" `, j3 u
  4.     propA: Number,( \5 U9 R9 h4 C
  5.     // 多种类型
    ' X$ ]: k# s% W: V8 a" j
  6.     propB: [String, Number],7 m6 R' ~0 ^' m. O6 S  P5 W
  7.     // 必传且是字符串. B# u" e% c/ c- q- }
  8.     propC: {
    7 z* O3 c8 Q: @6 l
  9.       type: String,
    0 T1 l  X1 O6 ]* ^' g$ z( f, b
  10.       required: true
    # l3 p: t7 i$ [# g
  11.     },: t; ^* V7 E9 N/ {" N1 r
  12.     // 数字,有默认值
    . l$ C4 l% u1 `7 c2 R
  13.     propD: {, S1 ]& ?( I4 W
  14.       type: Number,3 Y! D8 g: j5 D3 C1 ^
  15.       default: 100
    & V/ E' I% _! c1 F9 ^" U
  16.     },; `. }7 R) u9 v* _
  17.     // 数组/对象的默认值应当由一个工厂函数返回5 e0 o6 R) V! ]# K' ^# D
  18.     propE: {$ Z+ d4 _) }& j, o' G3 N
  19.       type: Object,3 l, {) ^9 E/ z5 ]
  20.       default: function () {
      v: H1 Z" T0 c2 g
  21.         return { message: 'hello' }
    6 b9 S4 N8 y. w+ U% i
  22.       }
    ! n9 j5 A/ r; Y" y, z$ L$ W
  23.     },
    . A# {9 [$ }- t
  24.     // 自定义验证函数
    ' N% Z6 B5 W' s" s1 u* n6 ~
  25.     propF: {/ A$ ^3 G1 R) d! d. k: z, R
  26.       validator: function (value) {
    6 A' U* D# c0 E$ f- x" b, }# N9 Z
  27.         return value > 10& Q8 ~- n8 H; H
  28.       }
    , o( r8 W7 J$ W. x8 F) `
  29.     }8 J* I2 m% [1 O& l1 M
  30.   }' }- \9 R( g$ L+ L3 h
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    : F% Y/ m8 |7 T/ J% Q+ {
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    0 Z2 L- W9 ?4 _5 b
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例  }) V+ O2 x. O) ~  H; V
  1. <div id="app">
    : b8 }. i/ d. G5 r4 d: e3 D
  2.     <div id="counter-event-example">
    7 R# ]* B) g: [+ d: Y( g! i
  3.       <p>{{ total }}</p>0 y2 K- \2 r& P
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    + d+ ?) ^3 [$ [: Y1 m( i
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    % ]+ a5 M7 f2 x% R  R  \
  6.     </div>
    6 _& O4 L# M( L0 \* Z8 ^* A
  7. </div>/ g3 J- \" d$ g5 a" O8 F
  8. % m4 x* H, f3 c2 r( _% ~  e9 E9 |. u
  9. <script>
    4 k, \6 z& D: K; R- W; C/ L
  10. Vue.component('button-counter', {
    ' ^0 q, M# T8 U1 M; D/ h# h
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',! x3 P4 q4 j' i) t% {
  12.   data: function () {6 ~9 a! l, I; [/ f$ F* {0 y% r
  13.     return {
    0 @3 r5 `5 H3 N
  14.       counter: 0
    & |% G0 ~6 y( \) L) Q# o
  15.     }" H2 L" @" J! X* Z
  16.   },4 O0 {( W. y9 ^$ [
  17.   methods: {3 {9 Z/ Z9 b! v  ~  B5 |
  18.     incrementHandler: function () {8 U* k6 n- x" V  H; o
  19.       this.counter += 1  i- _& E& L3 I  c
  20.       this.$emit('increment')1 Q0 |* u1 u6 `! Q; ~* D8 m
  21.     }" p# p2 j5 e& U' t
  22.   },0 k0 Y1 U) ?1 ?: n5 A0 ^2 a
  23. })
    * u0 a7 R0 q! B
  24. new Vue({3 y! O8 G4 e1 P7 L/ E& d# G5 ?. d
  25.   el: '#counter-event-example',: k4 O/ P! i9 m( Z! M$ T
  26.   data: {
    8 {4 \+ N( _. a; A
  27.     total: 0
    9 n, T7 \$ w5 e6 ]0 D6 Z8 X
  28.   },
    ' V1 p! y9 e" g2 k2 r# g& F& p
  29.   methods: {% R' }' J0 V7 p! B- y
  30.     incrementTotal: function () {; i. l6 ]) `2 R" i( [3 X, T
  31.       this.total += 1. x0 Q) c+ {7 s( P  |6 T
  32.     }7 @1 j& I: [5 }7 G" B  i
  33.   }7 p  T5 r* [  k) j' K
  34. })
    ! H3 w+ Q- Z6 l. u- r
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    * H1 y. D( s8 I# c
  2. Vue.component('child', {
    / k" Q) c( Y# d2 f* F# v5 I
  3.   // 声明 props
    - ]9 f) \2 ?4 f5 E) B, S' P
  4.   props: ['message'],' S0 Z7 Q% z) R! d4 n7 e0 l
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用3 _' t. O$ S- Y: K
  6.   template: '<span>{{ message }}</span>'
    % Y9 L3 h6 J$ u) n3 m
  7. })
    3 y0 A" d9 g) a- K- P, C
  8. // 创建根实例1 Y; J; A6 o+ n
  9. new Vue({6 @& r' A/ r$ H/ u" B
  10.   el: '#app',
    * v+ \( i" H- q$ N& W( A
  11.   data:{
    $ q  |; V; r4 r* H4 S! o
  12.     message:"hello",9 s/ t. n- Y; H* S, ^
  13.   }
    . e& q3 {9 v; M
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
      g. t$ @. p  Q
  2.     incrementHandler: function (v) {/ z$ K. }; e- }$ p
  3.         if(v==1){6 F! k8 f7 z7 c; \% Q3 L9 I
  4.             this.counter -= 18 n) h$ W* M, a: q( r# T( A
  5.             this.$emit('increment',[1])
    & Y3 S: P3 k2 E  c) V
  6.         }else{5 {. u* |7 O# I. z$ u# G! }2 v
  7.             this.counter += 1
    & u; [+ o# ~5 G" T9 ]8 s. y  J. p) u
  8.             this.$emit('increment',[2]): D; S2 v% p' \0 X! H: W1 G: _
  9.         }
    6 @  H6 e+ N/ J& `
  10.     }; r2 `8 w8 E4 @$ s$ h$ l# Z" ]9 I
  11. }
复制代码

1 S5 y# `( E9 i7 H( a
2 u, ^7 U/ B  ~& z$ H9 ?# Z
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-20 05:38 , Processed in 0.068470 second(s), 22 queries .

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