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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 12760|回复: 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,并使用它:
7 |5 g  q# p9 W3 N3 \- C$ b) j
  1. <div id="app">
    + y) s* g. z1 S3 g+ a
  2.     <runoob></runoob>5 Q5 c/ |* z- g: Q2 B& N
  3. </div>( G9 Q* N& A" _+ a
  4. / W; h# w/ g5 m7 C# ]  H6 [
  5. <script>
    # X) Y5 L0 Y( k- m3 y) m. A/ g+ Y6 @
  6. // 注册& z  ?7 W( ^+ V, Z8 l
  7. Vue.component('runoob', {
    - l8 v: d# w, G
  8.   template: '<h1>自定义组件!</h1>'9 |% i7 T1 {8 W1 X; L# b
  9. }), D9 c! ?3 l) z$ o5 t5 A8 H3 v8 R( _
  10. // 创建根实例
    ( A' l* H8 d0 U  G1 F
  11. new Vue({
    9 x5 d9 P1 B' Y1 P5 L) N; _, \
  12.   el: '#app'
    ; ~* {& c, D" X4 E1 P0 r1 @
  13. })
    - D# ^" \: g6 x5 u" D% r! _6 J: M
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
; `& h8 ]0 {: \/ h- W- V
  1. <div id="app">; X* ?% }' h! \1 v7 w9 P1 e
  2.     <runoob></runoob>8 U: U' n7 O' \
  3. </div>
    9 t  I/ Q( B% j6 ?0 w1 }9 \2 {/ Y

  4. , O! z2 o$ ]2 S& j6 a0 l$ V
  5. <script>
    3 o; q, b: r! w$ J6 ?$ u/ p
  6. var Child = {- j5 j7 f1 \: J' }: U
  7.   template: '<h1>自定义组件!</h1>'6 ]. K; Q% @+ ^0 G2 b+ G
  8. }; x- e: }* g1 y4 ?( U" X" G

  9. . f9 l, W# X4 C/ |) T8 S  o6 v
  10. // 创建根实例) c( @* i- p$ I  ?; y& z9 X' _
  11. new Vue({
    3 |8 `$ R- e& I( f3 H% k  M
  12.   el: '#app',
    0 {+ Z) d; o$ T$ \% i3 O& A* r3 M
  13.   components: {
    2 Q' S3 C/ W' g6 {2 M2 a
  14.     // <runoob> 将只在父模板可用
    ( c6 Y2 ^! e% H$ z
  15.     'runoob': Child
    8 K2 `0 t3 H% [
  16.   }: R. A  S4 U% M) ^# h
  17. })& A4 H! U% L5 Q3 A4 r+ C3 p
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例; I7 P) A! a. G
  1. <div id="app">
    8 V2 o5 |0 G! t$ {: p4 c0 X. O
  2.     <child message="hello!"></child>( C8 J0 @  B& E4 a  U) q# v
  3. </div>. r, T; n4 q& ?

  4. & r0 n0 R- ]8 T+ m- L# ~
  5. <script>
    ( s( T" Z& b2 ?
  6. // 注册
    & i, Q! j6 r2 z, q* s
  7. Vue.component('child', {% T+ c" L5 \5 M$ T6 W/ e
  8.   // 声明 props
    4 c& }% ~0 L7 T& ]8 i% m
  9.   props: ['message'],9 r4 e0 F: R) l& n: h* w
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用1 _& a$ O( X9 M+ s3 b, J* g' }) c
  11.   template: '<span>{{ message }}</span>'8 v8 V! J+ O2 ?1 d& ^
  12. }). l; Z. y6 D4 N& d) |8 x
  13. // 创建根实例4 n; o$ |' }, J( S4 G8 s' b
  14. new Vue({
    3 h/ A) W& @" ]5 {2 z
  15.   el: '#app'3 L1 j# e& c9 P0 p$ k
  16. })
    3 w0 L2 W9 ?. K1 \
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例( i- N6 p3 o9 \
  1. <div id="app">
    ) V: E0 C+ o  v3 U* j& z
  2.     <div>
    : d: S# u4 \$ _8 V9 D0 @
  3.       <input v-model="parentMsg">
    : j; g7 O3 i: m" [; f# Y9 U9 d
  4.       <br>
    ) F) f8 q$ Q+ v( E7 g
  5.       <child v-bind:message="parentMsg"></child>
    ) U) J" E" T" B: ?9 I8 Y" t
  6.     </div>. H7 m6 f, a6 @7 v
  7. </div>
    ! H  M. w3 E- r

  8. ; }/ \- o. a5 V7 @7 \$ k; L
  9. <script>
    7 E" J* D# Y9 d( Y" s" o( [
  10. // 注册2 y& n/ e7 \& ^6 h; \5 T* A) P0 L3 o' Z
  11. Vue.component('child', {) ?+ y, V3 i3 R5 D
  12.   // 声明 props; K1 h. f7 i5 j" l. Q, B/ r0 o
  13.   props: ['message'],
    ; Z0 J  @" k% I; t( k1 }5 k
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用# W; q& h8 f3 B: a, r
  15.   template: '<span>{{ message }}</span>'! a) ^! E( d7 q8 _, N' V- P/ H
  16. })9 @7 ^% x. D4 y& L; r7 |
  17. // 创建根实例
    & T9 C8 {9 l8 o- s% i9 y: L5 {3 l
  18. new Vue({: ~1 Z, w' w+ b4 h
  19.   el: '#app',
    7 j" F: n; L' R* D/ i: m6 n& q
  20.   data: {$ @  }+ F# l3 x' s( q
  21.     parentMsg: '父组件内容'
    ) W3 R: d' \: U2 |; \6 l
  22.   }
    ! t8 n7 z$ s' d* T5 y
  23. })* ?( S, s# {6 H1 w3 u& n6 }2 Y
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
% w7 a8 E# t8 {. ]* L
  1. <div id="app">8 [7 x  ?" Y" E4 ]
  2.     <ol>6 ~/ X  z) ]0 S( }3 D" x
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    ( n$ F" k, ]6 ^. ?
  4.       </ol>
    ( g& o5 F2 b+ [  i# Z8 [
  5. </div>
    . B1 D4 Y' U6 F/ X; `' O: Y" L

  6. : R: Y2 x5 c: J+ m5 J1 U
  7. <script>6 V) o# l( L# @; t
  8. Vue.component('todo-item', {
    ' |6 x: b6 f' j  ~( y/ D
  9.   props: ['todo'],7 W5 {: `  E- a% q' E) M: }% y
  10.   template: '<li>{{ todo.text }}</li>'
    ' y& W* M8 u& [. Q# o) B4 S. ^
  11. })
    / [! c# q- h2 p5 ^" y1 d
  12. new Vue({
    1 q& P+ H# i  r# _8 ~- f
  13.   el: '#app',* \1 A1 [" s9 d/ G1 J/ P
  14.   data: {9 Q8 B7 f4 h0 s* j% u
  15.     sites: [
    6 J+ j* ^$ z( {4 I; {! [' f
  16.       { text: 'Runoob' },* x  B# a: b9 x$ r$ I( K: H
  17.       { text: 'Google' },
    0 j! G0 p* k- W3 P0 [! w/ A' C
  18.       { text: 'Taobao' }# F4 o8 @: g( Y0 A6 D! j
  19.     ]
    % q. F* [* z$ w" K
  20.   }5 x$ Z9 y9 F+ T, |! l$ S! _7 g
  21. })7 u" f/ i3 d' V3 i
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {9 b7 O, r$ A# @2 I6 Z/ D2 ^; n
  2.   props: {
    " h1 T9 g! `3 P1 b3 [( o, q! u  Q
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)8 M8 c) ~9 U( @: j
  4.     propA: Number,$ q7 J5 m9 C8 r
  5.     // 多种类型
    / ~9 y7 x; x, D* E
  6.     propB: [String, Number],
    & n4 ]+ W5 \% d6 R* A8 J2 F! N
  7.     // 必传且是字符串
    9 v/ n/ v  S" G* D9 `
  8.     propC: {, D" Q- q9 B3 T" r- q7 w3 D; }  X: P
  9.       type: String,# j, _: {/ J/ y- L" _7 _( ?
  10.       required: true( S; G( ]3 X% }9 J- N2 P9 I8 C
  11.     },& O% m8 Y6 O. A& M2 D4 \
  12.     // 数字,有默认值
    % v) u2 c% u" c9 ?8 D; ]
  13.     propD: {4 }! n3 d# y% l* L
  14.       type: Number,
    ; g- A/ R/ z' j* @% x
  15.       default: 100
    0 _% |& @5 i; G8 G# g8 k
  16.     },5 y* e9 V" V/ U
  17.     // 数组/对象的默认值应当由一个工厂函数返回# ^& v+ S- D, E  P6 p- R6 O/ C3 J
  18.     propE: {$ M( v) A. A8 |
  19.       type: Object,* ]' J4 a  q( l/ f
  20.       default: function () {
    * o; B1 @7 e; M2 o9 [+ y
  21.         return { message: 'hello' }$ Q+ m7 _4 U7 C( ~( ~% [9 s
  22.       }
    ( m' ^! g  t1 u* m
  23.     },
    1 W9 z, x+ {6 q' G
  24.     // 自定义验证函数
    + d& R7 _; `2 ^9 n' ]! a4 v
  25.     propF: {
    6 K+ v7 [8 F' L) X6 a$ x3 d( {* c
  26.       validator: function (value) {9 x) q, _4 Q1 o
  27.         return value > 10
    * u1 V  s+ p! ^0 B: G" w
  28.       }
    8 ?* l, Q) J) K8 A4 D
  29.     }7 w5 m$ F5 G* P8 L
  30.   }1 Q! _! ]4 [  j% ^: O
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array/ U& r( o* s& l$ N& E
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    0 @2 w. I* C" V) X! [3 n) O
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
3 Z/ m/ b; F; L) S# |* I$ ^
  1. <div id="app">
    ) V; o# \+ U7 d' a0 G
  2.     <div id="counter-event-example">
    : A! x+ f* ], v0 e& u
  3.       <p>{{ total }}</p>
    - E/ [' W8 w- c" ~
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>! c" f- S+ }% d: c/ {1 w
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    8 U. x0 ~" l  o1 P, p0 B; F
  6.     </div>
    4 d% x$ R2 P, t3 h% G
  7. </div>
    ( q# _) z6 l4 c) B/ e1 K

  8. ) g/ Q) H4 o3 M8 V6 `5 q% e
  9. <script>" ~: q" e* z# V0 }% o+ q; {3 n
  10. Vue.component('button-counter', {
      H! |3 o3 w8 P5 \+ l2 v" x) X
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',0 ^% q; U% x5 n% y! J6 Z" B
  12.   data: function () {/ z$ L9 j% G+ p( f: P: _
  13.     return {6 h3 t/ s' w* x0 j7 `$ r
  14.       counter: 0' U/ ~/ _! [2 l
  15.     }
    7 q) g$ T" J# M8 O% w' m4 m
  16.   },
    ( K: n; ]+ P6 c# u8 ]3 ^5 I/ n
  17.   methods: {) e. D, ?' B0 u- m1 _: X4 p; _
  18.     incrementHandler: function () {
    3 d) \7 v8 b% U5 U/ L. g+ M; {9 U
  19.       this.counter += 1
    ( k: q$ z% K8 j
  20.       this.$emit('increment')
    9 I0 o% ]0 U5 ]: ]% I7 c* K
  21.     }3 o% w. M2 v: s
  22.   },
    , E7 q2 B0 P( |0 B, F( s% l/ d
  23. })
    0 S9 b9 \" o0 d: O, u
  24. new Vue({
    * i- ^/ q! Y  `
  25.   el: '#counter-event-example',
    . z+ t6 p% ?( i* h
  26.   data: {: l  q/ t5 H! d- b4 J
  27.     total: 0
    ' [# M& H/ z8 R5 J7 Q0 X
  28.   },# q: d) X& t9 K# {4 U7 {
  29.   methods: {
    5 R- k+ _9 C1 e2 X% ]1 ^5 I
  30.     incrementTotal: function () {
    8 h7 e% e. ~) K# S
  31.       this.total += 1
    ; P5 t6 u+ y! V# t
  32.     }+ o5 {( a7 O  P0 ]4 o! Z' r4 a
  33.   }4 L# ~5 _: W+ P, E
  34. })
    * \# ?3 U4 P; Q( b, k
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册* @1 {* R4 b# |0 g. H7 U% ^, D0 O# R  b
  2. Vue.component('child', {
    - g2 T* n$ f& G- \* p
  3.   // 声明 props
    $ p8 M1 x3 A7 ?: k! M9 _2 G/ T) L
  4.   props: ['message'],4 I" J( L" Y6 u. `$ `8 |- m
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用' H7 j7 C/ {! x- v% o
  6.   template: '<span>{{ message }}</span>'- `! I& c* a9 U: Y& `
  7. })
      v, x1 b/ y' h0 J
  8. // 创建根实例+ J! u! M( d9 ^: z/ f# \
  9. new Vue({/ y" @8 y' [; |1 @
  10.   el: '#app',
    - v/ G, c5 v) B
  11.   data:{
    / K9 W" H! n7 v8 n& \# i# D
  12.     message:"hello",  o% W# _7 t1 _; Q
  13.   }
    , e+ u  w& c$ _' Q
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {+ R; {, z# R! @
  2.     incrementHandler: function (v) {
    5 I" @* J* |* U& ?# S' _& i9 c
  3.         if(v==1){
    $ a  L7 ^3 L' t. V
  4.             this.counter -= 1
    # W- J% Z( C% ]0 x
  5.             this.$emit('increment',[1])
    ' R) @/ N0 t* M. J- M
  6.         }else{
    # f$ @' a- ?% A( l& l# b  x
  7.             this.counter += 1
    1 o/ M0 Q3 T8 A( ]0 s
  8.             this.$emit('increment',[2])
    % J5 v/ v8 @* Y5 ]! y5 a
  9.         }
      w5 V; m1 m8 H8 V( m: }" @% G
  10.     }
    " s. g5 x4 ~9 D" x  R
  11. }
复制代码

% l2 y& k2 l3 G0 r; m' I% s2 N' A3 y
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 16:30 , Processed in 0.129186 second(s), 22 queries .

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