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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

$ ?% x' X$ |! Q% ]5 u
  1. <div id="app">  y  N4 e) s5 Y# X( E& j: f/ T& a
  2.     <runoob></runoob>- v/ _- `1 x' F( f+ j' c
  3. </div>4 t# [+ D- X$ W/ i# D/ c+ F  n

  4. , n" r! D, n! D9 L" _
  5. <script>
    / i+ y, ]" ~1 x$ s7 I1 x/ ?, z
  6. // 注册
    ! @8 R: H# O# ]7 ]0 n, {
  7. Vue.component('runoob', {  P6 g: s( h  M* o0 Y9 G# K
  8.   template: '<h1>自定义组件!</h1>'
    . B( e( q" Z& Y" _
  9. })  n7 r% R5 o# l$ D% ]) @  @
  10. // 创建根实例6 X: V; I9 [& r4 b6 H" U/ t: [
  11. new Vue({& A- ^' W( E8 k7 f1 \3 z3 o: Q
  12.   el: '#app'
    , l0 \/ S' V  s1 x! k0 ^8 H
  13. })# o5 C2 B* M8 J# w1 E
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
% d3 T$ ^+ U% r; z8 F4 U1 k, L
  1. <div id="app">
    ' k: L+ ?/ w9 C
  2.     <runoob></runoob>: i: p# f* H0 u2 }8 I
  3. </div>
    6 @5 G6 I- w7 Q

  4. . A: p% r0 a  j/ K6 g( T! C8 e, h3 b* n
  5. <script>
      @6 c" [4 ]# q
  6. var Child = {
    ! G! m' M+ h  Z
  7.   template: '<h1>自定义组件!</h1>'9 f1 c- H' a; K+ T5 ]6 ^
  8. }
    + l' ^9 Q( K% {$ v$ J3 C' Y" F8 D
  9. : E& ^- E2 X" E$ ~) }( L
  10. // 创建根实例
    0 V8 k5 U3 m& t+ I
  11. new Vue({% ]3 z4 X! [, V5 N! w+ a  ?
  12.   el: '#app',- @% x- U" q. g5 U
  13.   components: {
    ( K/ i( O4 S3 C4 I
  14.     // <runoob> 将只在父模板可用" b: ~# \6 |- d9 e- K% G2 ]
  15.     'runoob': Child: N. D6 t2 R) w% }
  16.   }
    2 _# f% E- k. x* _2 }/ A8 |! D
  17. })
    ' s, z4 x$ D  K' U0 E
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例3 J1 ^, N% I3 ?
  1. <div id="app">
    % ?: ~6 I7 r8 ^7 r
  2.     <child message="hello!"></child>
    . I! w6 l! s9 Z
  3. </div>
    8 Q; H1 H$ J7 C- z6 B, L
  4. / c8 w. ~/ w0 x
  5. <script>9 w- m" e6 H9 z! T, _  J
  6. // 注册5 \6 {9 ?6 x; B' ^
  7. Vue.component('child', {
    " u; W" ?4 m& I" s
  8.   // 声明 props
    3 @' L8 J- ?$ k0 l" j& C+ e
  9.   props: ['message'],
    & f) U! B3 y- h2 t
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用# p& z3 y" T7 A4 g+ h3 i$ J
  11.   template: '<span>{{ message }}</span>'
    * @+ F4 O- s$ ~, Q9 T
  12. })& {. w9 h/ F! S5 S+ }
  13. // 创建根实例
    & D/ V: w; w  W: m+ }0 h$ Y) K  o
  14. new Vue({
    1 s. d2 b; e) ]' R  A$ p$ G
  15.   el: '#app'
    2 \2 J. t2 s8 ?" f1 O
  16. })
      d8 Q& X6 C+ ^3 G% s  i
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例  i8 Z; I# r( f, R: T7 @+ d7 g9 J
  1. <div id="app">3 t9 a/ T( F& i6 c4 y" t
  2.     <div>
    4 X, k$ [! ~. \9 [9 s) s
  3.       <input v-model="parentMsg">6 y  i- Z$ g$ K0 Q1 d1 _
  4.       <br>( c2 d+ r2 b4 X# X9 P/ [( `
  5.       <child v-bind:message="parentMsg"></child>
    3 s' w' Z" t  ~4 Y8 s" \  E
  6.     </div>: Q+ w: i, A- D% t( n- u% |
  7. </div>) f( p4 u$ |, I# n. ~) c! \

  8. " [1 U' ^% v, D' `+ B" T: D) B
  9. <script>
    4 t3 E- a& a" u; u6 I. _/ y9 d
  10. // 注册
    ( _% z5 |9 x! ~
  11. Vue.component('child', {1 w4 p; _3 {3 H, L% _* N
  12.   // 声明 props
    ' O/ d* q* y1 {/ x# j' [' a
  13.   props: ['message'],
    9 E7 Q( o& U6 O" `1 r: k
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用, F  X) Q5 L+ x& Y4 i
  15.   template: '<span>{{ message }}</span>'" `' W: N: q3 n- s% F
  16. })
    1 i) [. B) n  o3 ?& y& X
  17. // 创建根实例1 N# u8 L, w# g, u1 F( @- Z
  18. new Vue({
    1 r4 A4 S/ v, c- K" n
  19.   el: '#app',
    0 g# m5 ]! s$ d0 y* X) H: T
  20.   data: {
    8 j/ x5 B; P; Z8 i* w' i8 k
  21.     parentMsg: '父组件内容': e  X. n: l; W- x) Y2 l- O4 L
  22.   }
    4 I1 ?% b' k0 ~8 U# h) j& p
  23. })
    8 v: |3 r) ?/ L
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
( a5 Y; K/ D! Z, \: _& D' }
  1. <div id="app">
    + _8 L9 p1 x1 u( g) X8 x
  2.     <ol>! P5 y4 X" d. \" L# J( O
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>2 F7 Q. v7 N# u8 F. r
  4.       </ol>* `' a0 a+ I2 K% e* w" v. b, F( R- O9 d
  5. </div>
    ( z0 a6 P, t: [

  6. + _. j& o' x+ G: Q! z. f( D
  7. <script>/ S( @! }& x! P1 C- {, r- @
  8. Vue.component('todo-item', {& p6 R! w+ R) O
  9.   props: ['todo'],
    " [6 |) \+ X4 m- o# n0 R+ q8 ^
  10.   template: '<li>{{ todo.text }}</li>'5 |  s( Z( n2 U( [2 W. R
  11. })
    2 B1 r) U  H- _# d0 |) E3 e
  12. new Vue({0 G1 `" X$ @* C
  13.   el: '#app',
    ; H+ }0 X. k  z% q- p  C
  14.   data: {
    ' k  q7 N- v- j+ ?$ {
  15.     sites: [
    1 s0 j- {- T: r( o+ d( z
  16.       { text: 'Runoob' },, s3 A6 Z8 c. z7 J3 [4 K3 k3 {
  17.       { text: 'Google' },
    / H7 D9 C$ G% i7 U4 e, t/ n
  18.       { text: 'Taobao' }- l- `$ z0 [% ?/ X( U5 G
  19.     ]# m  v( H% X, A% K1 W) k7 H9 d
  20.   }$ }0 \4 F$ {: Y- D
  21. })" @( S! F2 m$ i
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    1 J+ W8 p6 X0 T, b$ y6 r7 u
  2.   props: {
    % M) ?7 L( ~0 P1 P
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    / M" E! K  p7 S1 e
  4.     propA: Number,
    6 y% T7 t8 B) B& b) `2 U
  5.     // 多种类型
    " j# X; T, ]- Y1 c
  6.     propB: [String, Number],% }" D1 ^7 t# ~2 F' z" Y
  7.     // 必传且是字符串
    ( L! Y! l7 t1 b  p- Z# v
  8.     propC: {5 i7 K1 A2 V9 U0 [. f2 J
  9.       type: String,
    0 x- u+ f$ n/ {/ ?+ W
  10.       required: true
    + b" r$ T& @5 @" y) i* {2 ~
  11.     },0 ?$ x7 C0 M5 g6 F+ z. z0 a
  12.     // 数字,有默认值+ M9 P2 W, X8 V9 @( V
  13.     propD: {
    ! W3 r4 |: S0 D! @
  14.       type: Number,
    & P. J& r7 k; I6 i6 K" y
  15.       default: 100
      ], t% K6 h( f* K
  16.     },
    , B5 {; W4 L( }( s
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    / h+ c0 F& v1 X" i0 w: d) a2 `
  18.     propE: {5 [2 F. I# x- s; d' ]1 ~
  19.       type: Object,
    : h3 ]; H1 f5 o
  20.       default: function () {
    % L  |' m( y; D' j% |! @8 L
  21.         return { message: 'hello' }
    " b( h9 P! [: k% _$ p+ B$ g# K3 ]
  22.       }
    0 s- k2 [0 k" W0 d+ \$ m3 z: W
  23.     },
    / k: U1 w( p  H) ]9 B. {% G9 v
  24.     // 自定义验证函数
    ) M& R3 k: j% o- t* y2 E+ [( |. ^
  25.     propF: {% M3 t$ m6 F  V( f3 h/ b
  26.       validator: function (value) {7 G  Y% \4 a# T6 L0 d2 A2 X- O, a
  27.         return value > 10) e/ ^7 F* J2 [" M5 a8 y
  28.       }
    ' f, o0 `7 ]; J/ a" I0 i" K
  29.     }
    3 H, A8 _" @$ F4 R, [
  30.   }2 ]2 d( @) X7 ?& s2 i
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    # ~( j* e4 Z9 _% F6 [% c$ y$ A
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    8 R- W! n, a" D1 ], u
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例$ ~- i! s; E7 W4 I
  1. <div id="app">9 X4 \! }) q  ^( Z& \2 m/ N
  2.     <div id="counter-event-example">
    ) Y) n/ l% }1 ^, H8 H9 p' i* H
  3.       <p>{{ total }}</p>
    $ b8 G5 E- d/ f  J9 G- Z& n0 J: ]' }
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    + H  L/ h. Z1 I
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    # l, z, w) h; e$ F. C0 O
  6.     </div>
    " ]2 c0 U; \' h! ^8 I: |
  7. </div>
    + t- Z, m4 @+ g# P, D- ?
  8. 2 Y! {+ ?; }' F( w8 \
  9. <script>
    6 T. b# [5 U" h2 N4 t/ C
  10. Vue.component('button-counter', {
    / w9 Y% K# a3 E$ x% L' p) a
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    * K6 W5 J. x, D
  12.   data: function () {1 a7 ?* X2 N( Y
  13.     return {
    / b& B  H: a' D' w! J
  14.       counter: 0; w! n* N* l6 U: [! j9 y# L3 y; u! A
  15.     }' L# q1 D: {7 J* e
  16.   },
    - k, Z/ g/ {" E$ P# ?( j5 o1 U& A
  17.   methods: {" E3 o! m3 I8 S& o0 c
  18.     incrementHandler: function () {
    0 F8 `/ T2 f" I0 D
  19.       this.counter += 1
    ' a9 ]# r- m( x; s
  20.       this.$emit('increment')6 D9 R! f3 ]2 e, W5 V1 ^& [. _: r) k
  21.     }
    ( D! A- V6 \- F
  22.   },7 g; q% R  M3 e# k6 K- v; j
  23. })( v2 v! k* H% o
  24. new Vue({
    4 M3 o( W; W; m+ R9 W! M0 x
  25.   el: '#counter-event-example',
    / s) k9 M7 W* N( C$ P8 T
  26.   data: {0 ^8 f7 Q( Z; R4 i, [8 `
  27.     total: 0
    : U* w4 E# o% `. H4 H3 b
  28.   },
    8 H" K) S( x# s! }: z
  29.   methods: {# F' j0 ^+ K+ Z1 Y, [2 a: q3 P
  30.     incrementTotal: function () {
    2 \. v* S! J5 l# |4 \
  31.       this.total += 1
    - x6 i7 p& J. a
  32.     }$ J, \0 S5 M4 i# x
  33.   }' x" O7 P. N/ f+ K! K/ M
  34. })- l# f: A  ^4 @
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    2 C. l. G6 q5 c, C  t0 e4 m2 t
  2. Vue.component('child', {6 ~: G! y% U+ W; `- Q8 ?+ r
  3.   // 声明 props
    5 g* o' A  X% n  {  `1 d  l
  4.   props: ['message'],
    . o! ]* ]; v' T4 E# _6 j
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    7 F3 c8 f  [0 j  T' @# J4 R
  6.   template: '<span>{{ message }}</span>'. R, s; b5 H5 S$ Y' H' |3 ?
  7. })- ?+ G; \& y) y$ o& c+ ]/ D  S4 `  u
  8. // 创建根实例+ Q: Y% H1 Q; ~' b3 _. p
  9. new Vue({
    & U9 [' R$ z/ I) X, s2 ~
  10.   el: '#app',
    5 i7 \0 H# {7 a/ A
  11.   data:{
      u4 A1 Z* y' N; G6 y
  12.     message:"hello",
    4 `' A/ \  A, C* P5 D3 v
  13.   }0 Q$ Y  v; X, n' h7 n8 _& E
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {5 x. ~9 V- B+ D/ W& A; `, P
  2.     incrementHandler: function (v) {
    1 _7 |( |# [/ b0 y3 B
  3.         if(v==1){
    3 b* K! ^9 N8 k* y# ^3 p+ B
  4.             this.counter -= 1
    * S$ p2 `  @: }: ]; S9 c1 w5 R' D8 y
  5.             this.$emit('increment',[1])5 Q: i+ g) z/ w  w' C8 z0 l& Y
  6.         }else{: k2 C+ M0 F0 I  A+ q- X( X  ]
  7.             this.counter += 1% x, W6 m( v" V; y2 v
  8.             this.$emit('increment',[2])
    ! ~+ s# l6 v( b$ T( h
  9.         }! V% t9 ]1 _$ ~/ S
  10.     }
    $ N% H9 I+ I; K* m
  11. }
复制代码

0 S0 {" \9 D! ~
" X$ p: _% s$ A% }
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-9-22 04:12 , Processed in 0.056244 second(s), 22 queries .

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