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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15216|回复: 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,并使用它:
0 Z7 H! N" h5 I6 \4 S3 }+ a: H
  1. <div id="app">0 g5 q( G( m$ [( g
  2.     <runoob></runoob>/ {: c* }. F8 S5 k- K# p- s& K1 C
  3. </div>. D7 n' ?5 @4 K5 r! l

  4. ' W" t  D/ }* K$ k( F: N9 I6 Q
  5. <script>8 z" ^7 E. c) s) f
  6. // 注册) `! }6 E' `, F! w! x# v' j4 D6 ^
  7. Vue.component('runoob', {# \# Q) ~, t6 O
  8.   template: '<h1>自定义组件!</h1>'
    * b  [* q- f8 [; A- S8 ~
  9. })
      \4 \8 E; ~' y5 c5 e8 a
  10. // 创建根实例7 W: V5 N* m5 z8 A5 B* s; ~1 I5 J6 w
  11. new Vue({
    0 \: r# v2 m' B3 D" m5 v3 l. e* G: Q
  12.   el: '#app'
    : x3 Y$ M, w6 Q0 h7 D, a
  13. })
    1 A! r- }0 J, y8 {8 _
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

2 ?; J) D8 L( N
  1. <div id="app">5 E3 J! }9 O3 w4 A' y( u
  2.     <runoob></runoob>3 A: u9 n, P- Q, [0 x2 o* g
  3. </div>
    : k2 g+ H* ?- O! j3 E' h- n* `
  4. 0 p8 H7 v) ^7 x% Q
  5. <script>
    9 t6 I1 |6 [& l& D" }5 U
  6. var Child = {
    ) y+ g( P2 N4 y! u4 @
  7.   template: '<h1>自定义组件!</h1>': u: K3 N) e( @4 X- x3 B' _% R
  8. }* {& J$ R0 O0 H4 w: |4 I- m. F
  9. 3 `1 z' R2 _: }4 r6 ~: _# m$ ?
  10. // 创建根实例: l+ _! A) P- c
  11. new Vue({
    , y) B! G' h$ m+ B  s5 Q5 E
  12.   el: '#app'," }1 H5 c+ R: m1 u) n) F
  13.   components: {
    $ |" l; ]3 K0 X( `, w: M
  14.     // <runoob> 将只在父模板可用) e4 }5 U  t- L$ ~( U5 v. A; Q
  15.     'runoob': Child
    ' B2 K) r+ A0 |( I9 d
  16.   }
    # k! W/ U: Z  l6 ~/ L
  17. })
    $ d9 T+ F( A, r' G" N7 U
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
/ H5 ]) y1 Z$ b- k! W; a
  1. <div id="app">
    8 c* i$ j. H% J, A  I. }
  2.     <child message="hello!"></child>0 P" g& C1 d7 j9 e+ {
  3. </div>
      d8 f. J  }! c5 I& N
  4. , u5 n: t. f: N. f7 N6 R
  5. <script>( h" B1 i- v0 N' x* g  k
  6. // 注册
      w: a# B0 c$ G0 O3 }( {
  7. Vue.component('child', {) B1 \2 l! A2 `
  8.   // 声明 props
    & g) I/ z6 m9 t7 S' G! r# `
  9.   props: ['message'],. g% X, E3 }) V4 [1 a! g: m; e
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用6 T7 S2 X: E4 T/ n) l3 ]$ ^: s
  11.   template: '<span>{{ message }}</span>'
    1 W- S- E! {( c% r6 v# y$ |
  12. })
    # X1 W" i0 J0 c6 t
  13. // 创建根实例: u5 V0 R. p7 _* w
  14. new Vue({
    % M0 l. a& J; R" C% t
  15.   el: '#app', I/ A9 u2 J' \$ W
  16. })
    7 G+ N$ S9 P+ }* W$ O4 p
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例2 v2 y6 w* M: {0 E' p4 d
  1. <div id="app">. t  M" \" H/ D1 l: l6 D! g* v, ^
  2.     <div>
    - m! }0 M, Q/ n; C- I4 j
  3.       <input v-model="parentMsg">
    + f5 u" h9 H$ F$ e  \
  4.       <br>, O6 j3 q* A& {% P$ U- q. Z
  5.       <child v-bind:message="parentMsg"></child>) k- [) d  x6 T3 A$ l% M. t( T
  6.     </div>$ P4 B1 F; Q7 V$ E  w$ f
  7. </div>
    1 |( A+ r& ~$ z8 Y5 @

  8. $ Z! }. \- d% Q8 v( u# {4 ?
  9. <script>
    + b# N+ {6 I% a& K, p% V
  10. // 注册
    5 n$ ^8 v4 w( y. b/ q7 n* L
  11. Vue.component('child', {
    1 l' J9 Z7 y$ w& X
  12.   // 声明 props
    : y) W+ T9 d$ G3 Z& P9 ?, C
  13.   props: ['message'],7 @( A2 b( z$ }/ u3 D* U: Y
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用6 D5 B8 V3 [5 z
  15.   template: '<span>{{ message }}</span>'  ~& q$ C; e) u6 h, Y# L6 E
  16. })3 c! ^! U) O( N3 a& m, ^
  17. // 创建根实例* W4 N$ b! w2 u0 V( t1 l
  18. new Vue({
    ( g$ p2 v6 e. V9 l
  19.   el: '#app',
    ; Q) O2 F" I, Q; o
  20.   data: {
      g0 p; P+ p" ], n) a9 b& q
  21.     parentMsg: '父组件内容'
    7 k. M2 [' {% @; ?1 s
  22.   }
    * R- M2 E5 Z2 S9 i8 D. a! f
  23. }): b8 {; u/ s1 `. F
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
6 ^7 i! A/ r& g2 _, [1 ?# F
  1. <div id="app"># L. w/ e" a  k7 X! o4 K' g! e
  2.     <ol>( C- p* d* ]7 Q. T2 w1 @2 [
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    2 Q0 I' N4 E# ~% k" G
  4.       </ol>4 v2 \9 E* S! h3 Y* p' ~8 \
  5. </div>
    / x( t# o: M/ Y3 b( A% x
  6. 8 c- c/ _5 n& c/ A
  7. <script>
    # ~% T* b, I& R  `# M6 o9 {  s, W$ y
  8. Vue.component('todo-item', {
    - j' s0 T; ~* P( P
  9.   props: ['todo'],
    4 U, q( d, ^  i/ }
  10.   template: '<li>{{ todo.text }}</li>'
    * O+ I% q% K: ]* d; P( H8 B: Y
  11. })( v0 G. i+ x- \5 U$ H
  12. new Vue({4 U2 F4 t9 f3 A3 B& o
  13.   el: '#app',6 F% r- `9 W0 R: x) K
  14.   data: {
    % s: g8 j$ x" y3 v' C
  15.     sites: [# T3 g6 a9 G$ V, u
  16.       { text: 'Runoob' },* T7 r9 P- i0 y9 I, I
  17.       { text: 'Google' },- Q0 _! X& D9 g. _* F
  18.       { text: 'Taobao' }( o; M7 z& C$ n2 G& G
  19.     ]
    - }# G" _; l  \& o
  20.   }
    ( t: ~& w9 P  I' c  _; t
  21. }); |% M; k' t" `: q! Q3 n
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    3 i" k$ g0 u1 m
  2.   props: {
    + y& g0 A+ `, J* s
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    7 S1 V) ]& e3 D5 W; V
  4.     propA: Number,
    3 K  n9 A$ Q8 U0 D
  5.     // 多种类型' T) g1 B. u7 [+ ]
  6.     propB: [String, Number],
    % S2 G5 o4 e9 @; A& F$ |% a  k
  7.     // 必传且是字符串
    & I/ x" d! }% U/ O
  8.     propC: {, z) _+ e) |1 O+ s: H7 M
  9.       type: String,
    , {: C9 f" {! {2 r
  10.       required: true& g8 ~7 |8 w0 A, q
  11.     },' v/ Q- c. k/ @( f! J2 Q
  12.     // 数字,有默认值
    1 y* |  L0 {  q2 _5 Z
  13.     propD: {
    9 l& b3 Y2 I$ M2 \6 w
  14.       type: Number,
    - ]+ o8 `3 H! y, c
  15.       default: 100( I9 }2 T- Z% o
  16.     },
    - I" `1 h. y: E3 G$ d9 A- p( t" U
  17.     // 数组/对象的默认值应当由一个工厂函数返回2 r7 F5 e& n! _4 i8 ]! }
  18.     propE: {; T/ Q. k7 t% B; F$ k. {0 j$ g
  19.       type: Object,
    2 G4 I2 t; @" `) X9 G+ Q& L& l% Q2 I
  20.       default: function () {
    2 K" S* ?+ t1 G4 }. g6 R* v( {* w1 I
  21.         return { message: 'hello' }( w- E( w* h( c) z1 v) k( t
  22.       }
    4 [! H: Y# X4 p9 J  z
  23.     },
    6 U5 I# P4 j* j! H) N1 q
  24.     // 自定义验证函数' A2 V$ N9 b( H( p
  25.     propF: {4 D9 y) Y4 ]3 F7 U4 m9 Y
  26.       validator: function (value) {
    & A0 A+ L$ o1 D* |( P( r, Q' e0 E
  27.         return value > 106 W) p: z9 V7 @2 l% `
  28.       }
    4 c' c* _5 j  i
  29.     }
    7 U: g( u0 j9 j3 A! M& H* h
  30.   }
    9 @1 L& J+ Y3 \; E5 p
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    ; h9 h, A  T: P& ~
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件) O, x6 p! g+ X6 e# H
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
; e$ q. [; i" R# S
  1. <div id="app">$ a" m1 v% Q1 i% E! T
  2.     <div id="counter-event-example">
    8 Q% c- U  K! s, a% H0 |- ^
  3.       <p>{{ total }}</p>( U& F1 t: S5 L9 ?; V1 r1 [5 O
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>  u% F' O! O3 N& Y8 \
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>% T& x4 |' \: l; g; D+ e$ u: R
  6.     </div>
    1 `9 m3 D% F8 a& @3 G% W+ I
  7. </div>
    : `8 R2 k/ k6 j5 o% N' e* x

  8. 3 |! e  J. Q; K* h" s4 Y4 H
  9. <script>
    ( b, p& o; l" G2 F: j
  10. Vue.component('button-counter', {
    # }7 v& I' q) w  a: p( ~
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',7 q( w! u8 M& r  u5 w( _6 l8 x
  12.   data: function () {6 p0 e# i: |+ i) V/ m7 ^9 m$ f4 r
  13.     return {! C9 N& ?9 o  }8 q3 l" Z
  14.       counter: 04 n0 M! a* L1 ^& V3 W# T$ r/ R" t2 A
  15.     }- n- p# Y+ _- ?. ~3 i, ]4 k. W
  16.   },
    " K- m. u! l; ~
  17.   methods: {7 M# X& X3 t5 T, ?0 O% O, d
  18.     incrementHandler: function () {
    * c! A* N. U% w
  19.       this.counter += 1: I& O" j- X/ L" U" ~2 W0 Q
  20.       this.$emit('increment')
    6 @9 c- w( M: j, L1 D
  21.     }
    ! K& s3 I6 ~3 B6 Q
  22.   },4 O5 U/ x( ^5 N  K; Z; }
  23. })
    9 K% W# f/ m: }: i3 Y" |1 `
  24. new Vue({$ P- O+ l+ y5 [+ j5 h$ u' V
  25.   el: '#counter-event-example',
    # n* k5 z5 W3 u+ F. o' N. X
  26.   data: {
    ( M6 S* W& ]8 Z7 F2 J' Q
  27.     total: 0
    . x  ~  c( P  }, @: V
  28.   },
    # L+ J* x" }7 j. ^/ j* O" q  K2 L
  29.   methods: {
    % ]; b( D* c. K. Q
  30.     incrementTotal: function () {
    % U. D. j- ]' c0 H0 |
  31.       this.total += 1
    0 K  C: G# g. k8 p. U! \
  32.     }3 T% p2 N; n# ]0 M) k1 k0 N
  33.   }
    7 _7 t) b' x  ~4 u2 m$ p: @/ ?
  34. })- d- r# H. p3 V9 H$ z
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册" S) @) T0 w0 R7 \) D* _" t
  2. Vue.component('child', {! s8 Z5 a9 u% v+ y' o# E
  3.   // 声明 props* M) T2 p6 j7 S( m! j, Q
  4.   props: ['message'],
    ; Y, \# y+ j% S: u
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    2 I, [" N5 ?; ^. [1 ]' h5 o. g
  6.   template: '<span>{{ message }}</span>'
    . e' J. F8 _, y/ T
  7. })
    ) U1 g' ?* F/ u6 B
  8. // 创建根实例2 H+ i# F8 J$ }$ K" J0 Q5 }4 K
  9. new Vue({
    $ A2 R, w$ V3 l
  10.   el: '#app',! m8 U7 R. w9 P9 |# ^$ |+ X
  11.   data:{
    ' e8 k5 L4 T- r; j$ t
  12.     message:"hello",
    ) f; Z& k! ^& R1 f" g/ y& |" m
  13.   }/ |+ D# m% y/ ^" a2 ^
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    - W- v' {' @6 n4 v  S
  2.     incrementHandler: function (v) {7 Y1 Y0 V* X  v5 a' E; [; o  T% ~
  3.         if(v==1){
    2 ]: \9 h9 D& f$ `6 {
  4.             this.counter -= 1( ^  x$ W' x( f- H1 I
  5.             this.$emit('increment',[1]); g0 C0 M' U4 E4 @
  6.         }else{4 d( C, S! Y9 l) q- I
  7.             this.counter += 18 H; R2 K/ X% ]) r. b
  8.             this.$emit('increment',[2])
    9 Z2 {% |6 B5 ^- B- `9 U# c
  9.         }
    1 l) e1 W3 I4 _$ n9 W5 V6 A7 l/ `
  10.     }5 J6 ]& w: o% I- z) [
  11. }
复制代码
! p6 `6 `; \) y& X5 P
) z0 g1 w3 z/ W  e: Q( V( O
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 17:26 , Processed in 0.056935 second(s), 22 queries .

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