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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

9 B* w* l' ~, ], M  W" W
  1. <div id="app">
    % b& \* `5 \" g7 E$ Y/ V
  2.     <runoob></runoob>
    * O- d6 _" C/ D2 p
  3. </div>; X5 G( p4 J4 z7 g' B+ u
  4. - [/ w! O& j/ u1 H8 @7 b
  5. <script>7 [; C9 e9 t! X# d0 g# f; X0 X0 z# A$ m
  6. // 注册
    " z5 A& s, ?; C- ?
  7. Vue.component('runoob', {/ h8 |( `6 D  t7 A& Y
  8.   template: '<h1>自定义组件!</h1>'% ]+ b, z4 r8 e0 I" U& ?
  9. })
    8 S  A, H* I8 Z6 ]" b" Q
  10. // 创建根实例
    9 O2 K9 |, D- ]8 N' u: z( @" J
  11. new Vue({
    ; k. \4 w& \0 W& i5 k4 \
  12.   el: '#app'
    5 Q! E& b* H9 a( d, r6 D
  13. })7 s# ]! j# \$ k( `8 R) x
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
8 F9 p2 [, L' R. s, w3 j" i0 t' h
  1. <div id="app">
    , `( I& H/ L, H3 w6 A# {& j) k
  2.     <runoob></runoob>
    3 k% J5 |# [4 m# Q
  3. </div>" y$ M+ m6 ^- F0 d& {. }0 }2 a
  4. 5 y5 r9 C4 d8 Y; n9 A1 ?+ I4 t
  5. <script>4 ~' j& m$ \% b
  6. var Child = {
    ; q4 s6 q2 a8 J. F
  7.   template: '<h1>自定义组件!</h1>'
    6 }$ O$ ~9 V% v5 ?7 E  d6 [/ b
  8. }) R2 f8 _3 v/ P
  9. & y. B. m( Q6 f( l" r6 H
  10. // 创建根实例: Y2 @, l" [( F
  11. new Vue({
    ( P1 O' ~4 K5 G: c
  12.   el: '#app',: m" Q& y# ~+ k$ ]+ S
  13.   components: {
    1 O) |. c! ?6 u# m7 J/ Q" n, @
  14.     // <runoob> 将只在父模板可用' J$ f2 |, X, i& K- S# l: I
  15.     'runoob': Child
    ; A3 B3 F0 s, Y$ Y* C# b
  16.   }
    0 j* J% d" w  f; [. k* D
  17. })
    4 H% o7 B6 q- Z: s1 L
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例4 k; Z* C5 _& i  I: h
  1. <div id="app">
    # W" D2 \# T! x  D7 @
  2.     <child message="hello!"></child>; h: d( y6 y$ _& n5 }
  3. </div>
    : {. F4 R0 ^' a% p! O& r& [& i+ s$ Z. }
  4. 8 n! M) Q" D" M
  5. <script>- o4 S+ s( |2 H" u. a5 L
  6. // 注册
    5 L5 P- t, X$ z! N
  7. Vue.component('child', {; c6 f/ |/ w5 ^6 B: f
  8.   // 声明 props
    : T- b! J3 q* K8 {. g2 e- Y0 @1 X
  9.   props: ['message'],9 C% V. H+ i* V# s
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用5 |, O, e3 V9 d
  11.   template: '<span>{{ message }}</span>'. |- X8 i: L% p1 L( W
  12. })
    9 B9 Q" z& u9 S# J7 M& C5 y2 ^4 r
  13. // 创建根实例+ W. V$ d3 q: s2 E3 \" t1 |
  14. new Vue({- g% ^8 c) w  x$ ^
  15.   el: '#app'$ i& d$ E) [* t7 s
  16. })
    9 o) g! Q' R+ m8 M; B
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
5 |! L5 S& t% ]) a% @$ k* v6 ~, }
  1. <div id="app">
    : Y6 B, y: D) J4 ]3 o' K4 m* v# M
  2.     <div>- g/ h0 [& E) c0 Y5 A7 S
  3.       <input v-model="parentMsg">
    0 E+ h+ e+ A$ h9 Q. p
  4.       <br>% ]. f$ Z3 F& M2 _4 X* b
  5.       <child v-bind:message="parentMsg"></child>
    ( _( U' k# H4 y4 @! T
  6.     </div>
    0 s/ g1 {! W7 u7 I
  7. </div>
      E* t6 u) B6 x" }2 G2 G

  8. . J- }3 K  S7 i( M) Y; L" j' H1 g" V
  9. <script>2 j3 C; `5 L" l1 I) R) c0 O
  10. // 注册% Q# ?* X" j4 c$ K$ R3 `
  11. Vue.component('child', {5 P; U# {, y) h( M" B2 X' J
  12.   // 声明 props( p: J! t5 J3 Z  ~# i. p. U0 {
  13.   props: ['message'],
    ' B5 K! G( V1 \5 L0 y
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用7 d% G" u4 u& ^' ?, t
  15.   template: '<span>{{ message }}</span>'
    9 ?0 O1 b  ~) d& w2 H1 c0 Y! w
  16. })
    ) i9 f( u) l! q8 [( z/ F* E% E- A
  17. // 创建根实例' @6 |/ F; T* a0 U! }: m
  18. new Vue({2 |1 C. Z- M! L, w
  19.   el: '#app',
    8 F* ?, x; u8 a6 Q
  20.   data: {6 R! [' |' @0 i7 E( D/ K; S( Y
  21.     parentMsg: '父组件内容'( J* c% i7 J+ \' ^& O$ E. N% \
  22.   }" F$ v  }  o- r  V* ]
  23. })/ c1 C. W4 V. n$ ]* K7 I3 |5 t; l) ^
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
& S0 a8 _3 K2 w0 |, E7 ]
  1. <div id="app">- ?2 w% h+ {) g$ [0 g
  2.     <ol>& m% X; `- K. x+ Z" H( [* V
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    ( g% H2 D4 `6 Q. J+ Q7 U. A8 |4 f7 W
  4.       </ol>6 N6 f/ e; [6 I7 _
  5. </div>* C& I) n4 i0 G. d3 i: F
  6.   X9 }  P2 X0 z1 ~8 T0 A
  7. <script>
    6 T0 \: L; x) f& e1 @0 L
  8. Vue.component('todo-item', {1 k4 ^! e" @2 l! ?& `
  9.   props: ['todo'],
    6 l8 c; t% {2 I9 N9 c7 j2 l: l
  10.   template: '<li>{{ todo.text }}</li>'
    - \* c, `& g7 M: _7 s
  11. })  b3 u. B1 L4 Q3 A) U2 L
  12. new Vue({4 C  m9 ?# f" g9 h4 R+ ^
  13.   el: '#app',
    , s5 ?3 X7 I/ w0 k/ b; ]! ~0 K
  14.   data: {; _- M& k  Q+ C. U( k& E+ P
  15.     sites: [5 {2 Y+ c6 R! S7 N. ~. b0 w" q
  16.       { text: 'Runoob' },) R$ e" s! v" Z: p- s0 s
  17.       { text: 'Google' },
    ) B4 |  R( B: G
  18.       { text: 'Taobao' }' [# Q4 ~7 Y% d- Y
  19.     ]
    2 n# {3 v' A0 |
  20.   }
    : a0 d( ^* \& H2 a
  21. })2 F9 ~$ h: c6 M  F$ ?3 a5 ~5 V9 l1 H
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    8 S# a: T; ~& Z: {, C* Q7 Q
  2.   props: {; I) |& R1 m% O" S6 m
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)* U! r1 F+ w0 Q0 z$ |+ c
  4.     propA: Number,
    : j4 O- s3 b' V  M
  5.     // 多种类型
    * h! d9 z0 b+ f
  6.     propB: [String, Number],# Y9 E1 O6 [, h3 _  l( i) n
  7.     // 必传且是字符串
    0 R8 A3 {+ w$ C: T' H% w) ?% X. I
  8.     propC: {% q2 r7 y8 j1 V' l  ?
  9.       type: String,: N6 t$ [) O1 l' v0 G4 i
  10.       required: true
    6 [4 C. W% }7 }( n
  11.     },! n2 p8 h+ k6 u# z$ H0 K
  12.     // 数字,有默认值9 R8 P* N$ q2 [, k
  13.     propD: {
    2 s) Y- i2 w& O" f8 N
  14.       type: Number,$ y4 |( S3 x6 k8 x
  15.       default: 100
    0 q% x( u  `4 j) L6 }/ Y% I
  16.     },
    & r/ s/ b- n/ I/ q
  17.     // 数组/对象的默认值应当由一个工厂函数返回+ u0 a2 n# l8 N
  18.     propE: {* F1 l$ o4 l: d
  19.       type: Object,+ _7 _# }. D! r) G
  20.       default: function () {
    ' f' \# N0 A6 W: x; K. f' H
  21.         return { message: 'hello' }
    ) |4 d- j2 q$ Q% O! e  \% V3 @
  22.       }
    + P& z" j/ ~! L
  23.     },$ T2 n" k% O' f7 _
  24.     // 自定义验证函数- E+ ~! H: I: W5 O* |: i
  25.     propF: {1 y: _  ]7 z3 ?9 N% h
  26.       validator: function (value) {+ I, i/ L; |* h1 @+ R8 I9 ?
  27.         return value > 10
    3 M  X% b& [/ a3 `4 S1 k8 c. d
  28.       }
    ' C' e1 j* B5 i9 M; H
  29.     }
    5 t) {+ W# s, i6 `7 o
  30.   }
    0 S) R8 D# a- }" a! k# p
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    6 X0 B1 B% a$ j/ e# R# B
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件9 f$ r5 |8 E( g- O  H, b
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例* ~. D+ v" K; Y9 v+ {) J
  1. <div id="app">
    " q7 z; ~% r7 U. ^/ s
  2.     <div id="counter-event-example">' V& x% `4 c& Q7 O0 l: A
  3.       <p>{{ total }}</p>& d: @& b: C2 {- m. L% E
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    6 h9 i, K/ O& D- U5 L2 F7 K
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>+ E1 F1 p* n- u2 `. s" A
  6.     </div>
    * k8 h5 b1 h& q2 ?
  7. </div>
    , V2 K% l& q  Y- Q, A8 e* m2 N
  8. ) w# V6 e9 T  P: l/ }3 m/ R  {+ W$ y
  9. <script>
    % b% f# @# M0 u$ U
  10. Vue.component('button-counter', {
    8 j& Z1 }& y( Q$ T( B, u" Q
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    2 }8 M- M+ \& Q6 d
  12.   data: function () {+ j; S) M: s# T, u$ I- G2 e- B5 Z
  13.     return {
    / ^, _/ Y$ M  p/ q- t9 X
  14.       counter: 0( l' ~7 h5 T0 R) f
  15.     }
    9 ]7 x( |+ Q0 x9 \* E( X* {3 A- v
  16.   },2 G/ C0 j2 d9 o2 \: f/ b" C4 R# w
  17.   methods: {
    ( E7 W- c: h* c" O3 q) H
  18.     incrementHandler: function () {
    , z  |0 G0 s4 L7 j
  19.       this.counter += 1/ I; ]3 w" M  d$ g% N
  20.       this.$emit('increment')
    : g, O. A' e! L; a% M: g6 F  I
  21.     }! W& T! I$ j) R
  22.   },
    # G  O9 o- U9 t. ~: P
  23. })$ V, T4 F' f/ _& _1 d$ f3 A3 z
  24. new Vue({
    - J% F( |  S; p8 r) O0 V
  25.   el: '#counter-event-example',: u7 }; F) ]; ?; ]& g( Y% W
  26.   data: {
    / w: Y) k$ j' d% ^5 ?
  27.     total: 0( B5 n; E  v# y/ k
  28.   },2 Y: @2 f# H! U% r
  29.   methods: {; y7 l& t% E' G  m
  30.     incrementTotal: function () {
    * A4 k- `* H  E( _. j% i
  31.       this.total += 13 n* |  `8 z5 g  D
  32.     }
      E. \1 B' \3 G" h# g" t; R" Y
  33.   }  ~3 V& D( m. Q7 p
  34. })% |4 ~  o" w+ M( K7 t
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册) }1 D. {" I) P; L
  2. Vue.component('child', {
    6 |. E% O. d& y+ k: A  M1 j
  3.   // 声明 props
    * E) _0 h9 K5 Q; z3 Z2 H5 Z/ ?. j
  4.   props: ['message'],
    8 q" _3 n9 }6 l9 G7 w3 W. {
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用9 B5 a+ O3 U( h" _6 e
  6.   template: '<span>{{ message }}</span>'& t  z! G+ [; [" ?6 K3 E. j0 q8 G
  7. })
    ' u/ H. U* u, H
  8. // 创建根实例
    / R4 _" W5 A  \
  9. new Vue({
    # x2 H0 X" D3 Z+ E! g' C
  10.   el: '#app',
    ! ~. u/ j5 x3 e/ J1 w
  11.   data:{
      a% ?" e& v5 p5 R1 X& k, a3 ~
  12.     message:"hello",
    3 h6 h% P3 x' I4 u" r9 `0 v
  13.   }5 o, c% x$ r8 {  _! E' h6 J
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    2 f, ?1 [5 k8 u  f$ }4 ]
  2.     incrementHandler: function (v) {+ s, k% Z- B. R/ ~# y
  3.         if(v==1){
    * e: o8 w( P- D: B% Y
  4.             this.counter -= 1
    9 q8 Y( R  j* c) c1 x
  5.             this.$emit('increment',[1])
    ) J9 A: h  x9 V8 f; q
  6.         }else{
    . j, F$ @7 h* E% o" e" x
  7.             this.counter += 18 N4 m; ^, D9 F( g
  8.             this.$emit('increment',[2])
    5 N2 t, r$ M" s$ V; ^4 Z
  9.         }  X8 R& ^* ]! J
  10.     }6 o7 ]$ w7 c" [+ `$ L3 `
  11. }
复制代码
4 K& U. T6 C2 R' g

3 Q# N2 {8 Y1 q) r! u
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-19 12:25 , Processed in 0.138686 second(s), 24 queries .

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