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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

' h: a& A/ \  m8 C2 _
  1. <div id="app">; A- K6 R5 l! b5 i& R
  2.     <runoob></runoob>
    3 s2 O9 I* Y8 s3 k9 n) H. s8 Q& }
  3. </div>
    % L8 R, _0 ~: E! G! x2 X

  4.   ?* g9 l  r$ g6 x) l2 S$ L
  5. <script>4 X; S( M; N0 P) @3 j/ K& I1 _6 }
  6. // 注册
    , A& u8 e3 [' K' x' o4 U
  7. Vue.component('runoob', {5 G+ e4 u" X5 Z4 N* J8 o
  8.   template: '<h1>自定义组件!</h1>'
    * o# V8 z3 c& C3 X
  9. })
    $ ~% ~% a! b# V/ R
  10. // 创建根实例  K3 @. B* A" r
  11. new Vue({
    % y0 S+ f  w/ t1 Q2 z- e, L2 C
  12.   el: '#app'- u1 k6 @7 o& @3 ^4 g
  13. })
    2 Z. @  m* m" g& F+ k+ K5 ~
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

# X+ K6 U: o+ A% t; e
  1. <div id="app">
    8 M1 l# I; o4 Z+ Z
  2.     <runoob></runoob>
    9 V" H; t7 ^2 J0 Y( o
  3. </div>  Z, ~$ Q: e7 e; A* K2 T. J9 ]

  4. 4 I3 n2 h" ^7 D9 l( D  @* n8 o
  5. <script>; Q2 J/ W6 [5 m* {. x2 B
  6. var Child = {3 W0 T) A2 w$ a% p
  7.   template: '<h1>自定义组件!</h1>'# l+ B- J- ~2 H  J8 V
  8. }7 _" z) q& G" F3 I- I* D

  9. ! u* w( P$ H5 V$ ]$ Y+ i  m
  10. // 创建根实例
    ( @" R+ m5 X/ ~2 p( h
  11. new Vue({7 v2 F" z& j  X7 b8 D* n# s& h8 e
  12.   el: '#app',. \! a$ Q* o# v3 ^
  13.   components: {: y' j, A, R* a5 B9 u$ Y- P' q
  14.     // <runoob> 将只在父模板可用
    $ M9 P/ P9 e; I' J' W
  15.     'runoob': Child
    * D, f3 R# w* e
  16.   }! ^+ Z. v2 i5 T6 q# w( V" o
  17. })4 c6 m. S7 H! \) x/ x4 j/ f' l
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
/ M* \5 m) T6 W3 Z5 N
  1. <div id="app">4 w8 z% x& F% b: x# E* K/ K" W
  2.     <child message="hello!"></child>
      D  ]# h8 |  ?& }8 W4 U/ v
  3. </div>
    , f9 t$ s! m. |1 x' [, d6 O" @

  4. ! i! T: F/ T# j  S5 w$ I6 e3 b
  5. <script>2 k. }( F4 k: ~. Y% {4 Z
  6. // 注册( r* O( z4 @( k+ [
  7. Vue.component('child', {
    $ y- V) x3 h! I, ~9 \4 @$ M; Y6 ]: W3 e: Q
  8.   // 声明 props! C& U6 Y7 X. e/ F& X" [
  9.   props: ['message'],
    / }2 C/ B5 u$ h4 N' g2 ~( ~1 d
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用* l7 v/ q8 I9 d& |7 h! ^
  11.   template: '<span>{{ message }}</span>'
    ; ?) [! B5 V1 h0 ~# j/ E
  12. })
    0 ^0 |( X, z* S5 m+ X9 K5 F
  13. // 创建根实例
    ) o$ C* W' C: l/ f4 @# a7 {' t
  14. new Vue({
    ! J1 q1 N' ]- a8 Y$ p3 W; N
  15.   el: '#app': m# _% K6 |6 `0 o  s
  16. })' w+ \" w0 c7 h' j2 f3 a
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
# Z2 J% Z. B$ g" k  g
  1. <div id="app">
    # r! I/ D) A) N7 A5 g5 H
  2.     <div>1 w2 ]2 H: `2 j: M/ g
  3.       <input v-model="parentMsg">
    / Q' ^! _, H; R/ B4 f3 D
  4.       <br>
    & d5 V0 `! B  A
  5.       <child v-bind:message="parentMsg"></child>9 d8 k3 x8 A6 t/ i) P
  6.     </div>/ Q( d; ^9 v* H3 g1 X, L
  7. </div>
    3 R7 B# v; [7 r  N$ x: o) U0 g4 V
  8. . C  C$ p6 D+ y4 G; T$ ]" b* {
  9. <script>
    * G4 _8 ]0 [2 _7 H9 v
  10. // 注册0 `7 l( k  S3 k4 O
  11. Vue.component('child', {6 J0 y8 }3 H( p- a# C  \; u
  12.   // 声明 props/ K1 ~% x* y* l: s$ a5 O! c
  13.   props: ['message'],
    1 j; H, [3 S' r0 t0 X5 z
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用* y- p2 f2 }( {5 f% l' p
  15.   template: '<span>{{ message }}</span>'
    6 b. d& U+ y5 |" G8 t1 H) f: ^
  16. }), y4 f5 s7 j3 ?' w
  17. // 创建根实例
    " u! x: M! F6 ~  n, K7 b
  18. new Vue({
    - @4 q8 p' V1 ]& Z" |3 ~: a
  19.   el: '#app',
    ( P) P' t; g4 I  ^
  20.   data: {
    & O, C1 C) C0 \. L  }
  21.     parentMsg: '父组件内容'3 d% v; X6 Q% [8 q
  22.   }4 q% N0 w, i' J. ?2 C2 T
  23. })
    : r: ?% m) n- U5 ^) B
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例. U( q' |# X  @' o9 u/ S
  1. <div id="app">
    " q3 d  T/ W3 j6 Q0 T5 a6 m
  2.     <ol>" z0 V4 U( K% T6 L* \
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    7 C& w) U& S3 m
  4.       </ol>
    $ m9 V+ `  B, l6 n+ n9 Y  d
  5. </div>" x/ c% `' v- E) I: f6 }
  6. ' R2 O6 w; g6 W# k1 w' d
  7. <script>8 Q7 O5 M1 |7 i3 B* U' G: d7 a, S
  8. Vue.component('todo-item', {
    5 U4 `  d( j  @. ~
  9.   props: ['todo'],
    8 T4 p4 ]& c0 p" R* u' }
  10.   template: '<li>{{ todo.text }}</li>'3 ?9 ?. I, b! E' i. e
  11. })
    ! u# `2 _) T+ N$ ^# @
  12. new Vue({# X; U* D3 C7 D* \: ~: ]
  13.   el: '#app',
    # p+ a9 o! m/ Z3 {! J9 K' E
  14.   data: {
    ( Q/ _# J* J7 a/ J
  15.     sites: [. o, @. H) N0 ^
  16.       { text: 'Runoob' },& y1 e1 E, F9 z! u5 @0 I# O5 w
  17.       { text: 'Google' },
    0 C! L" F9 P2 _$ l) P' Y8 R
  18.       { text: 'Taobao' }
    5 N: L' W( H# J; W; V/ [5 R- r
  19.     ]
    & B% e2 ~# s, ~' S
  20.   }. a  A4 T0 O8 p* \" i) ~* J2 Z
  21. })
    8 ~  w/ V& b0 L2 x" n9 ]0 o
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {8 I$ ^( Z( r' F: t  g/ s3 m
  2.   props: {  E0 S+ [9 q% b' _
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)! Y( E! ]+ g9 Z* \  L) }
  4.     propA: Number,# I& k& W# `+ _) \* d6 P5 e* p
  5.     // 多种类型
    8 p- e& U2 L  V
  6.     propB: [String, Number],
    , k# [$ ^  b4 M4 f' C: s3 O
  7.     // 必传且是字符串+ i  @- `# a' \7 i
  8.     propC: {( \0 a0 w6 k' o! s2 r" U0 O( @
  9.       type: String,
    , @) X6 z7 n5 t3 s
  10.       required: true0 \# s6 n7 ?  O$ F# O) l
  11.     },$ P6 n  D/ A# Q* V7 R
  12.     // 数字,有默认值$ q8 M) k- V0 a* p
  13.     propD: {
    6 y" |" h/ L# n- K
  14.       type: Number,
    1 l+ W2 c1 B' ^# J
  15.       default: 100) r- Z# n1 P- [  L6 E3 \
  16.     },
    . V1 l" T6 s7 P* \/ |: i9 P' a
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    + R6 X5 Y  z& N1 `) v
  18.     propE: {
    4 _( h9 f4 m9 O  p
  19.       type: Object,
    0 B% b" N: U  g
  20.       default: function () {
    # b& ?0 v! d% J6 Y9 |+ U- j$ l
  21.         return { message: 'hello' }
    6 Q7 b1 O- ^; J% v; n$ j9 I
  22.       }) G- C( }0 X) j1 q& B, ^
  23.     },* q1 w  c# v  ?0 U: |
  24.     // 自定义验证函数4 N2 B3 g' c# U' \: j4 ]8 S$ b" l
  25.     propF: {8 N, D5 Y  d4 F; `1 o) m; n: K8 ~% o$ `5 p2 r
  26.       validator: function (value) {. B/ V& J( Q7 q8 a8 _7 [
  27.         return value > 106 F1 c1 B1 E# r7 Z" U4 C
  28.       }
    ' j3 W3 F9 D0 h# c7 L4 n
  29.     }2 P  X6 o6 E/ x) w7 u% n
  30.   }
    + V+ r2 q& j, C, X) z
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    # p6 N2 H& ]: Z( c. w  k; b/ A
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件) v0 ]9 k1 _  Y: V2 |
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
; R$ x2 e" @& g
  1. <div id="app">
    % k8 G4 J1 [9 z$ C& y6 k3 Q
  2.     <div id="counter-event-example">8 e4 z0 h' p% ]" C8 {
  3.       <p>{{ total }}</p>
    2 J# z! B0 B5 }
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>" @3 @! v/ \7 u
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    7 U9 O& X/ o  r6 v; S% o; Y
  6.     </div>
    0 V8 X* w1 ^) k! Q5 F4 v$ Y& S
  7. </div>
    9 _( a+ u9 q; B0 m  H  g, @. w
  8. 7 Y$ c* a% m; F7 e
  9. <script>
    2 D* P4 k9 n9 c& K1 g# G
  10. Vue.component('button-counter', {7 H) `5 x) _  _: A9 {4 N, s# A. y1 k
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    . a% y4 x  H* M8 }, E
  12.   data: function () {4 @7 y) X" D8 x/ n; \  p1 C% O
  13.     return {
    8 p, N& C2 Q) z/ K7 K7 O0 |
  14.       counter: 0
    1 Y0 o% N0 ~2 A
  15.     }
    6 {1 j; m; u0 B- V; X# A! [
  16.   },
    * n0 u# Z+ R  s  A- Q
  17.   methods: {  T3 e- B4 ~5 b) |$ f1 Q7 z
  18.     incrementHandler: function () {
    8 [5 |2 Q) d2 E* j0 Z/ a2 T) H
  19.       this.counter += 1# f* F* w# s) k$ S) H, f8 ]" X
  20.       this.$emit('increment')  \. w( J7 G) Y0 n& t7 {
  21.     }
    - |0 U1 ^6 r8 V( _- S
  22.   },, \0 X( s  K4 m  d$ `: n0 F' D, O
  23. })! H: s& P& e5 i( p/ n# u. P
  24. new Vue({$ e! L0 L9 ]1 o; ?1 ]3 T5 G
  25.   el: '#counter-event-example',
    % Q: x  V; T9 }+ r& G6 L7 p
  26.   data: {
    * n! h, i7 P% f5 G0 K: l
  27.     total: 0
    . X" ~. ^; X/ e' ]
  28.   },6 n8 y( ^* I: G# l5 h! c
  29.   methods: {
    , {/ K/ T/ D( w
  30.     incrementTotal: function () {
    2 G+ ~! B$ [4 v/ E- R
  31.       this.total += 18 B) X" u& v/ X( s9 O
  32.     }
    % z& ]1 P  P& s% f
  33.   }
    & k" a$ ?# G% G: C- m6 R; L4 Q
  34. })( ~' c. k- }) u% G  ~$ `' [5 c, V
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    , ]3 ]( Q: d) k( F
  2. Vue.component('child', {) h" W' `1 S: P$ J7 U" e. N
  3.   // 声明 props' I' t6 b: Y, ]  d% E
  4.   props: ['message'],% G+ M9 s& z  [* e; P( l; Q# [9 C- g
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ( D) S2 X/ l) l, G; d' _3 H9 Y2 n
  6.   template: '<span>{{ message }}</span>'* }$ L4 d5 I, Q4 l' {+ {
  7. })$ l4 I! k  [9 w  b3 B& H$ [- \
  8. // 创建根实例
    - ^, u$ _& v1 I, Y# A
  9. new Vue({8 g6 F8 J0 Z  E2 I% E2 t4 h
  10.   el: '#app',6 c* D/ I" \4 c5 d% I/ n. r$ Q$ h
  11.   data:{! J) L. K& Y% I4 ~/ A8 h
  12.     message:"hello",
    , C, b" C3 K7 i8 R/ w8 i- e
  13.   }
    , Q& y( D2 j) F' j& W6 G
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    & I0 g# w* S# t) Q' a
  2.     incrementHandler: function (v) {
    ( F& R* b& u; }1 f# H
  3.         if(v==1){
    - K$ r; q" R6 a" q% o2 x
  4.             this.counter -= 11 V6 M! P! p* y/ O. D% Y9 i
  5.             this.$emit('increment',[1])0 W8 S* f9 j6 t* u# s2 H, e+ Q4 {
  6.         }else{1 E& p. Y( w  _+ H/ J( r
  7.             this.counter += 1% e: [+ U' T# k4 n* S& X
  8.             this.$emit('increment',[2])
    : |# y3 Y0 ~( y7 e" P2 `$ g- }$ B
  9.         }) [& k# m2 i. N) q1 \) s
  10.     }
    ) f9 b2 K4 W+ ~! J' ~) u9 \7 Q2 K2 w
  11. }
复制代码
( ^3 x0 {4 V3 G+ e* T; o

9 _$ b; y. P7 C4 q) X' B# C9 [1 I8 r& q
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-8-4 16:06 , Processed in 0.083418 second(s), 23 queries .

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