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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

' T, B; g* o% b' S% S
  1. <div id="app">- [0 R8 e1 g5 _
  2.     <runoob></runoob>6 ~% @1 T2 F4 T6 w; j0 a, S# W
  3. </div>
    5 T1 ?  Y8 z7 b, y" `  C

  4. & R% O: S3 K! @8 Z8 Q4 T" g3 N
  5. <script>
    * N- B+ F  @/ \9 I4 E, B# S9 v* Y! V
  6. // 注册1 j- R5 m0 }' e: @. J" {' A0 q
  7. Vue.component('runoob', {
    8 ~* M. ]/ v9 E- J! e/ Z
  8.   template: '<h1>自定义组件!</h1>'4 G+ B0 o7 N, K/ A" }
  9. })
    9 F5 z  g7 B6 w
  10. // 创建根实例: d! h* D" E- G8 z
  11. new Vue({# z* n. y& j* j2 l, \/ F8 _
  12.   el: '#app'
    ( U! q# \* r3 [' q
  13. })
    ) X  w! w& ^7 |: c
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
# s2 |' X% b0 R* I! ?5 p  C  `
  1. <div id="app">5 j) P7 S+ G* l
  2.     <runoob></runoob>
    ( }7 D1 K$ s, x9 w- D/ B( q
  3. </div>
    ) F4 D, t% c* o

  4. ! {; Y, k) K- q2 \
  5. <script>7 U* E) Z( c9 c: M$ P+ f
  6. var Child = {
    / Z; H( w& D: e0 M# u& L4 R
  7.   template: '<h1>自定义组件!</h1>'
    % T6 j( `# h9 v( j  A8 R2 a
  8. }7 ^" ^0 P5 }) p4 |

  9. % Z9 S! q7 m: V0 ^
  10. // 创建根实例
    9 m5 _. t4 p1 j- B( B
  11. new Vue({) A9 [5 o. c$ z) ~6 l/ b& T
  12.   el: '#app',
    ) A$ |$ h* V' z# e
  13.   components: {' w: H+ I1 S9 z$ {
  14.     // <runoob> 将只在父模板可用7 M. V' l! j$ E1 s4 h
  15.     'runoob': Child. R% t/ @) O* |( {/ a5 k& t$ C7 F
  16.   }9 H! B0 h* ?/ `: I( R  i! z' |% ^% F
  17. })
    1 U5 }% _! Q6 l7 a( V8 P7 A9 v
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
: I, l1 z" S( {5 f6 h
  1. <div id="app">- F' b, p% C* T1 t, \
  2.     <child message="hello!"></child>
    2 k0 k+ |" M9 V4 R$ H; ?+ @
  3. </div>2 \. b5 B4 H, V, t

  4. : V0 ]5 t! |- E+ y$ N2 P( E- t
  5. <script>, S4 V3 A, Y! G  z' ^
  6. // 注册) n3 N3 G  u/ Z9 p8 W  O
  7. Vue.component('child', {' P7 g8 B9 h9 i9 b
  8.   // 声明 props
    5 T% p$ K/ h6 _- \/ T7 B+ L, n; R
  9.   props: ['message'],
    2 Z* g5 i# e; I& Z
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    8 ]3 Q/ P7 o' c* j1 l( @1 y  N
  11.   template: '<span>{{ message }}</span>'
    / k& k2 B3 v& ~) N
  12. })
    5 T3 S* z& n6 Z8 J; P; G
  13. // 创建根实例
    ; }/ n2 d7 U' e1 \& p+ F" u
  14. new Vue({
    . L+ ^2 p, A( J) ^
  15.   el: '#app'5 u& E1 e9 Z4 ?4 N! R
  16. }). p$ w% _+ k6 X6 G
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
5 u/ w( w, S: [) t. G' T* @
  1. <div id="app">$ Y* d" @* r, t# y
  2.     <div>; e" B  `/ W( C1 e+ i* n
  3.       <input v-model="parentMsg">
    3 g7 H7 ^, E) j- b* X/ Z' e3 [8 z
  4.       <br>* G+ p# k) t2 W% a/ n8 ~1 w  F4 R
  5.       <child v-bind:message="parentMsg"></child>. w$ K( w' e) B: p$ `7 v
  6.     </div>
    & d, k9 X3 _$ F: I8 \2 \8 |
  7. </div>( y* k, n5 P( t& D( c
  8.   h) [2 S7 i4 V8 y' I2 B8 d
  9. <script>6 ~" K' u: T: S) L# T
  10. // 注册
    9 D+ O/ `8 v' x; m
  11. Vue.component('child', {
      G) G8 T/ O$ ]. K
  12.   // 声明 props
    9 M. g4 _3 q/ X$ G' X+ a
  13.   props: ['message'],1 r0 w, `7 m+ r7 e* J6 Y
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    7 [# z- O. z2 |% ^4 R
  15.   template: '<span>{{ message }}</span>'
    " [9 s: [: }7 o5 A( z- p# H8 B
  16. })
    2 k; ]3 A3 \6 z$ M
  17. // 创建根实例3 \# P- z& Q4 c& ?) P: @5 L
  18. new Vue({# V* s3 z7 \( U
  19.   el: '#app',
    : G9 |2 F  F9 n6 b& w+ r- [
  20.   data: {
    4 b+ R; j$ q* Q) A
  21.     parentMsg: '父组件内容'
    ' R9 Q. b: }5 b5 U/ b2 z
  22.   }
    1 O) q- ?: V7 _
  23. })
    % Q! v1 f1 o* z. o: F; Y
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
7 D# q, R9 p. [) _$ o. u
  1. <div id="app">+ [) d5 g- z& [& }
  2.     <ol>
    ! G( x7 `" k0 O6 X8 |) K/ m
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    9 W" f4 f  A, k3 f
  4.       </ol>5 U) F1 C, {4 Z7 J
  5. </div>
    " N4 e7 \# `+ w0 p

  6. 6 ~3 f; Y7 ^7 ^
  7. <script>8 I2 V" Z1 {6 Y0 {' i
  8. Vue.component('todo-item', {$ Q5 D: M3 a0 l* \  ~
  9.   props: ['todo'],
    % `, m* j) u/ W$ c- f$ w
  10.   template: '<li>{{ todo.text }}</li>'
    3 F( e9 _: N) i+ @
  11. })
    % A" {1 C  n2 \# g
  12. new Vue({/ t, N; ?2 M( k9 |2 ^& }. w( ]
  13.   el: '#app',
    1 Z0 o1 N' J2 u& J
  14.   data: {' m- E+ p/ U5 r8 ?
  15.     sites: [
    ! Z8 H8 h+ _5 \) a7 k" m
  16.       { text: 'Runoob' },
    . V1 `0 T* ]* }; R
  17.       { text: 'Google' },+ v$ p9 l! a4 l) P" t& e: T& @; ?; x
  18.       { text: 'Taobao' }
    . S) b0 Q5 ]. a% u' Q; s0 I
  19.     ]
    + T8 D& ]+ r1 m2 `: S2 y
  20.   }7 Z# w; h& }8 G: E. T0 W( [, w9 h
  21. })% J) p/ r' k( h5 l1 g. `$ b) y
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {# t9 Q0 F" C. Q4 L. Y3 ?
  2.   props: {
    / o' ]5 m3 S2 Y
  3.     // 基础类型检测 (`null` 意思是任何类型都可以), M( \. o: {$ V: W: b9 d9 ]6 }
  4.     propA: Number,
    ; X1 }" A9 u' ~' P8 `6 R
  5.     // 多种类型
    9 Y, Q, R6 c9 x' E* ^2 ~
  6.     propB: [String, Number],
    $ K2 k# k+ M6 E; x& ^( K9 s; g; [
  7.     // 必传且是字符串
    0 V& d6 `/ h) G9 |/ x
  8.     propC: {
    9 N7 Z  \/ p1 ]# Y
  9.       type: String,
    0 _- L# b0 v+ p- r2 N
  10.       required: true
    - c+ ]+ `* r# M* L" B/ X. ?
  11.     },7 j+ o2 A' _; z* b9 g0 B1 ?
  12.     // 数字,有默认值* P/ W8 n8 ?# Q
  13.     propD: {
    1 g% M6 @4 e; o: x
  14.       type: Number,+ U, K5 _, |! Q9 {4 q7 F  P" _
  15.       default: 100
    ( F6 k0 l/ K4 S
  16.     },
    # E: f8 j, U: D. z' [/ a5 k
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    5 Y' q$ W9 L$ d- c9 {" D7 c( t
  18.     propE: {' V! h! Q, ?2 H. g3 L: m# K
  19.       type: Object,
    4 [4 s& F' a9 s8 G6 ?/ v
  20.       default: function () {: @) l% G4 _( N, o/ N
  21.         return { message: 'hello' }* O! q9 s8 [6 D
  22.       }
    9 J$ G! W2 s( U2 [
  23.     },
    2 S- T+ @: r" l& s7 [. U+ s
  24.     // 自定义验证函数
    & T) e% N) A4 F0 K; O
  25.     propF: {
    . @1 b' w% F" Y6 o
  26.       validator: function (value) {- i) k/ Z" r+ i) h: ?; A' w& r: `
  27.         return value > 10$ U( s; f* D2 F4 @# [
  28.       }
    $ E+ l& A" w" ^1 U7 c
  29.     }
    ' t+ i" Y& g1 v: x
  30.   }' z0 {, w* Q7 l4 e1 f( X6 Y
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    3 C. P6 X: A" a$ g6 ?+ \
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件7 o9 c) J9 ~, l, W  t+ t4 X" {
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例+ F' o8 R, {5 L0 V
  1. <div id="app">
    # y+ n4 a4 u3 y- y% M, f0 m* Q
  2.     <div id="counter-event-example"># n; O2 i8 _! G( Y8 A0 Y4 ^. s9 F! L
  3.       <p>{{ total }}</p>
    9 U: Q9 |; S  t5 z: R; y
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    / K4 f+ n0 ~) O3 W9 b
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    5 N# Z' ]; K# \" I# i
  6.     </div>
    ( i7 Z4 P" n- X
  7. </div>
    7 i$ G6 j0 f" Z# c( U

  8. & f/ Q0 D$ q  |2 T! M, A8 A
  9. <script>
    6 q3 g8 F9 N* n
  10. Vue.component('button-counter', {4 ^5 T# O4 D4 b) L" t
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    8 r! _- \. T- v/ k: Q  |
  12.   data: function () {: @! z: f1 f. @6 v( W: r( e2 y
  13.     return {
    % i. ~6 w$ M  C3 M2 h7 Z0 l% E
  14.       counter: 0$ m' w  O1 H. {% ^. F' s, W1 U/ S
  15.     }
    . P' x$ u) z* I+ {' B
  16.   },
    8 |; ]! `# E+ m) n/ f
  17.   methods: {
    7 B: i2 X6 `5 z* b0 z0 }
  18.     incrementHandler: function () {
    + M1 A- k7 l. W* ]! b) M, w
  19.       this.counter += 1
    7 V6 R( J1 |3 b3 ]4 e$ E0 {
  20.       this.$emit('increment')  l5 `' O; z$ U) f# D1 g
  21.     }
    2 b9 r5 _  N& ?& s6 ?
  22.   },
    ; V1 u* {9 U9 \+ O/ M4 b) m
  23. })% q  |: t' n, L0 R) }5 U
  24. new Vue({
    / ?9 U& g7 F. l" t# r# n
  25.   el: '#counter-event-example',
    ' j) D9 B4 y1 A- y2 C- L, [
  26.   data: {
    $ q$ C& Z- B1 W" U3 f
  27.     total: 0; [) v# c# _0 {
  28.   },! `' s7 d1 I6 Q: }: ~
  29.   methods: {0 T# l1 r' ]  f7 e- w5 h
  30.     incrementTotal: function () {
    * J" A; R9 K  S+ r8 b
  31.       this.total += 1
    ' p5 Z* R' Y9 R/ m
  32.     }, s# ?3 Z" h4 ]: a0 ^5 T0 e3 N
  33.   }
    5 x% L% t3 t) T) z
  34. })
    2 Z2 a$ n0 y* l1 D& S+ X; b; n8 o: v
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册- h) d+ p- h; ^. }5 F/ F" T5 G
  2. Vue.component('child', {
    ) d9 k9 o0 C0 K( Q
  3.   // 声明 props
    ( I1 a% V/ x2 E" Z# B3 q! Z) D) y
  4.   props: ['message'],
    ' M' B$ w- o- j1 O/ e" T! \+ ?$ _
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    + K3 F7 C3 q1 j3 H& K% [! W: ]3 H
  6.   template: '<span>{{ message }}</span>'
    8 q$ ~' \) J+ ]- Y
  7. }). n+ @. P7 a! d0 o% d7 t5 f
  8. // 创建根实例  U5 }, g3 h# u4 _5 }; d9 Q7 E
  9. new Vue({6 y4 y1 P; Q) b7 h6 f; l
  10.   el: '#app',
    # h, ?4 Y, ^: Q* z
  11.   data:{+ ]" a5 v+ E2 x+ R3 J- q; J
  12.     message:"hello",, d7 x, F9 }6 [3 ~4 @- N/ X
  13.   }
      k/ N! a- ]( J/ y
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    $ ]+ ?" k& Y, T! g. U# \
  2.     incrementHandler: function (v) {) D: m2 \: L' Z( H; P
  3.         if(v==1){
    . N2 q2 [+ V, @- T$ X2 s
  4.             this.counter -= 1
    & J# K+ a$ E& F. C: V
  5.             this.$emit('increment',[1])/ s* ]& [$ N9 z0 K) Z7 V0 Z
  6.         }else{* M( R8 d) ]7 z& n7 c
  7.             this.counter += 10 w0 |" M2 _* L7 v3 b* k
  8.             this.$emit('increment',[2])- o9 {* W( y4 ?+ l8 a. D
  9.         }
    6 F0 j0 A9 z* o) z$ w) w
  10.     }
    + U& G6 t! B' v& N6 m- Y1 p
  11. }
复制代码

1 U. J3 y" m6 |# k
, o7 d4 W; t& ]* z) L$ A. |
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-19 22:40 , Processed in 0.055406 second(s), 22 queries .

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