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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15354|回复: 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,并使用它:

  k/ o( j- V7 R. x# p
  1. <div id="app">
    9 m( b3 O( q7 D  v9 B+ P
  2.     <runoob></runoob>2 z  [, w& \, J! B& K
  3. </div>1 C* P9 m' X" C! ]( L+ \' C
  4. ) h& h) Z1 u: |9 y
  5. <script># |6 G. r+ i" W2 x/ @
  6. // 注册
    4 C5 i/ T# y, t* j& d9 P. h  D
  7. Vue.component('runoob', {
    ) l& S+ v! m, x, U# {& r
  8.   template: '<h1>自定义组件!</h1>'& V& [0 f% V# {. S+ C8 H  W
  9. })9 h: d& Z2 d8 F9 f4 N
  10. // 创建根实例
    8 d" E% k8 r! Y1 X3 |* H* z5 E
  11. new Vue({
    3 l' k9 o1 m* Z" Z/ ]8 ^
  12.   el: '#app'* W# y2 y4 s$ {$ @0 q, Q1 N
  13. })
    ( {$ [2 l/ q. U8 G/ P- C( t. {  D
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

# k: p9 T8 Q' s
  1. <div id="app">
    9 r% X. v' ]9 n
  2.     <runoob></runoob>' U# h, D( }2 }" W
  3. </div>
    ' m. ^# O8 A9 l

  4. 3 _0 Y) d& M& {5 R2 C
  5. <script>( s9 Q# ~( H- @2 U/ h6 w% y
  6. var Child = {
    4 l) w: d; Y# m
  7.   template: '<h1>自定义组件!</h1>'9 ^4 V. D* `& _+ g5 ^! F
  8. }+ ^4 |0 u0 z' k$ _6 f

  9. : e; ^; Z4 v: D" C7 i  S3 `
  10. // 创建根实例
    ' k/ Z; j7 d) Y+ l$ U- w
  11. new Vue({  ]: W# U; k/ T* Y  e  F
  12.   el: '#app',
    ) V9 E) ?7 c6 I1 g
  13.   components: {' K9 [. ~5 G6 |8 m. Z/ t
  14.     // <runoob> 将只在父模板可用1 x% H- K# F: T/ O0 }+ R3 B
  15.     'runoob': Child
    / Z' W5 g: d/ }% t; Y1 z. A. V* ~8 _# x
  16.   }
    6 \) }+ |9 U, ^5 ]5 F  q
  17. }); q  I3 K0 _$ R
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例" o2 I$ T3 e" N+ I, i: l' p% {
  1. <div id="app">+ b# E/ N* @% g/ P, M/ K
  2.     <child message="hello!"></child>% i) x; i* Y7 g2 L1 g, T
  3. </div>& S  [  L3 I  Z
  4. % W& m! ^7 N7 S# d
  5. <script>1 J1 c3 n+ i' \8 y* A0 k9 H  }
  6. // 注册
    " m! g8 b' d& y5 P
  7. Vue.component('child', {
    ! t7 ~0 _( [/ u; b+ E) J
  8.   // 声明 props2 \$ a$ Y$ F, d9 @0 J
  9.   props: ['message'],
    - y" \6 s) A; u* I+ o
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    1 K, `' u2 u) L* {# i4 p
  11.   template: '<span>{{ message }}</span>'
    7 [' Z% I' @% l; A# W
  12. })' s) h4 s/ ~: [
  13. // 创建根实例
    1 V8 @6 G, f. B# _$ H8 j
  14. new Vue({
    7 G- n+ b3 Q6 y# ~  l( y
  15.   el: '#app'$ w7 Y* S) N& p5 n% m7 v- V
  16. })
    9 F$ ^3 \' u5 L8 f+ z9 o, a0 w
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例+ \$ N1 q  _0 T" U1 Y
  1. <div id="app">: H2 c$ {3 E2 w, j/ g+ p
  2.     <div>
    8 B: M* a& t/ j" \$ l8 v% y
  3.       <input v-model="parentMsg">$ K; Z6 h" _/ g9 W6 R
  4.       <br>' N& P/ v/ u3 L0 c2 Y
  5.       <child v-bind:message="parentMsg"></child>
    . w3 T! i# }) s9 l) v( {; ]
  6.     </div>
    $ @5 l/ j" h' e: H) H
  7. </div>- ?. @1 ~* p- E1 _1 l) h9 I
  8. # i- a( {  n4 T: u: B4 i, ]& \
  9. <script>% ]. e& S' {' p. @/ V3 c" O: E3 p
  10. // 注册
    4 o5 z1 G$ G2 h% c+ e; `- _
  11. Vue.component('child', {
    0 q: a. p/ o* z: ?$ O# M
  12.   // 声明 props
    * W; i( G3 W( m  K7 F
  13.   props: ['message'],
    : w# B2 y: u. }/ Y7 k+ n# S! u; M
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    / J4 k, w! x2 T% _
  15.   template: '<span>{{ message }}</span>'
    2 n5 N' S" g! `3 n) n/ x1 O
  16. })  G  U7 H& i! R" d8 l( x7 \) K4 A
  17. // 创建根实例' N" j! U* C& {9 [+ @, r" y
  18. new Vue({
    . P; M# u5 y$ z6 s8 E- P! t
  19.   el: '#app',
    0 W. k( `2 G/ `
  20.   data: {' b7 O; V: n4 e3 m6 p" Y
  21.     parentMsg: '父组件内容'  c+ q) v9 h  A$ m; M
  22.   }0 t: P" u; d! \& H* A3 P3 Z3 ^
  23. })' w% r' y9 z; y, c5 z
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
1 G. T8 h+ [+ }! c2 K2 k, G/ b
  1. <div id="app">9 _# [8 b6 l& U
  2.     <ol>
    & Z+ u1 }* S; y; G( S, i
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>" }5 b# {1 d/ s  ~2 S% ]* H. m8 _6 \
  4.       </ol>
    % n0 o# p+ K- ?$ K4 y& J3 S6 K
  5. </div>% b" v. [9 M4 V) }% I
  6. * k) O: s) x, d9 r" u* ^& I
  7. <script>( {5 L2 @. o, {) b
  8. Vue.component('todo-item', {
    3 z* \/ M0 J- |8 b& u2 @
  9.   props: ['todo'],
    : b9 O- R  W. _4 p# R9 R
  10.   template: '<li>{{ todo.text }}</li>'+ i" r6 R2 Q) n# }5 m, e8 ~+ ~& J4 o
  11. })9 Q0 e' p6 g- c& R! o
  12. new Vue({& S( T9 \) }( r! v
  13.   el: '#app',5 X; p" |* m. W& }3 {
  14.   data: {
    $ N( r' }" @% U, e: b, M
  15.     sites: [0 `$ k; S$ m- z$ }, M
  16.       { text: 'Runoob' },/ ]/ p" J5 S+ z; e% L- V  f: I
  17.       { text: 'Google' },
    7 R6 C! b+ U0 @" w( C2 @
  18.       { text: 'Taobao' }; M3 D/ ~) v! [9 }9 k
  19.     ]
    , t* T; d' v5 p; U, b
  20.   }
    1 Y0 h' {8 c5 [& m/ E/ ^4 S
  21. })" \3 W1 D" |0 S2 y4 t+ B
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    2 \5 B/ C$ k2 v; e
  2.   props: {0 Y7 `3 v* _/ o( U* F
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)8 V6 i7 H; \$ R# x1 k6 O$ R
  4.     propA: Number,# Q4 w1 h- o  R) I8 s6 D
  5.     // 多种类型( i  W- q6 E; p/ l/ @" t7 B
  6.     propB: [String, Number],
      G+ W" u) d) y. B( R" N+ C. M
  7.     // 必传且是字符串
    7 s& q$ D( z+ I' t
  8.     propC: {
    : L9 O) B1 z& e
  9.       type: String,! a3 o' {  N/ O" b
  10.       required: true
    0 g* u- b3 v" N3 s% s: `- s5 E4 c
  11.     },; U4 y4 D. G0 K! G) a
  12.     // 数字,有默认值, C- X6 H: C+ a* J7 c8 ]
  13.     propD: {
    ! n3 T# g" r% F4 g0 W2 c8 ]: u8 f
  14.       type: Number,
    % @+ _; i  K  i( |
  15.       default: 1003 F2 O* C8 E' u% \% U
  16.     },  U3 H8 Q' ^$ w* u& F( V
  17.     // 数组/对象的默认值应当由一个工厂函数返回3 w) A! H$ z2 b, }6 H5 ]3 B+ C
  18.     propE: {
    # x. }8 q: M. M+ {5 a" j
  19.       type: Object,: r# p3 @) W1 s
  20.       default: function () {
    . [& w4 z( Z* e) s5 b
  21.         return { message: 'hello' }/ |# T5 C6 T- D2 J
  22.       }
    % B1 Y0 `/ @8 H7 ~0 e- D, @
  23.     },0 b3 o' C  n! H& g$ e4 L# V
  24.     // 自定义验证函数1 b6 c- C0 ^1 _; `
  25.     propF: {. Q/ I( N* [1 W
  26.       validator: function (value) {2 s+ |3 R4 r7 h# |$ V" y
  27.         return value > 104 [6 D3 P- z% B/ |! j
  28.       }1 ~! O& u: @5 Q5 _
  29.     }1 q0 p% D3 j/ O
  30.   }
    * V  v: p) ~5 b
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    $ ?) {# L" m* m: l' Y
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    ' Y) s4 u* F; S/ x
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例1 N* \' E' g' w6 J, L5 q+ D
  1. <div id="app">
    + I- d: d- w( W" }
  2.     <div id="counter-event-example">
    , d: o4 j# v/ m: f; q" m9 a0 a
  3.       <p>{{ total }}</p>
    7 h) B! `/ x+ p1 J# X1 f0 a% E
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    4 @5 E# a3 ~6 m8 y
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>8 |, t5 e  y$ A0 u
  6.     </div>( v0 `# i$ w: m0 M8 k3 i% C8 A
  7. </div>
    ; b/ B! }9 j/ i& s( ]
  8. - o# o; q& x% k1 W- ^
  9. <script>' i4 w3 _; G' b
  10. Vue.component('button-counter', {
    & @( m0 D( f" ]/ [$ k
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',7 k5 r7 H* T4 ~3 c# U1 E
  12.   data: function () {' T& _9 r- k9 ^5 u1 o$ y3 y2 O
  13.     return {
    ; v5 m3 G2 Z* G1 y
  14.       counter: 0, N' t8 b0 F) x( }9 b& Z$ F
  15.     }
    & c& P0 m+ R3 G5 I- H0 Q
  16.   },8 r# G  [* P/ Z1 J
  17.   methods: {
    1 H+ \9 H$ F; W8 s. B& `
  18.     incrementHandler: function () {7 }- ~2 k) R+ Y3 s# P& Z
  19.       this.counter += 1: u; D  M/ [, @
  20.       this.$emit('increment'); q8 F& H( K4 {8 O
  21.     }4 i4 N1 W2 a) `9 p0 T. b. W
  22.   },
    5 S5 d# `+ P  E2 b) @1 u
  23. })9 r+ R. ?4 ?  H5 C
  24. new Vue({
    , u. C- H# X4 @2 v' y8 ^# k- p0 o
  25.   el: '#counter-event-example',
    " H: _& q; D8 k) K
  26.   data: {2 M  Z* S9 M  ]' H" \, A
  27.     total: 0  F5 b7 F$ t/ _7 c  Q! H
  28.   }," G0 ?0 b1 g3 `# m
  29.   methods: {- h3 H7 F2 u+ a4 f7 w& c$ U$ S
  30.     incrementTotal: function () {' k2 l# E/ e, n) `) ^
  31.       this.total += 1+ k2 N/ ]: |" p, f, I7 R- H
  32.     }
    9 Q9 v* x: Y" X
  33.   }
    7 R6 B2 L* T8 N0 `$ z
  34. })- v$ P$ V5 L% r8 v- q7 y% Q
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册- b" ^% l- w# O7 L- y$ Z
  2. Vue.component('child', {
    0 D, f& M3 {* d1 O8 `2 ]% i0 ?
  3.   // 声明 props( U" ~1 V. \5 U3 ?
  4.   props: ['message'],2 U$ _& _3 e# ?; B" b: t
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用$ i3 W* ]1 n; B1 `
  6.   template: '<span>{{ message }}</span>'; ^$ F7 c& q6 z7 J0 l( J- P8 s- w
  7. })* x7 j& |! ?3 C; \
  8. // 创建根实例0 g; U. H; f$ W7 R' ^
  9. new Vue({
    6 N& n5 q$ H- b
  10.   el: '#app',9 K8 H8 c7 F+ W' }3 P+ L; N; M5 Q
  11.   data:{4 H6 F$ Y6 E# I* h
  12.     message:"hello",
    # G2 y  M0 h# m* M
  13.   }
    " x, w. x1 _% u  |
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {3 r0 i  H3 e) O1 B+ L! I7 o5 \8 e
  2.     incrementHandler: function (v) {
    ) }0 z7 L% w1 i! s- Q
  3.         if(v==1){
    + `" F! T6 Q2 [# o2 G; R4 ?' _
  4.             this.counter -= 1* ]# j0 C6 U0 x/ B/ F5 M7 Y5 t
  5.             this.$emit('increment',[1])0 q( W" U) u3 c3 X& |% L2 ~
  6.         }else{
      E" s; V4 {* A3 u, d$ }; g
  7.             this.counter += 19 X; f8 t( N' G+ `5 A
  8.             this.$emit('increment',[2])
    " p) q6 v8 E5 o* T: a
  9.         }* |( V+ Q1 d* H7 D1 N  p2 u
  10.     }: x5 X6 x8 ]/ E+ m* |
  11. }
复制代码

) N5 c% U4 T# X5 H: r0 J2 N6 j% H2 `1 C% i
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-16 18:44 , Processed in 0.062485 second(s), 23 queries .

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