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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 11005|回复: 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,并使用它:
& k% E+ ^& b! f, M( m. [
  1. <div id="app">" V/ z/ D; A) @8 d; K7 m6 f
  2.     <runoob></runoob>, B  w; @* s' r9 L9 L" o5 y
  3. </div>2 K- K1 g, k9 ^9 k8 F: ^4 U
  4. " f8 w- R# S* O2 I) V1 x6 }
  5. <script>% Z7 P) ^4 j7 i3 `" i
  6. // 注册
    6 r, P, V! c7 ~3 E" v
  7. Vue.component('runoob', {& j3 x1 V5 ^2 A. i0 O
  8.   template: '<h1>自定义组件!</h1>'
    / {2 W! L5 P& z; S4 s4 l7 n2 o6 O
  9. })# n* \  q8 t8 \, L# C* K7 s2 X' Q
  10. // 创建根实例. K7 g' C! O/ ~* v' O) G) U. w
  11. new Vue({5 }- c! I8 D, [7 r! W
  12.   el: '#app') w4 s: h! X9 ^/ r" c: j, ]: I
  13. })9 g: f9 k+ j) o# n6 z. }. |
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

" K7 m; n- ?# V7 C$ f9 i
  1. <div id="app">- o( K. p! J) b* W
  2.     <runoob></runoob>' c; c8 D5 W$ i/ }7 I% W
  3. </div>
    2 L$ j" Y  g3 d
  4. ' W" d" i- d6 \$ M" E
  5. <script>
    % ?) i' {% ]. p4 ]
  6. var Child = {9 c9 |( z7 K# G. X
  7.   template: '<h1>自定义组件!</h1>'
    5 [9 M3 q9 Q7 ^# G
  8. }. {" F" ?2 O  U; c9 V

  9. 3 `6 M% j& N( @! C: V. o* Q8 i7 i
  10. // 创建根实例
    ; [4 ~( |4 D6 D- W- g  `8 G; G
  11. new Vue({% z1 c, T: d6 [
  12.   el: '#app',
    * r* ]% `" z3 y
  13.   components: {
    3 _1 n- q2 _/ V, n  J& E& }/ a
  14.     // <runoob> 将只在父模板可用( e: n) y6 U0 f* p0 G$ v: b
  15.     'runoob': Child
    / D* l1 k% @9 j
  16.   }- W& _- D( W. {* C, n) O3 Z7 ]
  17. })" l9 K1 S+ ^" B: W+ z9 {
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
+ F# K% \6 {; d. V/ l
  1. <div id="app">; D& ]  a  E4 f. s" t9 [- Q* x
  2.     <child message="hello!"></child>% A& b7 z9 x$ n' T: ?  K" ]
  3. </div>
    9 {) h/ J5 S/ U3 u9 A; G; [
  4. # ^% s6 g1 E7 M9 p3 O, ^. A3 t
  5. <script>1 M+ {! Q. Y2 d  X. ?4 E# c
  6. // 注册
    , o: s; \, }& h5 @  V7 Q3 M' D) O
  7. Vue.component('child', {6 m# W. Y/ k$ N4 C; r- J, w
  8.   // 声明 props
    1 x+ r( D1 O7 g$ k5 s/ x
  9.   props: ['message'],
    # _) ^& y' Q8 v! o# w0 M
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用( _, g( R1 H1 w7 V+ z! j
  11.   template: '<span>{{ message }}</span>'3 e# ^" h( |/ p+ A0 h; u6 g2 y
  12. })& z9 V7 ~7 |+ N# j- `$ N
  13. // 创建根实例) }' a! B2 E* n% k
  14. new Vue({# I$ b3 _- \/ w" ^- n
  15.   el: '#app'2 M1 @- }& V1 b& S: V
  16. })) J, r' t- m/ u; Z0 p4 h2 N
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例3 {* c" s+ @% ^$ S1 b, T5 [
  1. <div id="app">
    0 \7 X; R' u( S0 |7 K0 R
  2.     <div>1 w$ |' n" O7 Q( j5 R$ S1 D( P
  3.       <input v-model="parentMsg">
    2 ]: e" w# d# X) l+ z2 c1 m& d
  4.       <br>9 l/ [' ?$ r2 @- Q3 s3 A, ~/ D0 M
  5.       <child v-bind:message="parentMsg"></child>
    ( z. w9 i, [0 e4 b. |* D# L. d% r
  6.     </div>$ c0 F* _/ f* t: g7 d1 K& V
  7. </div>4 y; i+ s' X" c! F9 I/ `
  8. / S( j5 r' V4 W9 n) b
  9. <script>0 a  l& I) X% W
  10. // 注册
    * A0 ?+ A" j3 t& z; J
  11. Vue.component('child', {
    * Z- ~) e% n% r+ e
  12.   // 声明 props% u' W3 X) V" m- X5 k! Y
  13.   props: ['message'],7 w/ J+ _- p3 K- }5 b) v6 ^1 m( m
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用9 |$ B4 J0 X7 v$ |
  15.   template: '<span>{{ message }}</span>'
    9 k$ g* _7 \1 O' |
  16. })6 {* s5 s6 Y0 l! @. x2 _
  17. // 创建根实例
    ( o% w0 @+ g0 @9 G6 C9 r- U
  18. new Vue({. [$ B$ S' J# e+ t' L' X" n" N
  19.   el: '#app',
    - K& N/ E0 R4 ]" t
  20.   data: {
    : L  o2 }# }& Y% E2 D% r- ?
  21.     parentMsg: '父组件内容'
    # W- W5 t2 u/ [# I  p% `5 }
  22.   }
    % o4 x4 P! x" T+ Y" k
  23. })) R7 [/ ~* ~8 G6 n7 M4 V% \
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
2 t1 P; }# k; C% |1 Q' B, v& U, P4 s
  1. <div id="app">' h$ i6 h# P# l* O8 L9 f) a
  2.     <ol>8 i4 f: }, B( ]" Y
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    % E" t, L& K& R6 J' ~" ?! H
  4.       </ol>
    ! K% [$ s! D6 Q! _
  5. </div>5 h. G! b, {3 P
  6. 4 u/ Q6 ~4 B6 @3 {, _, `
  7. <script># n4 q5 q# Q, x6 U  w" ]4 {
  8. Vue.component('todo-item', {& d. O& T2 K& C) _9 A+ J4 C7 \
  9.   props: ['todo'],& h/ c$ k2 m: N) M  i4 v" a
  10.   template: '<li>{{ todo.text }}</li>'# h) p! z4 {& o3 {# K4 Y
  11. })
    * u7 ?4 ~6 j  X$ e* [* d
  12. new Vue({4 I+ r3 U( V: d: E4 Y" p
  13.   el: '#app',5 ^3 R! k" u1 g% z8 z. C' X
  14.   data: {
      d# Q" Y0 o4 l& G" I* [; A
  15.     sites: [# Z- l7 _0 t" l7 n2 Z1 j8 ^/ X
  16.       { text: 'Runoob' },
    % ~  E' y8 K/ x# |3 E6 f
  17.       { text: 'Google' },
    6 R/ E, @% t; q* q) @6 S& u' e
  18.       { text: 'Taobao' }
    % q. w/ P, j; v+ V7 P; V* `5 w
  19.     ]
    2 u" v6 J$ y  q) O
  20.   }" P; Z8 {/ M* Q9 f& ?$ I# f
  21. })
    # r7 Z% c2 y  B) |8 X$ Q
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {, o8 R. d7 X% w( y7 ?$ M
  2.   props: {
    ( h/ v- n# ^$ |  `9 F
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    ) ]' n* ?. N+ ]
  4.     propA: Number,
    9 |4 y# x7 f2 d8 ?3 x
  5.     // 多种类型5 @- q7 P9 n# R5 T
  6.     propB: [String, Number],
    " s" y* i8 M9 J- L* C& T3 u
  7.     // 必传且是字符串) N, a/ X8 _" v3 w/ {
  8.     propC: {
    6 Q3 T3 K: Z$ ?9 Q4 `
  9.       type: String,
    1 H! q9 g2 r- x2 I6 ~8 E7 r
  10.       required: true
    + E) y, S# [& v! d0 R- ~
  11.     },: c2 N! d( {0 s% a4 \
  12.     // 数字,有默认值
    4 ^) }5 T  Z2 G: Q) W
  13.     propD: {
    # J- N- Q% z+ H
  14.       type: Number,. w; T0 N1 d0 b0 F- N$ R/ n0 U0 m
  15.       default: 100& L7 [4 P4 F6 u% o& g, o' ?
  16.     },8 v3 X9 ]/ ?# s2 h5 ~( h
  17.     // 数组/对象的默认值应当由一个工厂函数返回- N2 j+ g- K# B. w& {4 \7 x* J
  18.     propE: {7 d1 P5 t! g: f1 B) a  P/ t
  19.       type: Object,! z. e3 ?# r; b3 Y, v! ?  T9 B
  20.       default: function () {5 ?/ T6 ?5 j/ m. `- ~( ?  U) x
  21.         return { message: 'hello' }1 W+ D% X1 k; d) |# E
  22.       }+ J  t, I9 N/ U* p( k. I6 f3 [
  23.     },5 p( b6 Q1 _2 {% r, ^4 Q# W6 N& U
  24.     // 自定义验证函数: J# z; O, ?7 E6 P% ^" H
  25.     propF: {& V  ]' n/ E2 g+ _; x( o. i* k
  26.       validator: function (value) {# Q$ Y9 ]2 x# b- b; u# {6 `  Z
  27.         return value > 102 f$ m4 f+ G5 ]: a5 e+ B
  28.       }
    . X% T4 e" Y' b+ S
  29.     }
    1 }/ Y* o1 o0 Y+ q  R2 P' B/ A
  30.   }0 a+ n0 ~) _; y- B9 e1 X
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    $ q+ U+ r6 @6 w' x5 Q( l
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    3 I  j' l2 t% u: G( {  A
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
# z- s: W+ e" m7 F; K$ ]6 y$ K
  1. <div id="app">. ^+ |3 {5 o  L6 [7 E1 h
  2.     <div id="counter-event-example">
    0 v' c7 g0 m3 V% y) M# \7 q
  3.       <p>{{ total }}</p>
    7 V3 n- a& O5 H5 O1 c9 ~
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    4 T: u! E& F: d" J4 W
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    & n) m+ }" E) x- H- V4 `
  6.     </div>) k3 t: }, S( F, ?
  7. </div>
    ; B# y, r, W2 R/ V5 t# q
  8. # y1 W9 w' Q5 K. y/ F' Z1 W( Y
  9. <script>
    ) S! U! ^- B# T
  10. Vue.component('button-counter', {0 L, R# y5 {: F, a
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    * m  O/ M6 l6 \; {& o
  12.   data: function () {
    . u+ K. g0 g% M9 B
  13.     return {# k1 R/ L4 i% ]* N6 N% I
  14.       counter: 09 @1 K3 R2 W* K* L4 ]) J
  15.     }* `$ @3 o2 U- I* T2 h. x0 J7 ~  T$ E$ o
  16.   }," I8 j. z4 S4 |3 K% U
  17.   methods: {
    $ m' _/ ^7 F0 S' n+ |4 R& d  T" {
  18.     incrementHandler: function () {
    9 h3 O/ f( r8 m
  19.       this.counter += 1& |9 t7 S* z/ X9 k! S
  20.       this.$emit('increment')
    4 V: n" P, u/ ~7 H- Q
  21.     }
    : S' m0 s( ?3 y5 [7 X
  22.   },
    : |3 T3 L' ?0 t7 y
  23. }), [6 |/ J' U5 P3 ~7 ?% r% T
  24. new Vue({
      {8 r  B6 P/ [
  25.   el: '#counter-event-example',
    , |6 H; @( v) e& I! {' S
  26.   data: {+ t8 F4 y% M$ T7 J& I
  27.     total: 0
    3 X4 r" d9 G5 X/ N3 d
  28.   },/ l9 n& K% U; F, D
  29.   methods: {
    " U# `& z$ [+ C
  30.     incrementTotal: function () {
    5 r$ D: a* s4 f/ }% R& D2 P& d
  31.       this.total += 1
    $ W) G) [, U: ^" e
  32.     }
    ! R# u1 w9 Z5 n) W
  33.   }& N& X+ j" S; t" h% a. k
  34. })
    1 u2 h- O7 U4 H% W7 Z" ]2 ^
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    4 a% I1 C& Z# w  [" }/ x! s
  2. Vue.component('child', {. M5 I  }' q- L1 s; d. ^: |' b; D
  3.   // 声明 props' A& ^1 ^4 y6 B* U- E4 G
  4.   props: ['message'],; G# m0 z6 j, z; [
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    / b* p8 V5 B5 `4 [
  6.   template: '<span>{{ message }}</span>'
      n# D# b- s: n8 d/ i2 p) L8 {
  7. }). F2 J! p4 G1 p6 S
  8. // 创建根实例4 \, r% o  Z% B, A" |8 e
  9. new Vue({
    ' c& E# {% b, L/ A* S
  10.   el: '#app',! k" M9 m* h* ^: r) v
  11.   data:{
    8 l, Z, W0 S* Q# [( r4 ^
  12.     message:"hello",
    % M! s) U+ q$ W  ?4 l
  13.   }- V! k' _2 D5 h% x
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    0 [( M6 u' l. F0 c
  2.     incrementHandler: function (v) {: w' N( d2 x( z
  3.         if(v==1){; V1 c9 w0 V. ^
  4.             this.counter -= 16 d8 L0 f2 S( C- m
  5.             this.$emit('increment',[1]), _' ?8 x, ^2 \$ ^& l
  6.         }else{) D* ~# a8 H$ W
  7.             this.counter += 1
    ( n3 w0 \' \  F# Q5 C5 J
  8.             this.$emit('increment',[2])- d6 W/ ~* X5 D5 j) J+ G4 |/ E- q2 }5 B- @
  9.         }
    + _, D5 B( [9 y7 g( B+ v9 t
  10.     }6 W; n& T, U" H+ v3 u
  11. }
复制代码
: U; Y3 r" Q, l% J. M. ]+ I

# m( m% Z  ^2 T7 J/ J
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-15 17:16 , Processed in 0.148513 second(s), 23 queries .

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