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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

& l; G7 t2 k, ~5 u% c5 K
  1. <div id="app">, c$ F; W7 M* g0 a7 \1 K0 h
  2.     <runoob></runoob>, [0 B  E0 m( E* e
  3. </div>1 B) l/ F. h  j: D
  4. / t% H1 o, B+ M" T) O& g& d3 a# y
  5. <script>
    ' m0 I3 P& X/ M! j6 D5 ]7 ?
  6. // 注册
    3 Q: P$ n$ ?/ }, p5 h3 l$ P- t& I; a. s
  7. Vue.component('runoob', {
    ' q& z8 @' a8 Q1 G! }
  8.   template: '<h1>自定义组件!</h1>'
    ; L; ~  B. k6 O! y
  9. })
      _- y7 s: W, `0 o( Z" T) M7 z. G
  10. // 创建根实例$ e4 ]* ^4 n9 X! E. D
  11. new Vue({
    # F$ `0 O" D0 f
  12.   el: '#app'& `; T5 j* e$ L8 R0 D" e' n
  13. })  [9 h+ `$ K$ P. A
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
! e; B7 }/ S$ @7 g. v/ C! r9 S
  1. <div id="app">
    ( E3 I% S  i; X: A7 ^( R' X  z( [
  2.     <runoob></runoob>
    , F# P0 A0 b) T0 l5 [$ c/ X
  3. </div>, o3 \7 r% s  Y! P' T% d4 \* a

  4. ; J: n+ v# x, ?
  5. <script>7 i. Y3 i! U& c; O
  6. var Child = {% l. q/ _* m! U9 B
  7.   template: '<h1>自定义组件!</h1>'$ R( @- e$ R  p
  8. }
    7 ]# f7 s* W( \$ ~; r

  9. 5 u# @% u8 q) m9 Q& w* B$ o
  10. // 创建根实例4 s1 s. a- K7 `  f* m6 x" A
  11. new Vue({  N- w$ _: C* |9 i% [
  12.   el: '#app',/ z2 v( S. R/ M2 b' R$ M6 `
  13.   components: {4 A% o6 W  H" f# S6 o8 e+ G9 L
  14.     // <runoob> 将只在父模板可用" R4 k! F/ j% I6 [& ^' a2 d0 S5 h
  15.     'runoob': Child5 }: ]+ [6 s5 w
  16.   }  r) x! F7 x( ~- q9 q
  17. })
    * D2 I8 y: m7 p$ L( ~  o8 n6 I
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
& J: f( C0 l3 o2 X, n$ J
  1. <div id="app">
    % f% k$ {* |4 E$ q# b, A& d( X0 `' e
  2.     <child message="hello!"></child>
    6 f. M, D2 Q4 u8 ~4 o
  3. </div>/ D# z* J  s+ `% w; R) b4 m

  4. , h# ?5 r$ i5 Z' M
  5. <script>
    / R2 W  j( {& y" J- e* N
  6. // 注册: a/ V3 M7 \" J8 w
  7. Vue.component('child', {
    5 ?9 [# s8 b% m: a+ M; _" S$ h" ^
  8.   // 声明 props+ E2 j2 B  m/ s9 @8 _
  9.   props: ['message'],
    8 p" Y% b) n9 \! X. y- w
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    / K& [% I9 m) X' S
  11.   template: '<span>{{ message }}</span>'7 a- o; n8 J. j- c" Q* I
  12. })4 S9 N! H# G' B; p
  13. // 创建根实例6 f' h+ C7 ?( m+ {: y
  14. new Vue({
    6 H& u& L! r5 p. w, O4 ?
  15.   el: '#app'
      I6 B! h6 v" P, L
  16. })
    . e/ w# x, [3 V0 E
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
0 K0 F5 c) a* {7 G
  1. <div id="app">
    3 H9 \$ e$ _( r" o: I( \% R
  2.     <div>* o2 G; L% c% o4 f- X
  3.       <input v-model="parentMsg">
    / x. [4 j8 r" M0 h% B
  4.       <br>
    % ^: a( Q  N' L: I2 e$ Y1 S
  5.       <child v-bind:message="parentMsg"></child>8 r! o" c+ q# ~$ Y; L1 O
  6.     </div>
    3 z6 |$ e1 u4 O
  7. </div>
    2 ^# {! ^- C: l7 ]4 A( X6 L1 K

  8. 9 ]4 b8 O8 c4 R& H5 K" O, V* L0 [
  9. <script>
    3 R* q' E, @& c) j% @8 \; p7 m3 f
  10. // 注册4 E. o' ^# g0 d# ]1 W- |# S/ D
  11. Vue.component('child', {
    1 _1 Y; R  w: \  u, B, f% Z
  12.   // 声明 props5 X! D. ]7 H$ ^! a- v/ a1 `0 U3 W
  13.   props: ['message']," P7 s% o6 `! ?5 Y4 i9 M& q5 E( [$ c
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    & K; R5 d- V4 K7 b# o+ y
  15.   template: '<span>{{ message }}</span>'  {8 F! N1 Q" B: \
  16. }): u/ T, [+ b( R% K5 [
  17. // 创建根实例
    ; q, b0 f0 z/ t/ b
  18. new Vue({
      i1 t* b3 s) m3 [
  19.   el: '#app',
    + L' R# d$ K/ U/ K$ \0 Z
  20.   data: {
    ' ^2 x# V2 v# m' Q) [
  21.     parentMsg: '父组件内容'
    2 p9 |" j! v* U: T* v; T7 `
  22.   }5 K5 N- Z- S, h: N4 L- Q
  23. })7 U! ~! ~+ @) E
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例# ]9 [4 i. c- g
  1. <div id="app">$ v+ `7 \# g4 u3 y! y' q
  2.     <ol>
    " a4 N  D9 N3 I7 h- C2 q; Z8 I) H4 d
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    8 j4 v) i1 c! ?1 x1 _" U. _
  4.       </ol>
    + \3 Z' x5 T0 A7 N" f$ v9 t' G
  5. </div>3 q' J* [( O0 X& K- g0 n" @$ i

  6. 0 z( S9 M% ~- l2 _
  7. <script>3 l6 |! H( N* d$ q
  8. Vue.component('todo-item', {" [4 b% X9 g5 Z4 B! K" t4 f
  9.   props: ['todo'],1 f+ S) k% E! Q* _" g  _
  10.   template: '<li>{{ todo.text }}</li>'
    " T% h0 s! j8 C+ j" C+ z
  11. })
    3 `/ K5 ~4 l* \4 J% W  R- G2 h3 J  i
  12. new Vue({
    * E: a9 _$ j# d7 Y; ~: F; o
  13.   el: '#app',- }, U# u" [4 c! l- ^/ i. D+ b: b& ]; S
  14.   data: {
    ; H/ M( [( T6 q- H3 p# u3 z# A* @9 h
  15.     sites: [
    % t6 |* B) @4 u+ R% [
  16.       { text: 'Runoob' },
    * b5 {2 ?3 Q/ _, J
  17.       { text: 'Google' },
    ; k1 h- T8 A: u
  18.       { text: 'Taobao' }
    ( P) h* z% M3 K% a" l! J6 M
  19.     ]8 D# e2 O2 d0 k5 m
  20.   }
    3 c$ [  ]% F! M) S3 l% [8 K
  21. })9 a6 u+ U% y/ ?1 b* ~( @/ t! Y
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    1 @: }, F" r$ ~( e
  2.   props: {2 M, u9 |! n9 F% a0 h
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)7 x0 I- P* Q! }8 i5 w* ~
  4.     propA: Number,
    / B) I4 ]. B' e7 _4 P
  5.     // 多种类型
    . p$ {7 G- g0 }. d
  6.     propB: [String, Number],
    * k$ ]+ X# q+ F+ i/ |4 Q
  7.     // 必传且是字符串& k+ r& S* |* j1 I
  8.     propC: {& E( m( E+ ^5 D/ Q: }* f6 }
  9.       type: String,
    6 R. \) O. d3 o; n) b
  10.       required: true# t5 o& O$ |/ V+ \# [3 s
  11.     },
      @& j  L# o9 f- I
  12.     // 数字,有默认值. }8 p8 l: a. c
  13.     propD: {/ ]& U- q7 y6 P8 _
  14.       type: Number,
    ) W- U% n; m' e* ~) c- l
  15.       default: 100$ }8 r1 ~" {  k; {
  16.     },/ Z6 B3 O+ @8 a, P, A+ }* M4 N9 F
  17.     // 数组/对象的默认值应当由一个工厂函数返回- y$ `( i  Q" p! a" t
  18.     propE: {3 ~4 H  N- x: q$ D' M2 d
  19.       type: Object,
    , K0 q0 n, m% ?( T6 t8 q& @! l9 Z8 l
  20.       default: function () {1 v2 c# s3 d$ Z4 \% G4 M4 T
  21.         return { message: 'hello' }- p$ t. A- l6 T% [4 J4 f
  22.       }" X/ }' |8 a! N' F+ i, R  L' s. f2 M
  23.     },
      V0 u% n8 g! S' V% w' B. \' R# R
  24.     // 自定义验证函数
    1 f  r5 W& L6 K( u* Z, _& r: d
  25.     propF: {) }& v7 A4 s0 v1 J
  26.       validator: function (value) {
    ) E( \: O6 Z1 U2 Y; i! o
  27.         return value > 10' J) y  G. l& ~! P7 T" A
  28.       }
    0 C! Q  u; Z& Q/ ?+ R2 d
  29.     }
    % w8 k5 ]: L7 o1 j- K! X
  30.   }9 s& F0 E+ t7 q  g
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array4 o; h4 ?+ r# C& h/ a' S+ l9 `
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件) J% K7 B& z1 ~$ ?
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
" |9 G8 K' w" ]5 @- \& O
  1. <div id="app">
    - v* C7 s4 J- ~" A+ E' ?& Z! ^
  2.     <div id="counter-event-example">% M( e, A7 D% n9 N5 M4 Q1 |
  3.       <p>{{ total }}</p>) U. @7 z. V0 k
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    & I& v. Q- G, ]! [
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>+ C5 B6 {" g! @% V
  6.     </div>: b% T. _) k, S+ c$ m! t  V
  7. </div>1 Q/ S! y/ G, ]: [9 Z( J, L6 e4 v& o
  8. - R+ z0 z$ F7 ?  E. H
  9. <script>
    3 H& I+ {4 W, Z- ~3 ^3 l
  10. Vue.component('button-counter', {
    9 R5 O% V2 z6 y- G2 b! s5 o' Q. u$ A
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    3 Q5 v- m) f1 K! t0 ], Z
  12.   data: function () {
    & e' ?% Y( c7 k. u5 D$ b5 v
  13.     return {
    ! ~4 I3 ~9 m( P' d
  14.       counter: 08 l. I5 G6 [& I6 h
  15.     }
    1 A5 y  h0 h' k2 _
  16.   },
    " d8 H# P: b8 j5 w2 V: R
  17.   methods: {
    - p8 r/ w: d3 @# k
  18.     incrementHandler: function () {6 `  w# F9 C% k4 z' q
  19.       this.counter += 12 q; H5 D  B7 H$ ?9 V
  20.       this.$emit('increment'), Z) Z0 B7 ?, z' m
  21.     }0 {2 C9 a  e6 J5 s
  22.   },
    & k! p$ q: x5 g. e; F& M- h
  23. })
    4 L" R; y% i9 H
  24. new Vue({! ]+ W+ X( a, o; _* H0 A; y. Q
  25.   el: '#counter-event-example',
    7 O/ i+ Z5 i( u2 G  m- X( t9 w
  26.   data: {
    ) D6 r( z4 a+ L+ }
  27.     total: 01 @- u9 H1 N( d
  28.   },
    0 |; d% [! t4 X! @* P
  29.   methods: {( I& F2 J( w0 V2 y' w+ p* {4 P
  30.     incrementTotal: function () {+ R7 v6 y. T  P
  31.       this.total += 1
    5 d3 ^& I% E6 p5 [
  32.     }
    , v  G- c' a% C' ?( |( H. K+ L
  33.   }
    ) {1 b, S: X, @6 r3 _" ^" ^
  34. }); n+ [3 L' s  E, j
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册* Q: L  D$ q# ?  O( [0 F' J' A( l0 G
  2. Vue.component('child', {# P- d  m/ P  @
  3.   // 声明 props
    + p8 T8 o6 t- k* H5 Y# h: J; [# S; A
  4.   props: ['message'],
    1 d1 j1 A! ~% F! h. @. ~
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    % [$ C$ d" c9 c( |* L
  6.   template: '<span>{{ message }}</span>'
    # p$ [. ?& U3 ?* E
  7. })% p, `8 n. M7 c; ]: G) m1 |
  8. // 创建根实例
    ) b# l* Z' _! M
  9. new Vue({7 z, T% P1 d) [5 ]. U
  10.   el: '#app',
    ; s9 f) T: G3 g6 l) `: a
  11.   data:{8 g) o( }4 g3 I9 X2 @7 E, @6 T; O
  12.     message:"hello",
    ! N. w7 d* B; U# {' B
  13.   }1 G! l0 [; z: K" \; y% ?
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {( E6 d1 T, h7 E5 i+ x
  2.     incrementHandler: function (v) {& K' C; m% {& C# [. S0 ?
  3.         if(v==1){( |5 U2 ~5 X  e- f2 i
  4.             this.counter -= 1
    : a( t, L' T1 ]9 K1 X: b  J% C
  5.             this.$emit('increment',[1])
    4 S1 Z! K* d2 \9 J; Q$ n7 m: M
  6.         }else{
    & {, r1 [( O+ F- ^- q( M$ X8 V* Z% ^
  7.             this.counter += 1
    8 ^( _! H5 ^7 `# A
  8.             this.$emit('increment',[2])
    1 [% t8 @; Y$ m& s, |: I
  9.         }
    4 \- Y* V8 N* E# ]9 N
  10.     }% H2 L2 I. h5 z* Y/ E! O0 K9 J
  11. }
复制代码

  ?, R0 r4 x1 L4 S6 Z0 s# t
5 A8 Q! H( c7 U- j) v$ G
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 21:34 , Processed in 0.146541 second(s), 23 queries .

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