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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15350|回复: 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 o: ?* {  E9 }- ?/ b' b; w
  1. <div id="app">
    . S% d) q+ {1 Z( Z+ F  n
  2.     <runoob></runoob>- g# g7 C- {, X7 @
  3. </div>2 P$ v) a( o' ], G- L

  4.   f) k  \& e+ r& _) S( Z' k' y+ q
  5. <script>
    & J  ]0 n5 p/ a. g
  6. // 注册# \) Y0 _9 f3 o3 P$ x$ f7 [8 R
  7. Vue.component('runoob', {
    ' \" `) h2 q. f. h+ V4 l
  8.   template: '<h1>自定义组件!</h1>'. W9 n: _: T, x4 n
  9. })
    4 Y' u+ r7 x( C" \! L+ M" d9 o
  10. // 创建根实例
    8 h; S7 i: Y% [+ e4 i3 y
  11. new Vue({7 M+ M& z# W8 u, r$ \
  12.   el: '#app'( F; h  C) Y- r3 v( M4 m
  13. })
    ' y9 ^) c, L. Y5 M+ y0 [: }
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

4 U0 b6 E4 H  \: F: A
  1. <div id="app">
    7 T: G- `5 m8 n5 I
  2.     <runoob></runoob>% j8 E& u3 Q! ^' T- D, _) J) n
  3. </div>
    * V" ]# E8 {; y6 C
  4. ! Z# _2 O6 f( K9 a7 P
  5. <script>7 t) O9 ^5 z( l9 [
  6. var Child = {3 n" |5 Y9 O$ d: A6 X
  7.   template: '<h1>自定义组件!</h1>') L- E& P# A3 z2 @! r
  8. }: l9 s% K+ c! Q' p* p
  9. ( J, Z9 S* F+ u2 f
  10. // 创建根实例
    . k# p, b) \! c" v) X% Q$ c' K( o
  11. new Vue({
    2 j6 L9 ?0 Z; O% `- I% q
  12.   el: '#app'," {- Z2 T0 M2 H& Z! o* F
  13.   components: {
    - D( E2 @- y) m
  14.     // <runoob> 将只在父模板可用! N0 \) ]' `- O' ^4 c3 i" `" _
  15.     'runoob': Child
    0 U8 d( l) L( P! w7 j+ G, @8 @! }
  16.   }
    " ?" S! `6 k6 l. ]) ]4 S1 D
  17. })
    $ P9 }" S; \  p) m
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例; C! V1 i- n' Z- k" q0 x
  1. <div id="app">
    $ T- r1 j7 L9 \2 [: g4 `
  2.     <child message="hello!"></child>; D* o# G2 F7 b0 j
  3. </div>" x. u  j% X5 z
  4. 7 J, V: _8 B" @4 w! r7 y. ^
  5. <script>
    9 s8 X- m8 ~% F/ D" K
  6. // 注册
    $ \6 ~( ]' i# f" w
  7. Vue.component('child', {. D+ I" D# f" _
  8.   // 声明 props/ A  m+ i0 `  B9 c; ^( P3 l2 ?2 V
  9.   props: ['message'],! {2 n$ c4 D5 q6 Y' [7 w9 f
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ; f$ `8 L; N* |1 }2 E  h3 w8 R
  11.   template: '<span>{{ message }}</span>'7 j. ^) ~, H. Q7 H/ o! s  j
  12. })2 W) q1 j: s! O$ I; N( S
  13. // 创建根实例) E5 c" S4 L: K# g" }2 `
  14. new Vue({
    ) p4 C$ I6 `% \2 g/ [- N
  15.   el: '#app'/ ^+ Y7 m8 k- M& A6 H
  16. }): m3 {( T, z. n* |" t/ g( d
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
6 F% d. {8 f7 @; j8 y5 x( a4 V* K
  1. <div id="app">* l1 m8 G. g1 [4 E9 t* Y. m6 _% ?2 a2 \
  2.     <div>" v: l: l. @6 u) q: v2 a" q; p! L
  3.       <input v-model="parentMsg">
    * V' g) z; `5 V
  4.       <br>
    9 |% J" p6 N- m1 E& f" _
  5.       <child v-bind:message="parentMsg"></child>/ y# G- m- Q9 @% s& n* n! m
  6.     </div>
    , {, [, B: X4 c- m* n: b
  7. </div>
    6 |+ P, L8 J; w" ^( ?1 p
  8. + t, ?: j% J% j1 l. k  k
  9. <script>9 w+ J! h' I5 ^$ b2 n
  10. // 注册
    4 n/ c4 q" U2 n$ L2 d
  11. Vue.component('child', {/ Y8 ?9 o/ u2 [/ i- R7 P
  12.   // 声明 props
    6 \( K  g, B1 y9 W( F/ G( f3 }' K/ Z3 c
  13.   props: ['message'],
    2 S  L3 Y8 S% e2 {5 x8 x! X/ V- B
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用5 \/ B4 |$ c; I- ?
  15.   template: '<span>{{ message }}</span>'
    8 d# ?. Z1 z/ z' ?+ I
  16. })
    # T+ A1 {5 c, E. ^0 k
  17. // 创建根实例, Z: L- E3 }( |* N
  18. new Vue({
    + k# C4 C# N- Z1 k' q! o: X. R" `
  19.   el: '#app',% |6 L& Z7 ?  S1 N- K3 j1 I
  20.   data: {3 T+ O5 y$ c3 R: K: a8 @$ }+ x* R
  21.     parentMsg: '父组件内容'4 f0 [& i# x! ]# U
  22.   }  S4 o* q. H" ?. |' c/ M* \
  23. })
    7 M9 ?  q0 o1 U. P: P
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
$ r& Y7 f% ^; x: ^& B( n! v
  1. <div id="app">& N) F6 c  t1 C
  2.     <ol>
    8 s( K" r( R$ a( `6 S
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>: O( g% H3 T5 G
  4.       </ol>
    " }. n$ H% ~) H/ p* B, t/ X
  5. </div>
    " q5 U2 O$ j& D$ R

  6. : u' V5 h/ r+ t( p$ ^6 \
  7. <script>
    7 x9 O1 K9 l. G; f5 d+ `
  8. Vue.component('todo-item', {+ T0 _' A0 ~5 F7 B+ V. X
  9.   props: ['todo'],3 }+ J; P* B7 Y% J4 n% o
  10.   template: '<li>{{ todo.text }}</li>'
    " @% o0 [: }; N: F% B' Y4 l
  11. })/ _& l7 y; A( l5 ~6 P$ k) T3 V; i
  12. new Vue({
    % |: ~8 d$ i5 a3 C
  13.   el: '#app',% ^. R5 t  t! d6 D/ Q! o) m
  14.   data: {5 I) k8 z( u" ?; q/ k# _* M
  15.     sites: [
    1 ]# [  d1 K. f8 E) D- F
  16.       { text: 'Runoob' },8 @4 o3 y2 w5 P0 Q+ P
  17.       { text: 'Google' },
    + c% ~, O4 u1 ]" [7 g7 ^' e5 x
  18.       { text: 'Taobao' }
    # G( K- l: Z9 H0 d7 }) e
  19.     ]
    3 M( n6 X. w  w+ _( c
  20.   }
    & N; c3 I+ q& y: @8 Q5 m' U
  21. })
    7 u) }- H3 h3 l# M/ Z
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {  q& |5 |8 c# J, Y& W0 Z* L
  2.   props: {
    - y) `; _+ q& `; e* m- H
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    ; S7 `" y- l$ v1 ~2 k
  4.     propA: Number,; A# n0 v0 L! `  y
  5.     // 多种类型- p4 |" b# h1 ?2 W% M0 u
  6.     propB: [String, Number],
    : O: P3 S2 e/ H* I
  7.     // 必传且是字符串
    ( b3 @4 V! e" E9 r, a/ H9 C
  8.     propC: {) ?3 @3 B+ [, o
  9.       type: String,
    ! R) u* T/ Z. ?( B7 W8 H
  10.       required: true
    9 D$ ?! ?) L* `, c% y, v
  11.     },8 m& n. S7 r- w, F2 A' d, z
  12.     // 数字,有默认值/ n5 K1 I! m+ g  l4 K
  13.     propD: {
    ! b; t7 l6 }. [" k
  14.       type: Number,
    * Z* c# o1 Z7 m
  15.       default: 1006 ^. `: K  R; s" B5 u+ y1 D
  16.     },
    5 _0 E5 r' x) a* i( ~# c) Z# V) o! G
  17.     // 数组/对象的默认值应当由一个工厂函数返回4 z% i" }' p7 g) l9 R  ~
  18.     propE: {
    ) e: o) V+ ?3 P
  19.       type: Object,8 V2 ]) O% Y2 H2 N- ]3 ^' o
  20.       default: function () {
    4 |  n: n; ^" p0 h" ^& C; {
  21.         return { message: 'hello' }" r' d% l$ ?+ _9 N
  22.       }
    3 A* l  n; K- }2 W
  23.     },# J5 L' h: }4 G
  24.     // 自定义验证函数2 Q; a/ r' e0 y/ h) W3 V8 J. P' ^1 G
  25.     propF: {! P" i+ |8 U; v8 O( s" O
  26.       validator: function (value) {4 M$ j4 n4 K" \; U% H! D6 |- R
  27.         return value > 100 m, q" j' t+ |" o
  28.       }
    / }9 ^! N. a/ f. q4 A' o
  29.     }
    4 e% ?5 n! }* [$ q) W
  30.   }8 y3 [2 Y# F2 `' ^$ ^. B/ c
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array1 _' M0 _1 v' B
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件: N+ ~' D5 ^/ a
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
1 y# I6 k% k: w' B, ?7 _
  1. <div id="app">7 ]7 y7 l9 u; O7 L# |& P! O! l
  2.     <div id="counter-event-example">" J) A  F" A0 M2 F8 B
  3.       <p>{{ total }}</p>
    $ f0 [, Y) y. w2 V
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    + f! H; C9 y' ]9 P5 S5 t) p
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>9 Z. A, `* u/ U, F: M' f: f7 C
  6.     </div>
    0 y2 X0 ~  e7 n
  7. </div>
    ' w! ]9 d* u" {* }7 u* E& e& @

  8. 1 f, k2 l: y% ]! `
  9. <script>
    3 r+ m7 Q; ~* v0 u
  10. Vue.component('button-counter', {1 Y7 J" X* {# B5 t) j
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    . i3 ^8 d! i; g/ Q$ C6 r
  12.   data: function () {
    3 ?2 A. ?* ~7 Y1 i. q, e# r
  13.     return {! s1 e, i) t" k  S
  14.       counter: 0
    / K: l) d7 c8 h1 h/ X
  15.     }/ ?0 o$ W$ `  Y
  16.   },/ L) W& [, m3 V4 H6 D/ V
  17.   methods: {
    . W/ K) [4 E# d0 ]% h& @  Q
  18.     incrementHandler: function () {
    0 n1 _8 @( x, H
  19.       this.counter += 1
    # O& X! ?- f$ n7 t6 S: N5 _
  20.       this.$emit('increment')7 L0 A4 K' t+ B: L
  21.     }( }6 i: a' o: B6 H8 q" h( f( }
  22.   },6 n+ [7 G) @, h$ n# m: u
  23. })
    5 o+ E! f& p8 q1 D
  24. new Vue({# Z$ h( z4 G  K" k  J, _, u/ h
  25.   el: '#counter-event-example',
      C8 [4 L" p1 l8 F3 H
  26.   data: {" U% [0 n" R2 {) Q2 T
  27.     total: 0
    9 w$ ~5 G- g* U6 m* O& b
  28.   },, q5 x) g. m" e
  29.   methods: {( y/ f. A. S9 u" a( j5 w7 F( e: n
  30.     incrementTotal: function () {
    " M5 K! N1 f9 P" ]4 K; ]2 Y: v$ H  j$ }
  31.       this.total += 1- q5 z1 \0 m( h: X
  32.     }; ~. v) F, M, X5 I$ m1 e
  33.   }
    0 Y" K# V" |/ i& I. L
  34. })  Q: K! w% `4 E, @" t, x& P7 c
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册- W+ Q. k' Q" p" a
  2. Vue.component('child', {
    1 i( U. M6 l4 k" `
  3.   // 声明 props
      a6 Y) l6 i, y, ~0 l( r! V
  4.   props: ['message'],
    * d- f; J, T( X7 |% |4 f0 E
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用) c3 I. e/ @6 I  Q  g  q
  6.   template: '<span>{{ message }}</span>'9 V0 j# W- L" n+ X3 W
  7. })- ]; ^' t: B. [. ^6 C. P
  8. // 创建根实例) f9 `5 `2 ?/ J
  9. new Vue({, H2 v( R( U6 |! B) X
  10.   el: '#app',  |6 `7 V* f7 T. W9 q
  11.   data:{! s4 {  e( [1 l; |: v
  12.     message:"hello",+ T; W; p; p) s) }2 K; G: v
  13.   }' J& @+ X6 m- @- W4 o  `: s* E
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {" i0 c8 }* G- n* m8 F
  2.     incrementHandler: function (v) {$ o4 ^$ ~* g  c9 v5 q
  3.         if(v==1){
    : V+ R  j- {4 q" U
  4.             this.counter -= 1* `- C$ U2 g9 j8 D5 K/ f
  5.             this.$emit('increment',[1])
    " R4 |) g: J& q7 v% {+ J
  6.         }else{
    % P; I; d/ M' Z8 b
  7.             this.counter += 1
    / s: G" A7 n5 a- l  t1 I  B
  8.             this.$emit('increment',[2])
    ( x1 w1 T" R( \  t5 W
  9.         }
    - [/ ]: m4 O1 ~8 n+ V
  10.     }2 B; W" z6 N9 v2 l% }
  11. }
复制代码

! v+ i0 n" j% [, i5 [
$ A; B4 r0 d! T' n! C: T
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-16 18:13 , Processed in 0.067942 second(s), 22 queries .

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