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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

2 D5 G4 i# C8 J$ Z
  1. <div id="app">7 c) @- e+ a2 V8 J
  2.     <runoob></runoob>: E& f) }' k1 X
  3. </div># o; u( |. x5 L  n
  4. 6 G" L( `+ ]3 d' R5 v
  5. <script>
    . x2 _, R% E7 z9 k1 B+ W" ]0 ?1 {
  6. // 注册
    % _- S. b9 G% A7 i; C, \& ~% h
  7. Vue.component('runoob', {
    9 M1 Q' o( r$ D6 R& ^; |  c
  8.   template: '<h1>自定义组件!</h1>'- W, l  {$ s' o# _' T5 w3 a
  9. })% ]- H0 m" s' D
  10. // 创建根实例
    / i4 }/ A4 p/ B, k( Z4 w2 R
  11. new Vue({; m1 s. J9 {- ~: v, H: D# v
  12.   el: '#app'
    & F* f8 g, [, x) J) W& g
  13. })8 T3 C" d3 n0 z9 I
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

  t6 O" S3 _  h3 s+ y) D
  1. <div id="app">
    ( c- T. v( |8 L2 @* f7 C5 h8 i
  2.     <runoob></runoob>( H- ]* [/ L6 n# f) d' m( U
  3. </div>
    ) I1 l1 }9 ^( C/ o( h# z

  4. - W% x$ G' C. L$ R8 d. k
  5. <script>( R8 ~4 g6 i* b. {
  6. var Child = {
    % e' s( Y9 k) ~" r
  7.   template: '<h1>自定义组件!</h1>'* I1 l  l, S' ?
  8. }& g8 w3 |+ I2 [5 t* A

  9. 4 V# I% j$ j9 a0 Q( q" p/ u" E# \
  10. // 创建根实例
    0 q  ~# N$ f1 R7 `- z5 Z7 q$ G
  11. new Vue({6 v% Z" S6 y* O* S! g. Q4 @
  12.   el: '#app',
    # ]. d% \( f# z, V3 W
  13.   components: {: c* m2 |# K* R, p
  14.     // <runoob> 将只在父模板可用0 a, b3 _3 o3 n' I: F, C! v
  15.     'runoob': Child
    + I0 ?  V3 C8 J8 H* c
  16.   }; X8 I+ g1 @4 j* p; U$ P
  17. })$ ]  r! w9 D- `1 B7 E
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
3 Q  p0 u3 ^* G+ r; L
  1. <div id="app">
    1 F* h% `" {) G4 L+ c% B
  2.     <child message="hello!"></child>, r  J" x$ h/ g# R/ z. C4 z
  3. </div>8 }: Q' b% m* J! r3 F
  4. 6 P% Y) C3 T, Q3 `+ k) N3 G
  5. <script>4 ^' k" O  m& m% R0 M
  6. // 注册
    ! M2 ^8 j! D. p% @
  7. Vue.component('child', {: I1 K% K8 C7 y) q3 O2 _- s
  8.   // 声明 props, C+ C0 b9 O$ ~- j
  9.   props: ['message'],( K  D' Z+ ?/ V
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用& I; l0 \5 M1 ^! P: W
  11.   template: '<span>{{ message }}</span>'0 L' c( d) e% s+ g0 ^- F- @5 v& v5 e* u
  12. })5 S% g/ H" ?! p$ h9 @
  13. // 创建根实例9 c6 U" l: j. A! o
  14. new Vue({, K! T2 A! I: v, [! g( k. z) t0 V
  15.   el: '#app'
    + d/ U* x' g4 T' w2 z* `$ L
  16. })
    8 `( M2 R' V& {5 d: R: s2 S
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
% F/ h6 Q0 Q% f- [
  1. <div id="app">
    ( y7 t( B! P* v2 \* J% W; J& ^
  2.     <div>* ?0 m$ Q, ?/ x/ ]0 D
  3.       <input v-model="parentMsg">( y- b# J, J2 ]# ]4 k8 _- ]  w
  4.       <br>
    * b9 w* ?; c8 g+ E2 W
  5.       <child v-bind:message="parentMsg"></child>
    $ k) N4 T( Q) {0 {2 p
  6.     </div>0 t9 o& {% I" u) N% K
  7. </div>  t/ t: B$ `1 P$ Q

  8. ( O( }& j4 R8 G! Q6 S9 y  p8 |
  9. <script>
    ! q6 E% _+ E0 g: ^7 W
  10. // 注册
    7 ^. B3 O2 {6 e$ ^" O
  11. Vue.component('child', {; P5 ]4 o+ h- o9 [
  12.   // 声明 props/ X0 U; n! |/ @* B' w2 [. w5 p
  13.   props: ['message'],# K2 b$ U  [4 N
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用1 P4 H: O3 @( \( E. [2 W
  15.   template: '<span>{{ message }}</span>'
    0 R4 B% A% Q& e8 u0 `) O
  16. })$ M$ r8 v( k, W  b8 h
  17. // 创建根实例
    4 ]' B( s& |8 l* f. @0 t
  18. new Vue({
    6 Z7 n1 U  P* S
  19.   el: '#app',
    ) R8 [2 @0 B3 e
  20.   data: {0 r- l$ R7 S4 p" t" Z5 p
  21.     parentMsg: '父组件内容'/ ]& r; L' `$ R- Q, j. Q2 e1 i
  22.   }
    & P7 }* i2 Y+ p" N
  23. })- E8 W7 E9 a; q3 X3 ^8 n7 o6 l
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
# u- [- U1 y; O" E5 j( A
  1. <div id="app">
    0 E. I( q) e' S$ V+ }
  2.     <ol>0 ?- M( U' y9 g( Q0 \+ m
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>8 G! V: l& q5 {4 a+ y+ l  k
  4.       </ol>- o6 F( M$ X7 I5 ]+ ~6 Y
  5. </div>! j6 t! v% @) ~2 @; K

  6. / V/ A. O8 D# e; ]# ^
  7. <script>3 u% f- p: j; \/ {" w2 t1 w
  8. Vue.component('todo-item', {% r7 u9 }" {: U6 u% ~1 m: u
  9.   props: ['todo'],
    8 r6 j" O' ?+ {5 A! p
  10.   template: '<li>{{ todo.text }}</li>'
    # o4 [8 A& U; \3 U9 ]6 A5 O2 Z
  11. })# M$ p  y5 \) S/ I$ s% X$ E
  12. new Vue({; \; p3 T, `1 s4 o0 Y
  13.   el: '#app',/ l( o, O* o, F& g6 f% g3 a! D) C
  14.   data: {
    7 g* `3 v7 I; s: |, H7 ^! N, b
  15.     sites: [6 n. x6 i1 z& [6 e# M+ r
  16.       { text: 'Runoob' },* B, i! v7 M* l. y. O1 [3 |$ W8 b
  17.       { text: 'Google' },5 g* y2 d* |8 Z9 l" h, H
  18.       { text: 'Taobao' }
    , o1 U8 ]- o* o: o# X. |  \. r9 ?! J
  19.     ]
    ; m8 o" s' J$ y  Y
  20.   }1 \3 @. X* S1 m
  21. })& f" b: ^3 Z) Q
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    7 H* K8 z* Z: h# q
  2.   props: {
    # {7 W& \& l1 O# g
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)( a  t$ j: o, R
  4.     propA: Number,
    * u/ }) ?! Y1 }2 S* E
  5.     // 多种类型
    & L) _5 n; h: N1 ]3 h' z5 g
  6.     propB: [String, Number],% E7 g! |9 B9 w- @, @3 w
  7.     // 必传且是字符串1 s- L8 ]3 m; Z# e- ~7 Q: S2 _
  8.     propC: {  s' i6 C0 f) {
  9.       type: String,0 f3 i" c' f! o2 T2 h
  10.       required: true
    : r2 U- J) ^, {" ^- B) G8 ]% h% \! p! A
  11.     },% E$ }9 c6 ]0 A- t8 O
  12.     // 数字,有默认值3 j5 t: u) S4 W* F& V6 t* {
  13.     propD: {" @. J$ b: q: W: x4 \" u
  14.       type: Number,
    ; C6 a2 |# ]" z3 A$ `" K: \: Q
  15.       default: 100& d5 O1 f- T) A  Q3 N; `
  16.     },. X) a( I# h9 R; W  W4 f* l
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    2 M/ Y" }; ?2 N3 K& S( x" h- @6 c
  18.     propE: {
    / o9 P' k5 w! |; j4 ^# R: A& t, O
  19.       type: Object,
    1 {9 D1 k2 O0 u4 G& G7 K
  20.       default: function () {) P  t/ k- \% b' ^1 c( {5 u' S) b7 i
  21.         return { message: 'hello' }6 l' {8 l4 d7 ?' d( ~7 L
  22.       }
    ' E4 b4 B' X+ K& e6 S* V" L
  23.     },
    * k! B5 b3 `) C  O
  24.     // 自定义验证函数
    7 u; w4 P' l: m' D, g
  25.     propF: {
    1 e2 u+ ]" t! q4 j9 Q& A+ w3 r
  26.       validator: function (value) {' _+ q2 I; z5 N8 ^
  27.         return value > 10
      d, \+ ?0 G$ N2 Z: g# }; y5 m# v
  28.       }* N! v: e& [2 G" S, J
  29.     }
    9 i2 z. V8 e4 U" K% }4 q& ^
  30.   }! J) X# ]6 l! e& H7 a2 D. ^! |
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    9 R7 \7 f0 @( w1 q! O
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件5 A, ~3 f, W) M5 \
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例- x! K# H9 i, a% M
  1. <div id="app">) [& J; g: Y  Y9 r+ D6 @! d3 F, e
  2.     <div id="counter-event-example">
    2 q# U/ \- C, g7 C% {
  3.       <p>{{ total }}</p>
    8 X% B9 D4 o* j3 q+ F6 R
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    ; V  v9 s* n1 n1 P8 Z
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>, L8 l# [$ O2 f! T( ~% \
  6.     </div>
    6 e" _# B5 q! ~4 q$ e$ [% ^. ]+ A
  7. </div>. z& v8 N# f+ m# p' |( g
  8. : X' U, K' S& O/ m. A# g8 _
  9. <script>
    7 u# {1 D' q3 E' [8 X$ J% M- f; m
  10. Vue.component('button-counter', {
    ; x1 L* J  e) [6 I  F; C
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
      f" b" O' q- y/ |2 [; e+ U# ]+ I
  12.   data: function () {# [! U1 w: x/ M. O, l
  13.     return {
    9 J7 a2 e/ y- z6 f
  14.       counter: 0) m" r1 t& b9 u* J* m2 t# E
  15.     }
    : `+ I6 L+ Y  b8 ^# o$ E: u' c# X
  16.   },
    6 N# p+ ?7 {' g
  17.   methods: {
    ! W3 v2 A; m, a! F! c: |; _8 U' e
  18.     incrementHandler: function () {
    . e9 {; ~; F9 \0 d
  19.       this.counter += 1
    ) b- `: k/ V3 e3 T* w* ^8 v
  20.       this.$emit('increment')
      N9 n3 K* n4 @; Z% q( [
  21.     }+ u) D9 F  V+ r% G2 Z) P0 B# Y
  22.   },
    # p% K) g8 J  J4 m5 s& ]
  23. })
    1 i8 z* _& f/ L; E3 f
  24. new Vue({
    % }. i4 @1 {- y" v5 w2 w! @( Y" V
  25.   el: '#counter-event-example',5 n7 r0 I7 i* F5 L  m" l
  26.   data: {
    . M* Z- a6 x$ ]
  27.     total: 0% e4 V  {6 {" |' j6 c! u
  28.   },
    " N4 N# K+ g1 |
  29.   methods: {
    # |  c3 c5 N; [" M/ g4 h
  30.     incrementTotal: function () {
    : n! N5 s' s% i* M& g
  31.       this.total += 1! B% Y( h2 p9 A; d: P
  32.     }
    4 C5 d3 @" {" S) s* f9 y  X
  33.   }
    5 }+ H4 m( T1 R; Q- B0 x# h
  34. })  p0 L7 [" p; J' T# p) w
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    # F  m1 p# o, a" O$ D; z3 a
  2. Vue.component('child', {0 u9 Z( g  R) R" P- Z. i2 }
  3.   // 声明 props# [- w. a+ R9 L$ B  u
  4.   props: ['message'],' P# N* L5 l( V6 O+ T
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用0 z) W% h$ Z& T% a, }
  6.   template: '<span>{{ message }}</span>'2 A8 x! l" U' Z; K" f
  7. }); S& H5 k1 V- ]7 N+ ], K9 J  C; ^1 r
  8. // 创建根实例
    8 e0 N6 k/ t( W
  9. new Vue({
    ) `$ |8 R: T4 c8 }7 D) A
  10.   el: '#app',& c8 C  Q* Q" ?2 g) g% c1 o% |
  11.   data:{
    3 G: u& C: d+ K3 E/ C
  12.     message:"hello",
      k% @5 y2 t4 P: m: ~
  13.   }
    / {8 D- ]$ `5 a( c4 z
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    * `& m) u4 @, I/ T# J; b9 J1 X# ^3 [
  2.     incrementHandler: function (v) {( ^' J1 ^/ A  C* g- J
  3.         if(v==1){
    ) }# Q. N: e$ [$ d2 z* i
  4.             this.counter -= 1
    , Q" W4 u  f: G/ v( \
  5.             this.$emit('increment',[1])
    / g3 l9 r4 Z+ P0 F- v
  6.         }else{
    - H7 Q8 P; I" x' i0 o
  7.             this.counter += 1
    / k2 [* q  ]( o) p$ \* d- y
  8.             this.$emit('increment',[2])6 e: t/ I; k. D9 p0 l' m9 u& ]
  9.         }
    # j2 A$ ~5 d, U& B7 \, j8 G
  10.     }
    3 d( V; @7 c, j) `
  11. }
复制代码

1 \+ G6 R' ^" k" Z5 f7 T- ]9 V$ X  B* r# h# y
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-7 02:20 , Processed in 0.151710 second(s), 22 queries .

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