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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

6 _- O! Q  e0 t
  1. <div id="app">, |5 T2 W3 |6 B2 ]
  2.     <runoob></runoob>4 K" Z# K. E$ t9 `, X/ T
  3. </div>7 ]( O, F, x) n, p0 `: H
  4.   |# l& A# B/ z% v" w
  5. <script>
    4 `7 z% ~2 p! a# S
  6. // 注册& Y5 A, l. }/ ?: ^2 x: i
  7. Vue.component('runoob', {% d, }3 R, |9 u4 W
  8.   template: '<h1>自定义组件!</h1>'
    ' q* P; O! H9 R1 [0 P
  9. })
    / E/ s- v7 x1 s" b2 g0 `
  10. // 创建根实例
    * o% U9 N& e' F" G% }
  11. new Vue({6 l0 T7 c9 h) [
  12.   el: '#app'" T; z1 t, a! _2 J9 h" s
  13. }): M+ l8 H' @7 R8 R& I8 J
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
, Z% L) e# I. A1 d$ o/ A* o( ?
  1. <div id="app">& t' g# l, ~! d# ]; C9 N1 z
  2.     <runoob></runoob>
    7 \- C# _6 R- e$ I5 ?2 a
  3. </div>& [& A7 t/ Y. P
  4. 7 N* V, W4 u. {1 Z2 j
  5. <script>3 C' s9 H2 H7 e  p, G
  6. var Child = {. G! y3 w9 P6 S( Y! e5 _  S
  7.   template: '<h1>自定义组件!</h1>'# A% \! g+ q, M! R4 V
  8. }9 Y' u- @1 |5 ^( l
  9. ) c6 H2 W9 M: r" ?5 f0 ?& {
  10. // 创建根实例/ O& @4 r# }% \5 j8 d- t5 s* W
  11. new Vue({7 d4 k: v* y: V( T; Z; S; ?7 D
  12.   el: '#app',
    + c1 N: V3 U( T$ ^+ a
  13.   components: {
      {' J5 }/ n+ N9 ^" v3 ?" _2 k
  14.     // <runoob> 将只在父模板可用& `6 C- F$ p& ~$ v( [" ^2 p
  15.     'runoob': Child) i: Z4 [* V2 j# e
  16.   }
    0 K6 B5 P/ I$ z1 Q! K
  17. })4 A( _. k1 s* W( ~7 p
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例2 Z0 m. ~* M) ~; [" ~
  1. <div id="app">0 K$ e9 z" S9 s: M7 {
  2.     <child message="hello!"></child>7 T! i5 Z, w8 M7 P) |3 h: s
  3. </div>* w0 {  h6 {& S* \0 ^

  4. ( z, \$ W4 A8 ~: X4 c- a8 p  j# L( m
  5. <script>& r3 ^* R. j7 Y5 h
  6. // 注册
    6 g4 f' }, L: @7 u
  7. Vue.component('child', {
    6 d3 h$ h( H5 }. A' [& d
  8.   // 声明 props
    8 h6 w3 V7 t! R( m- x' ]5 h
  9.   props: ['message'],/ F' G: ~( ]) B; m- ]  y4 B, P
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用6 K) c6 _: }* {9 t
  11.   template: '<span>{{ message }}</span>'
    , f8 H7 y; A( i
  12. })
    3 Q- T1 ~9 c& I  d
  13. // 创建根实例2 }: P! {4 G, q9 h( u
  14. new Vue({6 @6 h) B/ h6 f: K" S# `
  15.   el: '#app'
    ) V( `7 F0 B# B* [4 c) D
  16. })
    + c% G( v2 N5 c9 Z& `  c& P
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
# R: x9 x) Q; E4 A7 P6 U, z/ I- [
  1. <div id="app">& a% W7 I1 R- v( u
  2.     <div>3 b; Q# x/ J$ _3 N* }
  3.       <input v-model="parentMsg">
    . l! G/ k; _: O# Z( e
  4.       <br>
    2 O2 }! l2 N( f9 v1 R" C; @3 N
  5.       <child v-bind:message="parentMsg"></child>; V5 k# h1 Q% _% k2 t4 a% \. D- P
  6.     </div>+ T" y2 ?5 r# [! S# @4 O" |
  7. </div>
    3 a/ ?8 o$ x6 _

  8. - R) ^- R7 l8 l' R1 H$ p$ d
  9. <script>
    9 {, h. d* y# Y8 p1 S0 C# I$ u9 ~
  10. // 注册
    4 n& C" D0 [7 v8 s4 [) j5 x
  11. Vue.component('child', {
    6 {$ T, b5 x; L& i- D
  12.   // 声明 props! |7 O+ ^: ^% a9 C9 w
  13.   props: ['message'],& Y; K- s: c2 n$ o
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ; o: Z3 F( v* \: ~- `0 T! C
  15.   template: '<span>{{ message }}</span>'
    * v& `/ s; T( O6 J7 n7 I
  16. })% m! [0 e& t9 j3 [+ m; [; _3 C
  17. // 创建根实例( W2 }# c6 t' b+ D9 Z
  18. new Vue({
    ' t8 _4 ~* f& p* D; U1 _
  19.   el: '#app',% w, v9 N1 {  g4 ?
  20.   data: {7 G0 s  _7 V1 H% S
  21.     parentMsg: '父组件内容'
    4 u( Z2 e" Y& e6 W/ F8 ^5 X/ s
  22.   }
    8 ]* h* d" @5 J* m/ r& o
  23. })" a2 u0 g/ Q! A% H' d
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
  J( S( |5 G) a% g+ u( b: i3 g
  1. <div id="app">
    / H2 q7 ^! `9 f) R+ f9 ~- Z
  2.     <ol>2 K$ y: {4 z  u6 H
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>. D) F$ J; f/ I/ G* h' \2 z) N( A2 p
  4.       </ol>0 M" x+ k4 n+ K, v! t" ?
  5. </div>
    % l' d$ ~0 y( Y6 X, }9 X8 L
  6. 1 \' Y& M# S0 Y- H$ S
  7. <script>
    ' u4 N( G# t. |0 S+ }. j
  8. Vue.component('todo-item', {4 T: h* @" G# A5 b9 f5 h
  9.   props: ['todo'],
    4 F* r8 I  ~3 I( z' r- }' }( [
  10.   template: '<li>{{ todo.text }}</li>'
    / J- q( x$ d8 ~5 v9 `) w2 \
  11. })7 O* g( {- }" S2 w3 ?
  12. new Vue({
    ( k  U# p3 s, A* J- K
  13.   el: '#app',! e# s0 x! |, C: X
  14.   data: {
    9 _* \4 o, `7 m- ]) m' g" ^+ g
  15.     sites: [7 ?' s  v! U6 w$ ?2 J3 }* x
  16.       { text: 'Runoob' },
    , s0 ^/ [) H' N9 B2 m+ w" X
  17.       { text: 'Google' },8 H; {( e( ~7 `+ w% |  `; B. m, s
  18.       { text: 'Taobao' }, B' ?2 k1 v" M& B* y: r
  19.     ], L. X: f7 o8 A" b$ |
  20.   }
    5 ~. T/ L# A" `
  21. })( X- E, O! r, d* i$ u, E5 J
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    ; G* _) i7 N" |1 V
  2.   props: {# d. L' S$ c$ j8 p4 E
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)6 [. I; j) _  k: H7 b5 g3 a) q4 g
  4.     propA: Number,$ `! {& P0 _. m: A$ n' u
  5.     // 多种类型* c9 M+ h; m3 @) o9 ]
  6.     propB: [String, Number],
    6 w5 X+ _( u1 h4 V2 @
  7.     // 必传且是字符串
    ( e% M7 e% b6 s3 A' v( ~" k
  8.     propC: {
    4 ^& E; Z" L: i: G1 U) n
  9.       type: String,$ W. r+ @8 c+ a
  10.       required: true9 u3 ~7 q  I- o5 J1 J
  11.     },
    . x' S4 [! u) S# j
  12.     // 数字,有默认值
    * _5 t5 g, t$ l" C* b7 U" n) a
  13.     propD: {
    * _* c% R/ t' K
  14.       type: Number,* z( d! H) t) I9 A
  15.       default: 100* c. s* x5 ?' n( c- }
  16.     },
    / a) A" v) k" N8 _# i  ?
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    + o! Y8 h, A" O2 |2 g4 @- J
  18.     propE: {
    ' ~# g9 `4 }- Q: K  t- n; p
  19.       type: Object,! e6 l9 U9 V2 g9 z' g5 D
  20.       default: function () {
    * P" V6 A* L, {- ~% O$ d# R' s
  21.         return { message: 'hello' }4 s; F3 t6 M8 c# S" X
  22.       }" D) v2 B& E- H7 R) J! {
  23.     },
    2 E1 w3 p) ^0 g& w/ l( ~
  24.     // 自定义验证函数
    2 g5 @8 {, ]0 a% z# `1 K! C" I! P
  25.     propF: {
    ! ^# R; j7 t. ]
  26.       validator: function (value) {; {& H8 M6 x$ c2 {
  27.         return value > 10
    0 {" T6 l2 P. d
  28.       }7 U( a3 o' R  c( W; y- C) ~
  29.     }* r* v% i: _" q6 p" j1 L
  30.   }
    : L1 ~0 c5 c9 c+ W
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array3 |1 q5 i5 j4 s% k: J6 J
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    % N& d5 f" K% P
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
7 i. Z/ p+ J. W
  1. <div id="app"># t% ]7 O5 L- }
  2.     <div id="counter-event-example">: l& l: `+ D4 c4 p/ ~5 ?$ d
  3.       <p>{{ total }}</p>
    - E7 E' E& l9 ~$ ?2 q
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>' {+ W6 ?6 Y4 D* |6 k( ~5 Z6 d
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>( a2 m8 y+ n/ F
  6.     </div>; A+ [* D  o$ b9 h# w& B! R
  7. </div>
    * k( Z6 c. Q  ?+ e/ m9 ?

  8. ! q! Y6 q4 w1 i) [6 `6 v
  9. <script>2 t, x' B. R! z+ v, ]5 t
  10. Vue.component('button-counter', {
    # s* d# \. M( K/ S/ C
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',# d! B4 {3 a) Y) v' c1 O
  12.   data: function () {
    % F5 E/ ~: E% D- x6 M# k
  13.     return {
    % Q+ M5 Q3 h! S+ ?
  14.       counter: 0
    " N* X. j: F1 p& N
  15.     }
    5 F& w( c! }) m1 S$ e, ~; `
  16.   },
    1 k# m; N+ T4 |& |
  17.   methods: {
    $ y) H$ \: b0 ^, z; ~
  18.     incrementHandler: function () {
    # q( h! D/ ?) `: j. @
  19.       this.counter += 1
    & g0 l# [$ ~, D% @/ K
  20.       this.$emit('increment')
    8 w2 M8 K% |/ P0 J
  21.     }* Z' M! K& K) K  K0 a& _: y
  22.   },: {# _1 @, U9 i1 ?* e: F
  23. })- ~- P; y6 y$ n
  24. new Vue({
    $ W- b  {" F+ G  A  x' P
  25.   el: '#counter-event-example',) x! a- D  P7 S% [, X
  26.   data: {
    ' e* {  R! [4 V4 Y2 S; ], g
  27.     total: 09 m0 A( o' U2 t1 D6 }+ A8 N
  28.   },
    + }, P# j5 l3 G4 t( a% f
  29.   methods: {
    0 {1 X( n* z# e" ~  ~. s# o
  30.     incrementTotal: function () {! Z# S6 w2 j8 V6 p) x( R# H. O, e
  31.       this.total += 1, W& ]" M0 V0 c' u2 y, i
  32.     }8 m: r4 E  c/ O( |' p0 D
  33.   }
    1 j+ A0 R7 d  {' X4 J4 h0 x
  34. })0 M+ e% @: t5 e( W
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册0 s2 v0 ?& t+ M0 }
  2. Vue.component('child', {
    9 ]9 E  f. R0 U' j- s1 Y
  3.   // 声明 props4 G3 v% `7 E* x+ h2 v: {; i- S
  4.   props: ['message'],( k1 u: ?- P% R3 D
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    # y9 [* o& @3 q5 L
  6.   template: '<span>{{ message }}</span>'4 t# [, _4 T; S2 n9 S1 X
  7. })) P6 V' [; ]7 K
  8. // 创建根实例
    * V2 o( d1 q& w* m
  9. new Vue({/ k' s. D% N- \4 _
  10.   el: '#app',
    3 h1 g  x. w0 ^9 n! _3 \% F: C6 P
  11.   data:{! n$ W) Q- c# z5 G6 l9 R9 [3 P
  12.     message:"hello"," }5 n' m- ]1 N1 w; P' @. f& a
  13.   }
    7 |* O% M( X9 y# c" A; V
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    $ b4 g/ @7 l! }1 y$ `& F# u: ~
  2.     incrementHandler: function (v) {
    7 h6 K! P+ Q% u: ^0 L4 M( u
  3.         if(v==1){
    , Y1 L/ R5 p* y; o7 F$ J
  4.             this.counter -= 1- Y+ E+ y% @9 H+ c6 G8 M2 s
  5.             this.$emit('increment',[1])  d8 E- j' D1 L3 ]2 W8 X- m
  6.         }else{& r5 X) h  [+ B- I2 J/ R; _
  7.             this.counter += 1
    + k" ~* y$ l1 K8 }/ u+ a+ \9 V
  8.             this.$emit('increment',[2])2 o  y+ K9 P# N9 Y( Z; m
  9.         }; ]5 H; }8 Y9 e: [2 d: _
  10.     }
    # J* M- f& P4 e/ ]  T: Y, W
  11. }
复制代码
' j5 z) O& X$ [, K3 `, `/ k
+ m" B! V5 Y# G; i; S: [# Y
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-20 04:17 , Processed in 0.078773 second(s), 23 queries .

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