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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15649|回复: 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 B8 q8 h* E+ t9 t' |
  1. <div id="app">% R$ z( M% r" n4 H
  2.     <runoob></runoob>8 {4 _. c7 X  }) Z
  3. </div>
    7 G/ F3 H9 o3 \1 A- ~! {
  4. 8 U8 Q: w9 L+ [+ ~1 D* ~
  5. <script>: {$ E3 Q# a- u9 Q* y8 X5 F; d
  6. // 注册
    , p+ j, }4 p9 q- C
  7. Vue.component('runoob', {, K  b* t0 o+ N6 T7 b" n
  8.   template: '<h1>自定义组件!</h1>'
    + n& m& H0 U; Q5 P4 f- e
  9. })9 P# ~5 {; z+ z* o
  10. // 创建根实例
    5 w! M: t7 c9 x
  11. new Vue({
    . p9 E( F: d7 M5 X' R) c& d6 m# m
  12.   el: '#app'
    * u7 p( m1 i1 T. G: M* S& B
  13. })  ]4 C' z) d+ @+ y& R% h& Z9 z3 X
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
$ {0 x% F3 U. k/ I. |0 o
  1. <div id="app">+ r( U0 o) y) B$ `) N+ r7 B
  2.     <runoob></runoob>: N' ~  n4 n* @; j- D1 `
  3. </div>
    6 f1 s/ }1 h3 Z8 q/ [4 q$ v

  4. + b: }: [3 X. ~: ~8 n0 Y" D, k( K
  5. <script>% O- S% v; }/ ]/ B+ j
  6. var Child = {
    & \8 T+ D8 H0 E* N7 C' W
  7.   template: '<h1>自定义组件!</h1>'
    # ~( K. ^/ k6 y, }0 R7 R
  8. }
    + C+ f1 {! H' k

  9. ) `. k& H0 X8 H. x+ W- t
  10. // 创建根实例# t, \; D4 f; S- k
  11. new Vue({3 W6 Y2 v6 F7 \6 u7 p  y# m  L
  12.   el: '#app',6 n8 a, R: ~0 S4 c
  13.   components: {
    ( L, {5 [0 M& n/ L! h/ M' M: e; s
  14.     // <runoob> 将只在父模板可用
    ; o, ~# c" f/ M# M4 A4 \3 p/ {
  15.     'runoob': Child
    + o( R$ r+ L( w* ~" l5 q$ e0 {2 i
  16.   }
    ) v$ O9 i, E2 U' v4 R( c& X
  17. })
    " x" V# Z8 w! s" x: k9 W
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例( B3 D  r; e! h; [
  1. <div id="app">; [4 _% @3 h" A
  2.     <child message="hello!"></child>* o( x# [* d; l
  3. </div>
    , B0 t. l, e7 S3 n# O) M2 U; F
  4. ( F: C+ p5 P( P  ?
  5. <script>+ c- u7 B! {8 i9 j% H, j
  6. // 注册4 ?4 W/ l4 U. d- |2 b$ D( l
  7. Vue.component('child', {& C+ r4 c* e! a" o% \
  8.   // 声明 props; ~+ U" p) p: q% {
  9.   props: ['message'],
    1 G! i: q5 V, A% }$ I& C
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用) G& X& F; S  M: l' C0 z
  11.   template: '<span>{{ message }}</span>'
    ; e1 Z; w0 {- ?# W
  12. })5 |: S- ]' J* Z4 ~1 P( r
  13. // 创建根实例
    6 R: G5 H7 A; e% e# i. d7 T# C8 Z- q# v
  14. new Vue({: {5 k7 C& @& r0 S+ A; I1 F
  15.   el: '#app'# s+ D# _' h8 ]' r
  16. })
    8 U6 J+ M2 @# C7 Y( }9 X3 j
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例/ g  O' C8 Y# I
  1. <div id="app">
    ( L3 X  A; `& X" u( _2 L) C
  2.     <div>
    $ A7 U+ e* n. Z" ^, |3 f3 i
  3.       <input v-model="parentMsg">  `1 a" `* C- p
  4.       <br>
    + F- }8 D% `7 L; x. s; u" ]
  5.       <child v-bind:message="parentMsg"></child>  N4 A& ~0 n" g& g  P8 Y
  6.     </div>" R6 P6 E! s: x( V
  7. </div>
    0 V( C! S' \* J

  8. . U3 t" M6 F' a( b9 }6 T" l
  9. <script>0 g! |3 G9 L+ N' S- R) R5 b" i7 j
  10. // 注册. x* u( |/ _8 T, M3 L0 X
  11. Vue.component('child', {3 V  J7 ~3 y2 u% r
  12.   // 声明 props/ B0 j) W. t. N0 }% B, v
  13.   props: ['message'],7 M& N' V4 Z0 O5 j2 F( Z
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    3 |7 ^, ]6 U1 G* H2 C/ v
  15.   template: '<span>{{ message }}</span>'
    1 O8 |- F. F" ?- T' @$ E
  16. })
    , r6 s9 h! u# c
  17. // 创建根实例* l& B& W, }' |5 \/ K2 \. l# x6 q
  18. new Vue({: O' }  w$ `8 E9 i- e4 @
  19.   el: '#app',
    # l3 C. I: F' Z  l1 {( O
  20.   data: {4 D/ L; p9 ]; w# [5 b
  21.     parentMsg: '父组件内容'- U1 G+ S" m' J) ?( K7 Y1 B
  22.   }% v% H& q; F9 z) Q9 w( _
  23. })% P, e+ a1 j. G$ k  Y$ ~
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例) a: ^' G  S6 [* T* T
  1. <div id="app">2 N: w4 w/ p/ H- Z4 X
  2.     <ol>
    % @2 Q; w" M4 {5 l; q
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>+ F0 A: i2 L, p8 x
  4.       </ol>0 ^- j0 |& T. d4 N6 [' Z
  5. </div>9 X# |* k+ h6 ~7 p/ p; c' H8 \

  6. 0 l% f' z/ t  U/ H
  7. <script>2 b$ a7 N- M; g/ k! B
  8. Vue.component('todo-item', {
    9 ]7 a& e# _& P) w4 w% O
  9.   props: ['todo'],
    % }* T5 y$ Q! D7 U' s- m( z
  10.   template: '<li>{{ todo.text }}</li>'
    - m# p, X2 ?8 j
  11. })
    # ^. e, b1 z4 ?$ l- H
  12. new Vue({
    8 w  j: K/ m1 Y. ?+ J
  13.   el: '#app',
    . m8 v  z/ m. I9 p( N; l; P1 w$ i
  14.   data: {
    " e0 A  _' E& O) C
  15.     sites: [, j+ ]* H" N( C3 q. D$ u
  16.       { text: 'Runoob' },
    & u' p6 g$ Q2 z- O; F! \/ Z
  17.       { text: 'Google' },( J; p# k% \$ _# K, a$ @* h5 B0 _, K: }1 v
  18.       { text: 'Taobao' }
    1 A6 E, `8 J- j$ `; m5 e
  19.     ]+ u0 t& U  L$ q% d! E
  20.   }
    5 B! v; z5 m1 n2 n$ M
  21. })+ r. I( D2 H' v  ?) Z( b; Q
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    ) o* b8 k6 o* p5 a
  2.   props: {
    ' ~# g7 U9 L9 J+ y' o" e$ e
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    $ U' v% {2 l$ U* s
  4.     propA: Number,- Y, }  F3 I4 h  z, W) G* K$ f  ?
  5.     // 多种类型
    ' a. \) B+ J1 [
  6.     propB: [String, Number],
    8 Y- f8 Z) w% o, s3 Y. F
  7.     // 必传且是字符串
    / e  C, s% X7 J# V0 c9 L9 U
  8.     propC: {
    ( X* q9 ?% H' q4 V0 {! j
  9.       type: String,: y! ]; @2 c  _* o: k
  10.       required: true! K  a$ q! M: Z7 a8 O
  11.     },
    3 s1 T4 Y' B: m, X8 |3 b
  12.     // 数字,有默认值8 E: r$ `- T$ z9 [( X
  13.     propD: {7 V$ L& [& g1 p0 P9 @
  14.       type: Number,
    , U2 M# ^  N  ]" A1 _
  15.       default: 100# A4 R' P. y) F
  16.     },/ i4 S- F5 W9 E$ V0 z% h' r& c
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    7 b6 j) d* s. s% F; p5 i" J
  18.     propE: {
    8 {2 F( u4 l$ ~  O
  19.       type: Object,
    5 f+ J& f7 H& |% T; _1 X
  20.       default: function () {
    ( C+ {* a& o) \9 d: ]$ `( j
  21.         return { message: 'hello' }
    3 z) {: Q( S- z
  22.       }
    $ l9 L8 e8 S) \# r1 u8 ?3 G
  23.     },! t& U3 M( x* B. G% s
  24.     // 自定义验证函数
    & w$ ^' G' b/ L
  25.     propF: {- @5 u# O* t+ B% u
  26.       validator: function (value) {
    8 p, [5 o$ P" k
  27.         return value > 107 C8 {2 v8 o8 V
  28.       }2 I' d: l# ?# d. n% h+ [, v- |
  29.     }- R# {+ S/ e! I( D& ?! s) f, n4 `* _
  30.   }
    * M- U. ?) c, Y+ B; O8 J4 @
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array; x* q/ `: J8 L
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件& w, i, B/ A" `$ Q1 n
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例# p2 f& k# Y; u1 u# ?# [
  1. <div id="app">  h, ^* E6 d. ~, n# t3 X
  2.     <div id="counter-event-example">
    2 w6 o# j2 y1 m- k( M: I
  3.       <p>{{ total }}</p>
    4 h: f0 j9 r6 ]8 i0 V
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>" _  ]9 y3 k3 @8 j0 c9 j# N, w
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>4 }. e8 H, J. g2 t( O
  6.     </div>" U' H4 A2 v1 Q( |" F
  7. </div>3 Z1 }; C1 i( y# N; V9 [2 c" `

  8. $ w( T4 f) O$ F3 ^, J; E" q, r+ t
  9. <script>
    " o, l! S# k8 F! V5 d& z) u$ Z( Z' d
  10. Vue.component('button-counter', {
    5 U, v! E1 I6 L" B
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',) Q! {$ J0 z9 [  s
  12.   data: function () {* C: Q% c  D* [/ V1 B
  13.     return {
    : j- M5 a& k) T
  14.       counter: 0- @3 u, Z5 z  @1 _! K7 l+ ^) w
  15.     }1 x$ n- Q& g: B2 r3 |7 x
  16.   },
    ( |* A* q" U, {/ l( B
  17.   methods: {
    1 {" z3 v. w  [* q
  18.     incrementHandler: function () {
    9 K3 n# I. Y( b9 b
  19.       this.counter += 1
    0 g/ B: H( D" L8 A# l& C
  20.       this.$emit('increment')% M# V0 e+ p7 j
  21.     }
    , ]8 _# ]. q6 R' ]3 _& ]
  22.   },0 `+ K9 _/ j* W$ @
  23. })
    8 w# I! `& |- ^2 n. c
  24. new Vue({
    % C4 I$ m; e6 h, d, b; {9 _
  25.   el: '#counter-event-example',
    . u) F; m1 y) r# g% U0 p
  26.   data: {8 \4 k; Z. h# ^3 n( V( Y) `
  27.     total: 0
    # f. R& a+ t  V6 |" m0 l$ l6 c+ I4 S+ h
  28.   },
    1 Q/ N; g. C$ N7 w4 f% Z8 Y
  29.   methods: {
    3 A4 P$ w  M) _9 ]
  30.     incrementTotal: function () {
    $ B( j1 g: u2 A6 y  O
  31.       this.total += 1
      P+ ?8 R! E/ ~3 N+ s" h
  32.     }
    ' @. s5 M( p* \8 B6 E
  33.   }9 Y" [& _, Q  q- x
  34. })
      b" ]& A& J7 `: n. a! K
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册2 v4 x1 M" ]' K  V+ Z
  2. Vue.component('child', {
    $ c( n$ t0 @( @: h$ G6 _8 r! G
  3.   // 声明 props, D* D) }1 E# r0 w  K6 W
  4.   props: ['message'],# B0 Q$ C% ]# }0 k5 {4 W
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用" X. J: L# |. @' r
  6.   template: '<span>{{ message }}</span>': H" f# Z' `) q
  7. })
    ' D, s1 F% e( J8 \5 p: f3 ^
  8. // 创建根实例
    - S* l, |, f. H/ m
  9. new Vue({
    ' K: D9 a6 v6 c( c' Q" @' y
  10.   el: '#app',( i& y/ _* W# D( }* i" t
  11.   data:{
    & x" K! D; d* Y' k
  12.     message:"hello",
    % }& Q9 o3 {; _7 N, x
  13.   }- U+ j& J, Z' F( b
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {. r; q. z& r% I+ N
  2.     incrementHandler: function (v) {
    7 e: d# \: p- {7 x. @! g
  3.         if(v==1){2 Q/ _% M. _5 B$ R
  4.             this.counter -= 15 M; _9 I/ @0 h8 {6 M* [& a
  5.             this.$emit('increment',[1])- y9 @4 p2 h' P- G& Z+ Q& [6 X3 b
  6.         }else{5 X* n" F: \; v9 ^+ u. U( N9 P9 E
  7.             this.counter += 10 k2 S& H/ r+ s: Z/ R6 w
  8.             this.$emit('increment',[2])
    9 t; r9 c9 a9 {( Q8 @( {9 g! f. u5 Z
  9.         }5 B, V& e, N; E/ @4 p
  10.     }9 J+ V3 n+ |' l, E! N
  11. }
复制代码

( {* |; k$ u6 Q: ~: V. f8 m: ?. z, p9 |+ `) L
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-4-30 19:58 , Processed in 0.063427 second(s), 22 queries .

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