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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

/ H5 b. g$ G& x# P/ `0 Q$ f
  1. <div id="app">
    , o: p5 u, W, F9 G
  2.     <runoob></runoob>
    7 w2 b! C  R2 N
  3. </div>
    & z! s, {1 A9 K1 h8 ?
  4. ' [5 u, t5 {) K: T* o$ W! ]
  5. <script>. g/ K! C0 I  ]0 @4 ~+ l5 N4 b+ L
  6. // 注册9 k6 w6 P! K1 d: h6 {4 }5 h
  7. Vue.component('runoob', {
    4 T# Z' I! Y8 k5 \/ c9 S3 m. n
  8.   template: '<h1>自定义组件!</h1>'" H/ U( K& v8 g
  9. })
    0 x7 L+ K# x' n9 e0 n
  10. // 创建根实例  F8 Q5 S  m: r6 J, P+ L- k* c
  11. new Vue({
    ! E5 ^7 x; s, L6 _7 ?! a
  12.   el: '#app'
    + [" u+ [' X7 d% u( n0 c& G1 G
  13. })- v- e1 u& C. O' \: y- H( G
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
9 Y# k/ v. ]" F1 r: e
  1. <div id="app">- J# A) ~# \0 P9 ^: R$ X
  2.     <runoob></runoob>
    0 ]; g# Q3 R- s
  3. </div>
    ( l& i# B. V# [' ^! m  o6 u  }

  4. # \: l* m) @1 F
  5. <script>2 t# X6 H. |& P3 _% U# D7 i" f( k
  6. var Child = {
    / l" _& Q2 R& F
  7.   template: '<h1>自定义组件!</h1>'
    " g( V8 H) o" v$ R2 w1 @
  8. }
    3 \6 ]' V3 {5 e1 c; f4 `

  9. 5 }$ a! @& r, {% ^! G; z
  10. // 创建根实例
      _' S  d7 l" A  L. H) a( x# c' a$ e
  11. new Vue({
    ( M7 A) F- z% W
  12.   el: '#app',- d6 m$ e, J* {3 U
  13.   components: {
    " U: j  P, Y( ?9 j& q+ H
  14.     // <runoob> 将只在父模板可用
    - h6 W- J  g- H5 M% h9 R5 M+ ?
  15.     'runoob': Child
    / C! c! c4 }% u' c. `* F: `- ]
  16.   }/ d* P) N8 Y4 a- ?4 B
  17. })
    ; a  m& J, F% f2 K, b% _% b. v
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例) c, o) Q0 s% M& w& m. y2 q* k/ c
  1. <div id="app">0 w7 D7 a- k) x
  2.     <child message="hello!"></child>
    9 e% Z- a  a& Q, o/ g
  3. </div>4 D9 A9 e! A* Z& W5 ]4 W2 T) ]

  4. ' U$ g+ M' U8 O3 w3 H8 c
  5. <script>
    1 F' e! X# S0 D, r) t6 B- T' w
  6. // 注册
    1 m2 k6 x0 U* W
  7. Vue.component('child', {- i* I0 Y) ?5 g* l5 R- k
  8.   // 声明 props7 A$ f* s$ |% P* J
  9.   props: ['message'],
    6 q/ ~. D+ n) I. @3 d+ r' f7 [9 T
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    # R! X! M2 z3 P0 f1 i4 X2 h
  11.   template: '<span>{{ message }}</span>'. ^& h' d+ B* g% J# [$ N
  12. })) |; P% k& u+ g3 ]7 k
  13. // 创建根实例0 X# ]7 n  r! \8 g
  14. new Vue({
    , }! ?3 b* B4 ~) }: d  y4 ~
  15.   el: '#app'
    , T8 X9 X5 P' f
  16. })5 K: k; ?5 y- v* ^
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
. u0 C4 _+ h7 _8 K, k
  1. <div id="app">: X: O/ a- P1 z2 v/ S
  2.     <div>7 y9 F4 a1 R" J* H
  3.       <input v-model="parentMsg">1 }1 G2 x+ I& O
  4.       <br>
    3 q7 _- X! W5 a  s9 O
  5.       <child v-bind:message="parentMsg"></child>' |; H' ]1 X9 S
  6.     </div>
    ( l% i+ U/ ~" y7 g' {
  7. </div>
    2 H: K# B0 r  w1 |" H

  8. 7 F5 ?1 Z& x; b! @. C% w$ O
  9. <script>1 S& P. g, a& }# t2 V/ }' T
  10. // 注册* J! ?$ O/ j9 J5 f+ U
  11. Vue.component('child', {
    . X! o$ n) c  y, V# u5 B, c, N
  12.   // 声明 props- Q) r" B( `: r8 R7 R* Y2 K0 I8 g7 N: U; J
  13.   props: ['message'],8 ~6 Z9 u% G0 ~  E8 X
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用, D! ?' i4 F) F, \7 k+ j3 x
  15.   template: '<span>{{ message }}</span>'
    # u0 [4 J  r' v% Z+ r
  16. })/ H0 P( R5 z, f! b8 Y. a' q
  17. // 创建根实例1 r& L! B2 v  U0 F" c8 t) F  M
  18. new Vue({
    7 s( @, d! V1 e$ G- f
  19.   el: '#app',. ?8 ~6 U  Y9 x/ S" i9 O
  20.   data: {& F" D/ ]* V% G+ q
  21.     parentMsg: '父组件内容'
    + ~( \9 z. \( W2 _9 ]! y( \5 B
  22.   }
    . D4 R% ]- s: O
  23. })
    6 e, x% B/ Z3 G* h7 a" N
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
, Y- Z1 S# b1 P8 m0 k& ]4 N
  1. <div id="app">* k; n# C! n6 h2 A) B% @, R
  2.     <ol>. e+ C" Y9 f; n- X: t0 J
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    . l  b  U0 R! e1 i2 ?1 f$ b
  4.       </ol>
    , o: K3 @- ~8 `0 G' O; N
  5. </div>
    6 S6 t4 A3 z3 N( G  j
  6. ; Q. I% V6 i/ M4 H9 |# q. i) k
  7. <script>
    : [3 L8 \/ d* X$ k2 H2 \9 O
  8. Vue.component('todo-item', {: ]( ?1 ~: F6 b' s
  9.   props: ['todo'],
    $ h, I% T6 G. Q% V. t% e2 v. Y
  10.   template: '<li>{{ todo.text }}</li>'; E0 Y6 h1 {5 Q
  11. })# `+ ?! d4 q8 g7 G, N
  12. new Vue({2 K! n; I5 E6 t! N
  13.   el: '#app'," U3 p$ z( r% L$ c4 z5 b
  14.   data: {& }3 p) Q' s% u% g) ~$ Q
  15.     sites: [" M! A7 g  W' |- G5 W
  16.       { text: 'Runoob' },
    1 d" f" K9 d" N- b' U. t
  17.       { text: 'Google' },
    3 W" z. r, C3 s# u4 m2 c& n- ?$ f
  18.       { text: 'Taobao' }, ]; q: a% n$ G& O8 C+ j1 I$ o
  19.     ]$ G6 ], A5 w0 |. J4 [5 A
  20.   }
    * [' N% C7 Y( k
  21. })7 s, p! c" r3 x) X3 F
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    4 h1 ~+ r. `5 s7 r
  2.   props: {. \% p9 f& v, ~% f1 k
  3.     // 基础类型检测 (`null` 意思是任何类型都可以). L# n9 m; U& D0 t
  4.     propA: Number,
    ( N/ W  I6 l6 x' {, W5 M/ _4 C
  5.     // 多种类型- `) d! N3 _) Y1 z- X
  6.     propB: [String, Number],5 K: s+ r+ ]4 X
  7.     // 必传且是字符串
    # ^3 K6 K  ?  u$ w' O+ ^
  8.     propC: {( v6 U; `) @5 J5 V( s6 j4 F8 v& D
  9.       type: String,) o% P9 `. n$ V# |! l3 d
  10.       required: true
    8 u9 x! r9 p- S, R/ L$ u) K
  11.     },1 z- E, p5 Y# p
  12.     // 数字,有默认值. v7 `5 y/ `8 v' n
  13.     propD: {
      g9 [  ]. k' [1 V2 e
  14.       type: Number,
    6 a+ d. |7 Y# r- O& F
  15.       default: 100
    7 }( |* `' \( ?" w; a7 n7 w
  16.     },
    7 P0 I8 Z4 q7 U5 \0 p) D
  17.     // 数组/对象的默认值应当由一个工厂函数返回6 i" d4 i; e+ o- ?: Y  x, Z
  18.     propE: {
    0 E) z$ [; n  k! D  I% W
  19.       type: Object,# g' |) p5 I; M5 v/ Z' k! ~
  20.       default: function () {% Q, m/ W7 h/ j+ o: v
  21.         return { message: 'hello' }4 E0 p9 D& ~% _" I$ F: X
  22.       }" }6 v. L- a1 I
  23.     },
    4 B5 Q* l0 K4 ]9 M7 Z: H: O
  24.     // 自定义验证函数( o( ?: w6 X5 G0 G# e' U) s( B% k
  25.     propF: {
    1 i; I# R' ^) Q9 ?# {! J/ e8 i
  26.       validator: function (value) {4 J' J, w' M- P+ y
  27.         return value > 10& S' S* W0 T' p* w9 _' X, M! G* ~' n
  28.       }
    / ^# ^& g1 A! ~1 X; o/ C8 V3 w* V
  29.     }$ w7 G' ~, b" Q, O
  30.   }" X& p- z! K7 H4 F
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array8 K# n" U6 o7 J0 D% b3 ~- k2 X2 f
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件0 k$ K# E, y* e# E/ ?% r
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
0 a2 J' _' S- Y" q/ m" i
  1. <div id="app">
    : J) f8 W- U  ^) @$ o
  2.     <div id="counter-event-example">
    ! i7 c0 X% z, T' }4 S
  3.       <p>{{ total }}</p>; e- |$ _5 t/ `( a8 i
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>- F! \9 Q9 s$ H1 I" }% B8 E) y8 U
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    # F' V' o7 {/ w8 }, r/ P
  6.     </div>
    ; W; c+ b1 K$ l2 f  w% [; U  Y
  7. </div>
    6 E/ h( R8 `( J3 I6 O8 [$ E+ y

  8. ( ^$ J; ~0 i) q/ t+ d2 y, e
  9. <script>
    ! ^. ?. s  H$ c1 t( w/ {
  10. Vue.component('button-counter', {
    - W' D& |6 d6 e
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',  q) `# a% p4 _* q" P1 N- n5 K2 ]( ^
  12.   data: function () {' C4 t' }% h! m$ C
  13.     return {
    $ S1 a: m  E2 |& O! I2 M
  14.       counter: 0% G& f, u- D6 Q4 w
  15.     }3 _" i( D4 S- `/ F+ u
  16.   },0 z* X2 o# z. J; {  f0 H5 |
  17.   methods: {) N& i" z/ w0 r* d* U7 P# c! ]
  18.     incrementHandler: function () {, Y# K. L) C" t: ?0 U
  19.       this.counter += 1) h7 U8 k- @. h8 ]  H
  20.       this.$emit('increment')
    " I+ \, r! e( O" A$ M1 l1 Y
  21.     }2 K$ B7 o8 |+ ^, l% C
  22.   },
    0 b5 F/ X8 F8 [3 S
  23. })! `7 u6 m- d4 Y, F
  24. new Vue({, p+ e: V. u0 `, _& h8 a1 a% @- C
  25.   el: '#counter-event-example',
    . z1 v. D3 ^+ A: Q3 b
  26.   data: {
    1 J! Q; m& Q& _2 z# \# G4 j4 e
  27.     total: 0. C" B2 h5 _& w0 L
  28.   },
    / m4 o# c) m: @: c, L+ v
  29.   methods: {7 A/ S9 E: r  e. t
  30.     incrementTotal: function () {" V* f( Z( I5 ?# Q3 {6 n; ^) Z
  31.       this.total += 14 s+ u- p, J$ ~: t0 Q
  32.     }4 b& n" v: s; s
  33.   }
    5 N# Z7 G' u0 v  ]. O
  34. })+ _, w9 Z* t) p7 _0 s1 Q4 g
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    ( s  o: m5 o5 l, C! L  ~! l/ _
  2. Vue.component('child', {
    3 e1 ~# N, ^+ z( G4 z, U) A1 G
  3.   // 声明 props
    ' r" P( Z8 @, R4 M
  4.   props: ['message'],# ]& _5 [" v# C2 g1 P, H' G
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    0 S6 b! d( P) v* f
  6.   template: '<span>{{ message }}</span>'
    + g9 [, F' D0 ]( E
  7. })
    4 e5 F; P6 D* P4 c
  8. // 创建根实例% q6 o9 t' \& c( B! N% M
  9. new Vue({0 t7 I& @. H: G4 W; ^! R# J! i) B
  10.   el: '#app',5 V' i% A9 X! C& A7 ^3 j
  11.   data:{
    6 G% V" F# A& d8 v# x8 G
  12.     message:"hello",2 s1 m) F  [9 X1 k
  13.   }
    ) ]  e' a  y/ N% w9 e# f
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {7 W9 b3 I5 z* @$ f5 E" M/ c
  2.     incrementHandler: function (v) {* L, t- n% g1 k* \: b( V! _
  3.         if(v==1){  z" s6 _6 M3 Q6 \
  4.             this.counter -= 1) `9 Q' A, v/ `: t
  5.             this.$emit('increment',[1])' L- \6 d( p! H2 x3 |& P
  6.         }else{
    & o% {0 Z* {& Y
  7.             this.counter += 1: q- h' b1 C, E3 C9 H
  8.             this.$emit('increment',[2])
    + `1 |. y  g5 K: J% {1 Z" h. p) z3 Q( l
  9.         }
    3 `7 x. @( Z5 [/ V7 T
  10.     }- h' t0 J3 {6 v! o  r  D
  11. }
复制代码
# D* t' s! k# U7 M8 U7 j8 t

; C0 l. S$ h+ ]6 _5 x) m& F
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 21:39 , Processed in 0.116481 second(s), 22 queries .

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