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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 11479|回复: 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,并使用它:
5 p4 C  S% @# w3 D$ D$ K
  1. <div id="app">* {; b. {/ N& h% Q7 d& S
  2.     <runoob></runoob># a, q8 h- h2 B! a0 Z
  3. </div>
    # E+ {8 o) U' s( G
  4. 9 D, k) }! `; p1 }- y
  5. <script>
    " F9 w; t! {/ I- V
  6. // 注册2 P! q& U; Z8 F8 n* l
  7. Vue.component('runoob', {
    + a2 n+ V2 c8 ^+ H
  8.   template: '<h1>自定义组件!</h1>'
    * Y( X& o8 P, K4 k2 n: v8 ?! o
  9. })
    % F+ H! Z" \) {0 @+ h+ u2 ^0 ~
  10. // 创建根实例9 j8 Y+ i; E6 ?' F2 q: m
  11. new Vue({$ x! f6 D$ q6 \6 t3 `
  12.   el: '#app'9 h& @8 Y- r: M* a
  13. })
    ; i# V/ [& {3 c
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
. B7 |( M% ^- Y  l3 Z3 r$ m& D+ S
  1. <div id="app">0 s- W/ L; n# {6 L& n/ p5 |) D* r
  2.     <runoob></runoob>
    5 p! X2 ~0 _$ j6 l( N: {
  3. </div>! X7 W4 Y0 N6 A# T1 D2 U

  4. 9 K2 p4 J4 }- d4 `5 W
  5. <script>4 O5 F% I0 I0 e, C; G
  6. var Child = {2 \& v7 e$ B: ?* c0 O' M
  7.   template: '<h1>自定义组件!</h1>'
    $ Q4 x0 r  J( m% ~" K9 o6 v7 o2 G
  8. }
    . t& k! W- A! I& _4 C& v
  9. 8 H# t8 d" d+ d, M
  10. // 创建根实例/ f# J/ ?$ h. M  V, y1 T' ^
  11. new Vue({" y, A' e7 W# i1 F& o8 G8 K; n( A
  12.   el: '#app',) o( u: m. {, j
  13.   components: {/ C# |: X4 N( y( S
  14.     // <runoob> 将只在父模板可用, `1 Q4 ~$ m+ b" ^: ^
  15.     'runoob': Child
    6 @0 @5 ~7 Y3 L; l3 p: D, c+ A
  16.   }
    6 g! A6 J$ n* m% G% q; y5 A# D
  17. })
    4 ]9 x2 x% `7 c6 K' E6 i4 P, c
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例2 q/ C+ A2 z% [3 P# G
  1. <div id="app"># L' n* V7 K+ s. c& t9 Y8 C( [
  2.     <child message="hello!"></child>" S3 n, O6 v- \$ U; @, S
  3. </div>- g* N, X+ \( S; o
  4.   f8 e2 \2 u0 t; y
  5. <script>
    " U. j$ y4 e& Q, h% _
  6. // 注册( i% Z" R9 i; n
  7. Vue.component('child', {
    7 [: ?1 `( R; @
  8.   // 声明 props8 v: Y/ I& k1 l9 F* U" Z
  9.   props: ['message'],
    6 u8 `+ t5 k% ?+ Y/ r' C" O8 k2 H
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    9 b8 f, J" L9 i1 l; D1 b3 O
  11.   template: '<span>{{ message }}</span>'' U* ^; x- ~( K% V7 h4 g6 C: C/ E: I
  12. })/ ~0 f( E) ?+ V8 t/ ?
  13. // 创建根实例4 H; V5 X: F" X: x. X! A
  14. new Vue({
    $ E" i7 Q* O' Y3 a7 v- }" o
  15.   el: '#app'1 Q" S6 D) X0 b2 w/ O! M/ f
  16. })
    / U3 C4 {! u: M' T
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
. L" b5 Y7 l! M. U
  1. <div id="app">
    " Z' D. \7 K$ D3 ]
  2.     <div>; K2 J9 _. g7 `6 I# Q! ^8 Q
  3.       <input v-model="parentMsg">% _5 z4 r" c3 q3 r4 M
  4.       <br>
    % _& N( g: o. H& X2 M& P+ k- `
  5.       <child v-bind:message="parentMsg"></child>: i4 g& ]" X: j9 d  m. x2 c6 N
  6.     </div>
    . u" |, }* W9 d+ V% B, D
  7. </div>' z; l$ s) ?7 u: n# f8 `8 t
  8. & i" G$ s1 s. R- X' ^+ y* }
  9. <script>
    3 g: }( K) @( q7 a
  10. // 注册
    ( W3 W! m+ Q# B; Z) O% V; S1 ^$ M
  11. Vue.component('child', {
    ' s4 l, H: m+ f! T: x6 m7 F: x
  12.   // 声明 props) n6 C% J4 y6 f- i, t  S: @, ~
  13.   props: ['message'],
    0 a7 S: l5 u7 \# i
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用& e- I7 c$ d# ^, G  o0 ~  K/ o
  15.   template: '<span>{{ message }}</span>'( o- o- B* S6 K$ H. n- x( q
  16. })
    ! B. W# R. I" ?2 t/ j/ D
  17. // 创建根实例' Q( s6 b6 Y# ]4 I8 W
  18. new Vue({* j2 c& {% ]( d  a5 _/ j
  19.   el: '#app',
    4 D8 M) _1 q& J- }1 L& U- x
  20.   data: {* j& Q* K+ P; b6 G1 t
  21.     parentMsg: '父组件内容'" L9 F, ?8 L3 }7 F! E( A2 X
  22.   }
    : E6 T4 v& y% }- ^8 F
  23. })
      V. V$ ~+ X; l2 }
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例7 v, e7 [3 [, y: B' p! M
  1. <div id="app">/ G4 d, Y3 j" C
  2.     <ol>
    # q* Q# u) r6 a' d: G) A
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>! Q& s* t# ]9 C: _  Y& q
  4.       </ol>/ j/ E6 p+ L, j: t7 O! Y& h6 K) g
  5. </div>9 V) w+ ?4 D9 h9 Q# r! p/ L0 {% r, }
  6. & B5 q' P, a7 }0 y- [9 L  S) Y( y
  7. <script>8 c% x( ]% R! V9 z* a9 Y6 a
  8. Vue.component('todo-item', {
      {5 u% U( I( ~9 A% ~
  9.   props: ['todo'],
    5 H7 G8 u1 _' x9 O- y7 }5 ?
  10.   template: '<li>{{ todo.text }}</li>'
    ( s& B5 X, P4 Z  w6 J( x
  11. })+ B7 g- G! S- ]' ]
  12. new Vue({
    + r; X& R" x. U& b5 g  r' P
  13.   el: '#app',2 Q- K# U/ p( h
  14.   data: {" p$ t% c7 a0 a( Z) Q1 B
  15.     sites: [
    % s6 B  o1 Y1 W: A* d3 G
  16.       { text: 'Runoob' },
    . {/ n4 D  ~6 Z2 d" @# I9 o
  17.       { text: 'Google' },5 G/ ?& A. X# I$ M/ `
  18.       { text: 'Taobao' }
    # V6 g2 P* r; p6 v  ?: c" W4 k
  19.     ]8 j, z+ @! F9 @) |3 }& t- L
  20.   }1 X/ |- R3 H# b( i5 S
  21. })
    + [- }6 |) H/ t; t$ _" b* o6 n
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    . P4 z) [) q/ c) y( ~$ W& |
  2.   props: {  }( e+ L( G3 F3 n
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)- [% V% ?; L' w& h6 {, k
  4.     propA: Number,
    , [; A* Y4 C5 O* z/ _
  5.     // 多种类型6 \! X6 _& Z- q4 f7 f
  6.     propB: [String, Number],& Z0 n' \$ n# h3 D; i* K, _* Z
  7.     // 必传且是字符串
    * l2 U- b: {' c. @6 V7 D% ~
  8.     propC: {$ r) P" w5 q: _
  9.       type: String,; j' N. o6 ~$ J' ]8 y" |
  10.       required: true
    3 H: N9 V1 g( |" P1 z
  11.     },' z- j* Y2 ?% c
  12.     // 数字,有默认值
    5 w9 h- \! d; c$ L- Z7 }: n
  13.     propD: {+ |# L% G4 A) s3 _
  14.       type: Number,2 U  M& J% \% a0 M, D
  15.       default: 100
    , M: H# w/ Q2 a
  16.     },
    . X- B+ [" Z! F
  17.     // 数组/对象的默认值应当由一个工厂函数返回: g4 ]: D2 e: d5 e
  18.     propE: {8 F# c9 s/ J6 e$ [- f5 u
  19.       type: Object,) D. {- H+ C; {2 `
  20.       default: function () {
    . |% }* J$ [* F- w
  21.         return { message: 'hello' }
    + t- h: n) w' d. y
  22.       }2 f6 N- a% h  [9 ]9 [
  23.     },  k9 H% O# S/ @$ I: l4 B  j
  24.     // 自定义验证函数
    ( G0 ^) e# j4 x2 x; D
  25.     propF: {
    8 S4 }" d% ]: \9 y5 f9 A& `
  26.       validator: function (value) {  o6 X! w, R" N: I
  27.         return value > 10
    1 [, [$ A+ ~4 C7 a; ^
  28.       }
    0 O/ ?0 z0 l: t) ^8 n* |+ l
  29.     }. X. t9 U- p' J. e" J2 ?: t
  30.   }
    9 `$ p* ?. D; g: k/ A! }" s: {0 Z
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    % f3 l) M% e) @5 I- V
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件: t+ V# E& K" Y3 X6 T
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例7 R9 q7 a/ y3 O" E+ R- ]0 _
  1. <div id="app">
    ) }: n* }3 ]# u+ [$ ?% _
  2.     <div id="counter-event-example">
    / k. Q0 f- j# N2 j* T
  3.       <p>{{ total }}</p>% V" c" o" Q+ Y  f+ ~) B
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>, N$ U5 O! s. k0 @. p* R8 n
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    # P7 V& y4 B2 e+ r$ Z% Y+ c1 d' X
  6.     </div>; K( q- t( p/ U2 C; J# G
  7. </div>5 R- k$ S" z+ @% ?3 X

  8. + h1 K  T( t) s4 {4 m3 f5 `
  9. <script>
    8 n3 r8 i: c  O- s% G6 J
  10. Vue.component('button-counter', {$ y8 m' v! u! j2 a1 {
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>'," i; @+ l$ l7 o
  12.   data: function () {& @- u- n, ]8 R& _  n! P1 |' z0 [
  13.     return {) Y- i; I; D# O& `# ^7 \4 ]
  14.       counter: 0
    2 F; ]/ L$ m0 N8 ~: P# m! j5 z) Z
  15.     }; I0 E: v) |( X
  16.   },
      d& H- U( a7 j+ D! u
  17.   methods: {
    7 _1 j$ }, a- q
  18.     incrementHandler: function () {
    % b) Y4 i0 y/ K$ q" s( z
  19.       this.counter += 1* ^: t$ [, W) l6 q
  20.       this.$emit('increment')
    5 U# \0 l. k: d' [* w
  21.     }
    + S, c5 v! t/ T3 K3 r. i
  22.   },
    9 F! e1 h7 z- _
  23. })$ Z4 }; y. }# s+ m" U) A
  24. new Vue({+ T  N& n6 p$ e1 b8 ]
  25.   el: '#counter-event-example',
    : p2 B" t) c7 j2 j( c
  26.   data: {
    ) e- R' p3 ?, u* @7 k% C
  27.     total: 0
    + _4 K4 o% X7 z# y
  28.   },5 \4 G5 c  F9 ]" s- q. F# i
  29.   methods: {/ h  w6 Z$ `9 I0 r7 V( V
  30.     incrementTotal: function () {
    $ T, E3 B# W5 t+ ~. ?7 f0 E
  31.       this.total += 1* m0 j1 G. P: L6 ?: [9 h9 y9 o
  32.     }' q/ h6 s" @# u2 F6 a! j, [
  33.   }
    & S4 h; p, T; l- q. z- A
  34. })
    & V7 ~8 @$ }4 \
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册: ]  ~4 s+ c  p* p, p9 P
  2. Vue.component('child', {
    ' ~9 R* q2 ~# q* A
  3.   // 声明 props
    - ^4 S' R* c' j
  4.   props: ['message'],
    4 [  ?( u) i5 m
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    3 K" ]0 m4 x, \
  6.   template: '<span>{{ message }}</span>'% H+ `# a1 a; i- s% a8 F
  7. })+ C8 {8 b0 Y6 P! A# j
  8. // 创建根实例; ?* a# }- v* W) S
  9. new Vue({
    ; l/ n3 F& x" Y5 p
  10.   el: '#app',' m$ ~7 H1 ~$ v& X+ f
  11.   data:{$ j; q" Z8 c- A9 Z  O) `5 x9 I
  12.     message:"hello",
    2 i, }% A  ?5 u# R1 F
  13.   }5 J1 }" k5 R# ^5 }/ Z
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    1 r9 A/ ]% b0 P* v- z) z
  2.     incrementHandler: function (v) {
    , Z% _) r# j! v9 W- R& x
  3.         if(v==1){! Z4 x$ O1 i- w9 n, r- e4 e8 \
  4.             this.counter -= 10 }: ~7 R) ~" {5 h
  5.             this.$emit('increment',[1])) x9 b; N7 W0 R! d0 w3 s
  6.         }else{
    3 G7 q$ J8 B( b6 E9 G$ e
  7.             this.counter += 1
    2 T& Z! A- H+ U- _) T5 [
  8.             this.$emit('increment',[2])3 ]0 }3 r! ~% X
  9.         }
    9 i& z: h0 I: m7 F% b; [% i
  10.     }
    " ~( N+ _! f0 c! n- ?
  11. }
复制代码
, W0 t$ H0 Y0 _% a; J0 |

8 q' c/ S5 V: P$ w$ t3 B
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-6-19 06:25 , Processed in 0.126071 second(s), 22 queries .

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