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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 16295|回复: 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 h4 o8 Z; U2 L
  1. <div id="app">: H( f$ ]0 H% H! F& R' R) s
  2.     <runoob></runoob>
    2 e3 d# f& u) Q, @
  3. </div>0 G. O1 `2 U  R2 @  A2 v1 G
  4. - u  |( ]9 d+ e( t
  5. <script>& l0 T) A; [: P
  6. // 注册
    * O$ \+ q4 U% w6 d/ P. I
  7. Vue.component('runoob', {3 j$ o& n' n6 a. p  s4 c6 Z
  8.   template: '<h1>自定义组件!</h1>'
    . y) Y% ?4 z0 E2 V4 H3 z
  9. })5 i" ]  d( e% z# ]
  10. // 创建根实例; F  V0 q3 L# t/ z: A0 n. X
  11. new Vue({
    1 S/ `1 v2 r' S2 x
  12.   el: '#app'7 a4 }( G( j, l. t
  13. })
    6 H4 S! V; k  t$ t( d2 ]* H
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
) `# K- m$ u( F: L9 P4 @
  1. <div id="app">
    7 v: T1 M* P; r
  2.     <runoob></runoob>& S6 O8 s) i( q: c- f4 W- X' D  {
  3. </div>
    6 m* ^& }+ I/ x* [5 b  e

  4. 0 q: U. F, w# `& m" s
  5. <script>" _' @2 M) B; p, C9 s3 v
  6. var Child = {
    0 h& E- l* [: [) L; O& B$ [9 X- l
  7.   template: '<h1>自定义组件!</h1>'
    6 d6 \, E' D3 Y. R: l, L; q
  8. }( G/ h3 \4 k  {) j2 H2 J( k2 R
  9. " G- Z6 x  B: s) [- }8 A
  10. // 创建根实例
    ! L  X" S" I* b7 \& ^
  11. new Vue({( a- U6 ?1 ~4 E' J! V
  12.   el: '#app',. h" [3 G, @7 C9 R8 d. p9 k0 R
  13.   components: {
    ) Z: P: L& z5 i
  14.     // <runoob> 将只在父模板可用, c0 [! Y0 c- {
  15.     'runoob': Child! T4 M2 f) g* z
  16.   }
    3 `4 C: K" ^0 [8 i
  17. })6 {$ J. u6 @. K& q/ m
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
1 X2 c$ \! X4 S* M, }& m; f
  1. <div id="app">6 g/ p. I* R/ d- t
  2.     <child message="hello!"></child>
    - ]" A0 w& ^  q' Q9 Y
  3. </div>
    - p" v$ O( T: Z! C  v  a) M6 m6 a, U1 E

  4. ) i3 s$ H4 ]$ s% S2 Z3 j
  5. <script>6 B0 H/ N& S- F" Y4 M; D) h$ L6 j
  6. // 注册6 M+ D( x# u: ~! m0 y
  7. Vue.component('child', {
    : S+ \2 ~9 z% H  h$ T& _
  8.   // 声明 props
    2 @+ N0 g( d$ e! ^& T
  9.   props: ['message'],
    8 z- ?& w) o  D+ p* X& j9 y% U' {
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    " W$ J" W& R# i, x6 g
  11.   template: '<span>{{ message }}</span>'/ Y6 v- k" ]9 X# T
  12. })- S0 t: e8 Y0 J7 Y! O
  13. // 创建根实例, u- L. G6 o! i8 `& v' W+ o
  14. new Vue({
    8 o/ ?) A* P9 z1 y  P
  15.   el: '#app'$ O' f2 P3 Z) D) q5 b  C/ I
  16. })
    7 g/ u) J, A! _. N7 l# g
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例. o& B! P4 \- W2 s# j
  1. <div id="app"># J2 S/ Q, ~9 t4 w
  2.     <div># j3 ], }8 U$ R0 D! w# V
  3.       <input v-model="parentMsg">
      q: E3 k% u% D  Z4 t
  4.       <br>" m6 I% N! x/ @1 T
  5.       <child v-bind:message="parentMsg"></child>
    7 m/ I% v4 }  J
  6.     </div>6 Z' Y. V2 c) X+ k; A& T6 g8 A* s* F
  7. </div>7 A: O6 E/ Z* j8 _3 I: n. \

  8. , V, u/ H5 f$ l7 m0 \
  9. <script>4 N8 C6 t; l0 y( R
  10. // 注册
    " b  p8 p1 `& p$ w" j: f
  11. Vue.component('child', {* Z1 P2 B1 l2 I! g$ O2 ~
  12.   // 声明 props
    : p. I: o3 H% z" A8 b$ K- |
  13.   props: ['message'],
    8 N2 v# Z& H$ z0 ]2 f( U
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用8 S1 G' n" {0 V! O0 _  Z/ m) L
  15.   template: '<span>{{ message }}</span>'+ E3 \1 b* E8 m. I
  16. })8 _" J) Z. j7 N! R& z
  17. // 创建根实例5 j$ ?+ v6 v* v/ x
  18. new Vue({
    ( S0 R& h) _' o/ s
  19.   el: '#app',; h& }! D* c+ a1 E8 h) \2 t6 ^  A* K
  20.   data: {
    ; P5 J8 ]1 W0 B  Z; \4 O, \
  21.     parentMsg: '父组件内容'
    , u  `$ g& _% p% a1 ~) c
  22.   }
    & O5 s6 c5 V3 {( T$ }1 o9 A0 b! R
  23. }), I; _2 K) [, C
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
4 M- t6 m: c% {  a( s1 Q
  1. <div id="app">+ ?9 z5 y! x0 j$ f
  2.     <ol>6 F; f' X9 K) R; S- u1 b
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>& y3 b! f, h( t8 F! ]
  4.       </ol>
    - A5 |' t: K  ~( s7 e$ @0 k
  5. </div>0 ?& v3 L$ B1 r; z

  6. " T; w" @9 C" _# A1 o: K" i
  7. <script>
    6 l+ u4 t6 F% O. K( |( Q
  8. Vue.component('todo-item', {
    4 M5 Y' C  l" h( ^3 O7 _0 W
  9.   props: ['todo'],
    ' b2 g: f% o# s* p5 P' e
  10.   template: '<li>{{ todo.text }}</li>'
    , v% x' A: s0 D$ ?  F) U/ j
  11. })
    1 J3 [3 l, t. d0 q5 {1 {1 E
  12. new Vue({  }; p& P" J# V7 {
  13.   el: '#app',3 [* \! ~1 q0 i) }8 l  ^8 {7 y
  14.   data: {
    # z( b- `# d" N0 l( a
  15.     sites: [
    : ?% i- \& l: b
  16.       { text: 'Runoob' },& E8 L9 ^& U/ K3 w' b8 `4 {- t2 Q+ W
  17.       { text: 'Google' },
    - a2 U4 D. ]% t: a) E
  18.       { text: 'Taobao' }
    8 V' m& I# F1 |& c+ \; o; |$ K
  19.     ]& E& j9 z. k- Q7 F$ E! B7 @
  20.   }
    & f7 d$ L2 n9 E' X& {; b" ^. U) A7 f
  21. })/ r5 M" T  Z0 y6 t' U
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    6 F* C: V/ R  I. N
  2.   props: {9 b8 ~+ T) Y( C* n9 {- N0 N
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)7 c% c* N+ J2 w* j9 A7 p+ \
  4.     propA: Number,+ D9 s" m+ f# f" [8 S0 }' m3 s
  5.     // 多种类型
    " v7 V/ a9 p, a  j- Z
  6.     propB: [String, Number],: C: n; H6 v9 ^
  7.     // 必传且是字符串: k  V; R' ?, r! N
  8.     propC: {
    5 D3 c8 ^' F/ w! ^6 ^
  9.       type: String,
    7 y1 j5 y5 `8 l) z! v: T
  10.       required: true
    ! s, _9 J* L2 l
  11.     }," `8 h  F) d4 z9 ^( }+ `# \+ Z
  12.     // 数字,有默认值
    . \& f1 V, P6 s5 y4 [! Z: F4 j
  13.     propD: {) C: b; f) ^+ }: o2 Z
  14.       type: Number,
    ! v/ f2 f8 D5 Y, E/ ~
  15.       default: 100
    # d9 p& G5 }. e, P
  16.     },& K9 g3 S( A/ D+ l6 Q: ^3 M
  17.     // 数组/对象的默认值应当由一个工厂函数返回
      y* \. O6 p3 q7 v: I0 j
  18.     propE: {9 Z* f/ M- E$ U; u" u* l
  19.       type: Object,
    5 O% O5 g6 F' J: V# g! N
  20.       default: function () {; i0 d* n* c, X# q9 P6 l7 X4 E
  21.         return { message: 'hello' }
    & h- s1 u4 R8 O( O0 ^9 M
  22.       }
    ! c$ d) O. ~: U3 b5 ~
  23.     },: t1 t9 r% a4 M& |& B
  24.     // 自定义验证函数" |/ {7 l* u+ `4 S" r
  25.     propF: {
    1 h9 E# ?# j4 F9 E6 a' _- }
  26.       validator: function (value) {. @( ?* C2 l+ Q! D% K- _
  27.         return value > 10
    # L  D5 z. K4 K  T& t( u
  28.       }
    ( Q4 L  d- `& L' K/ i* p
  29.     }3 R8 H7 d6 a; e$ O" W$ h4 W
  30.   }: K8 }. q. o+ w* w
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    , L7 H! w* t( r$ {3 z
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    * V! _8 ]$ B- h4 b/ z1 O; E& k1 i3 E2 [
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例# b+ |7 ~7 o" p
  1. <div id="app">
    : i% @8 c! C5 k5 q0 _! ]7 n3 g
  2.     <div id="counter-event-example">3 ]& Z, A4 P2 O- ~8 R
  3.       <p>{{ total }}</p>
    / H2 J# _  B* l- L  l
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>. ]; ]5 P" ]! d3 [
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>: j% e- {& @0 K$ Z8 K, a
  6.     </div>: L% E# X/ l) l2 q" |4 g' y8 Q3 w
  7. </div>
    , |5 l& f; a" c: U; ~
  8. ; [3 y, @  p6 |4 z( m
  9. <script>
    * x: f& X0 W  n
  10. Vue.component('button-counter', {% S# m6 s1 O$ B3 q3 V. u
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',- x8 N) [  k/ |+ b7 V0 h+ C; L
  12.   data: function () {/ s# n; e" q  W+ s* ~1 ?' w
  13.     return {. m$ W0 a/ p2 t' _2 L
  14.       counter: 0
    % @$ ?' p- t7 B' t& r
  15.     }0 ^0 ?. V! I" x" W% D
  16.   },+ P( W, R* Q) K' k6 i
  17.   methods: {' Q1 l0 N& N8 {- A$ c* x. v
  18.     incrementHandler: function () {
    * a. z* m4 N- J0 F/ {: J
  19.       this.counter += 1+ s! {2 _" |. d
  20.       this.$emit('increment')
    . n+ G; t) ~% Z9 y: x( F
  21.     }
    + _% N  p6 u: L  s; s% B
  22.   },6 U  ]& O2 B- j& y% P6 M( M
  23. })
    & ~3 ]" G  Y! `( \& b2 M0 }+ a
  24. new Vue({% {" g3 ^2 `+ F# r& g5 B. T
  25.   el: '#counter-event-example',7 Q+ [" t5 ^8 v' r- b
  26.   data: {, p. m# R! x  }$ w
  27.     total: 0
    0 B2 s: w4 ~0 H, q% y' r  Q* S
  28.   },
    6 }! ]" E. j8 Y" `  l9 }9 p
  29.   methods: {
    . Y! ?& H: P1 V/ c- f% e" `2 G) n
  30.     incrementTotal: function () {) `0 P# _9 @! v7 f* |* z
  31.       this.total += 1
    ! ?, Q/ {# W/ C/ _2 G7 J# g: f0 f/ G
  32.     }4 H; x( K; d7 y# @
  33.   }7 l5 s. Z4 Z0 g: D+ j+ I% m
  34. })
    ) {5 G4 d& A7 B& T5 g
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册5 h" X; U: n% a  \# l1 `
  2. Vue.component('child', {
    5 K$ q. P7 W6 k; C* f! M
  3.   // 声明 props( ?" j! D; s" d
  4.   props: ['message'],
    ' p+ V  T; R! w- F, B3 b+ Y
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ! y* B# A  P" |2 C2 S
  6.   template: '<span>{{ message }}</span>'
    7 I0 t+ m# N& e# v
  7. })
    0 }* j/ X4 l: }) E: Y2 \$ e
  8. // 创建根实例$ v4 b$ G% S" F
  9. new Vue({
    ! c: b( m5 m$ o! G
  10.   el: '#app',
    9 A8 ^: t/ `4 M0 A$ V+ A
  11.   data:{- @( }1 j% ]' j* v% D' D
  12.     message:"hello",8 `" U2 M! Z0 i
  13.   }7 I) ^% w. h5 ]) I
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    ) E" |6 M7 F# {+ |6 g
  2.     incrementHandler: function (v) {
    # {6 Z9 }" Q6 \; l( ~
  3.         if(v==1){+ I" `5 K7 ~- w8 c& ]2 ?) h, D! ]* e
  4.             this.counter -= 1
    + n% l- u& N# a4 m; M0 ^
  5.             this.$emit('increment',[1])
    3 w( l( z8 w1 a) _2 {5 b
  6.         }else{: J& B+ d, B' L
  7.             this.counter += 1
    : W- O3 V8 J# n8 M
  8.             this.$emit('increment',[2])2 d; n$ u3 g. H3 \2 W  {5 h
  9.         }: x( v- {0 M! k  J, D
  10.     }% i* [4 l% I0 D& M# r
  11. }
复制代码
6 g- e' V* z6 i0 f% _

. o( [, p  c9 S
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-8-4 10:48 , Processed in 0.056779 second(s), 22 queries .

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