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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15830|回复: 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,并使用它:
  Q! c# [& [3 _* e% v2 |
  1. <div id="app">
    " ^2 F; C% K% y/ r8 Q1 w+ @
  2.     <runoob></runoob>
    3 ?1 U; `. w2 O! a* Z3 c+ ^# H# w! {; a
  3. </div>* i  E+ ]- O% r# O' ]6 ~0 V' ^

  4. " _6 S: y% n" {  ~' R7 Q& c, g) l
  5. <script>& ~# g$ Z& E2 D# P7 ^+ s
  6. // 注册
      Q! P' ~  B0 m$ W# b$ d( C/ Q
  7. Vue.component('runoob', {
    : M( Z5 N% B' q' A6 K* i' G
  8.   template: '<h1>自定义组件!</h1>'
    9 w7 V8 ]6 ?- a# S6 Q; h' ^. Q
  9. })
    4 R1 O, R6 N% R) u: L9 P
  10. // 创建根实例
    ( B+ _5 X8 m: x$ Y
  11. new Vue({
    0 B: O; g5 R* `9 y4 [% a/ q/ m
  12.   el: '#app'
    9 }0 E; Q3 X6 Y$ I( l7 _
  13. })
    $ V7 p3 y& F/ b. E  e! N% k
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

. ]) X9 r6 r; }
  1. <div id="app">
    " _* L: i) Q5 o  ~
  2.     <runoob></runoob>
    & q' F5 B  ^" b9 d6 |2 h) E8 t
  3. </div>7 _0 Q6 m' y& Q  i4 `% y  i

  4. 9 p4 t2 k1 g6 B7 H4 M& C7 e
  5. <script>
    - D/ w+ H5 P1 K: K, E! y  W
  6. var Child = {
    " \& j1 i/ L9 w6 N; N  E
  7.   template: '<h1>自定义组件!</h1>'
    : C. E5 B0 V$ L8 R+ v
  8. }3 S5 ~! p" ]# i% ]  v3 s% d7 a

  9. ) z! q/ _1 r0 [& A, `
  10. // 创建根实例
    1 _5 q1 R" h  h2 B
  11. new Vue({
    " y  {8 {! y" D& H. ?8 c
  12.   el: '#app',) Y& }% {6 S7 [& j
  13.   components: {. z1 R8 [, h# W5 A! Y  c, q; l
  14.     // <runoob> 将只在父模板可用  S9 i) k0 D8 E* J$ {* i1 b
  15.     'runoob': Child9 W9 H( X4 F8 G) c
  16.   }$ t4 z. S' V$ Z9 ?; k1 Q
  17. })) a) V5 p2 ~3 D
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例. A' `+ c1 Z- c2 P/ p2 y, d8 R
  1. <div id="app">
    . _* ~6 {- E4 p) V8 V4 ]$ Y
  2.     <child message="hello!"></child>$ P9 l6 P; [! o# d5 a6 B
  3. </div>2 d$ a$ r2 D8 a3 \

  4. $ Q+ a6 N2 @4 H7 l8 o. k3 M
  5. <script>
    & T6 R5 d& S0 Z  I. [  }
  6. // 注册% W$ H% |- c8 V& J# Y6 v! V
  7. Vue.component('child', {
    ; L. F, a8 K) n  ~1 {+ Y
  8.   // 声明 props
    + M1 N; r$ Q3 K; U  @
  9.   props: ['message'],
    0 X! v/ O9 j$ }9 K3 S& `$ F( J
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用6 X' o( c! \4 Z( r+ O9 p" T6 C1 o
  11.   template: '<span>{{ message }}</span>'
    . w4 D9 {/ k" h0 Z# |  n4 b' ?! g
  12. })
    , S4 `3 h1 k! {: R. x5 v* {
  13. // 创建根实例' p& e; g$ K5 c: A- S3 `' ?
  14. new Vue({, e! k- P0 \- g# |! D& s+ l
  15.   el: '#app'
    1 b4 ]9 w: b) N/ n! p$ J: u6 E1 {
  16. }); {/ L" ^) y( S( W/ u  _
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例0 d6 z& g0 A: e  v* [+ U, T! F3 l
  1. <div id="app">$ n, j$ y5 x# \. O1 T
  2.     <div>2 I* O  k+ J1 i& u8 \
  3.       <input v-model="parentMsg">
    : B$ O. J, n  i$ H8 d
  4.       <br>( }, ?$ W/ ~( V# ~" @$ m+ \
  5.       <child v-bind:message="parentMsg"></child>
    - s+ |8 x& [: M4 W" V8 i+ C
  6.     </div>) S9 Q' f' R( g
  7. </div>
    1 \$ U( U9 x6 U% }" D5 |$ {+ |
  8. 6 X7 e. g9 a5 t
  9. <script>% V0 w/ G% u$ w/ V. c% a
  10. // 注册' [6 b3 V; `8 g) t3 z# c
  11. Vue.component('child', {
    + ~( V& w: I, {8 o
  12.   // 声明 props
    : w$ U5 y+ R/ I
  13.   props: ['message'],
    : U0 N$ l; q2 u' `
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用! [7 c' F/ U, V$ B% x
  15.   template: '<span>{{ message }}</span>'
    6 L+ s4 N) f! F9 X5 `. L0 s
  16. })
    5 T1 m# ~+ I( u5 \
  17. // 创建根实例
    ' q2 I" V2 d. B) Z
  18. new Vue({# n4 q# N. J6 N0 m
  19.   el: '#app',
    " g+ B* A/ Z' G) |* w$ S+ |
  20.   data: {: H6 P4 J% b0 n: ^/ @# E, u- A/ n
  21.     parentMsg: '父组件内容'
    3 `( Z) H: h% M2 g# d# w7 B% C9 l# a# J
  22.   }
    7 ^$ {9 f: l. S+ W" i! b9 D  @
  23. })
    + v% ~# k- S7 Z# v! B
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例8 b2 {3 f  Y6 F, B1 A1 ^4 \
  1. <div id="app">1 |& F: E. @7 h& o* N) c5 M) z
  2.     <ol>/ D1 }/ i; _1 y  q
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    4 x+ ^. ~  Z% q6 ~
  4.       </ol>: `# D8 |% [; N$ y( G( |0 ^4 M  a
  5. </div>
    0 s0 \! M- w5 R
  6. 7 `" x1 P* S  m: n. z  |
  7. <script>% h+ G/ l2 }+ X8 ~
  8. Vue.component('todo-item', {
    0 q. }4 f* H0 j- N
  9.   props: ['todo'],
    1 p" i0 p! m6 \, I5 J9 [& k
  10.   template: '<li>{{ todo.text }}</li>': E& B. Q) Y8 V8 P
  11. })
    * A7 ]3 K) v" d. V' X
  12. new Vue({
    4 S7 g2 i" O+ o6 f& j6 F
  13.   el: '#app',7 {! A) n8 ?, N; |: l$ r. }$ v
  14.   data: {
    ! a. X9 Z" [4 D7 b) C
  15.     sites: [
    8 p# L8 D5 V; ~: w/ X& n- H
  16.       { text: 'Runoob' },) _8 ]' {; V" ~/ S
  17.       { text: 'Google' },
    ! A# P3 G, e( @
  18.       { text: 'Taobao' }/ i; b/ T6 M/ _% z/ h1 B- |
  19.     ]
    / n( i+ L$ P# c( y* U6 }- F
  20.   }
    6 I$ u' `/ c; B$ l( ]! ~* P6 L
  21. })
    1 M: P$ W/ E) q, [9 H' p, t
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    - S+ b' L7 g8 |, U9 H% }+ B
  2.   props: {3 {/ P4 E! Q& j& n' R- F
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    & v- ]5 s; ~9 C# W
  4.     propA: Number,
    2 B; g% \7 G" @! D4 G0 N
  5.     // 多种类型' ]. y) A( C' @5 q  C( r9 F
  6.     propB: [String, Number],
    6 |" s+ u0 ^/ a) C7 Z3 b8 U
  7.     // 必传且是字符串) s. I1 w/ F, u# C3 y5 s
  8.     propC: {2 b' \7 F, T# m0 y3 K1 A
  9.       type: String,
    - i  |. J8 n+ ~
  10.       required: true/ P) D9 _9 ?# p. V
  11.     },
    0 E* o$ v( G5 v1 e
  12.     // 数字,有默认值1 M/ N- p0 ?  v( o/ J
  13.     propD: {' N2 [* }+ y+ e4 p; a, ^! E) r4 q
  14.       type: Number,( `( w' z1 ~' }: I' v' I: f/ |
  15.       default: 1004 X5 {1 v6 Q; \3 k( W3 \8 E
  16.     },; i9 p( \0 D0 s1 \2 m2 t2 X
  17.     // 数组/对象的默认值应当由一个工厂函数返回1 @* p/ S8 ]& F5 M) e: T% f
  18.     propE: {
    0 U5 E/ m  z7 Y
  19.       type: Object,% [# v/ K: c9 }+ o9 p7 F
  20.       default: function () {
    5 |8 d1 W" T4 l# y1 q/ x
  21.         return { message: 'hello' }
    ' q8 x" E, p4 L  e9 F6 o
  22.       }! \% B6 n: W3 {9 _( g# `
  23.     },* K8 w! s9 L6 q) b+ F! n
  24.     // 自定义验证函数
    ! O. h, C# F! p: S$ n, Q! @  ?
  25.     propF: {
    0 b1 v/ g# e* s7 u0 }
  26.       validator: function (value) {
    ! x' c- n. o7 ^4 i% K* y$ g$ Y; g
  27.         return value > 10
    ) q1 T2 R! H9 ^$ S' W
  28.       }
    7 [, {, A" g0 \  S+ q
  29.     }% F6 O7 J9 C/ h2 R
  30.   }
    5 ~6 T5 t" x4 e8 ?0 ^6 I0 Y0 M$ p
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    6 y7 V5 I% J6 l, x  a+ \; [
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件/ k/ a3 a! v. h
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
; a, ^& o9 T( P! T' T3 I+ L
  1. <div id="app">, A# w( n% O: _. |/ G
  2.     <div id="counter-event-example">; N  `1 F5 {  s5 S
  3.       <p>{{ total }}</p>
    - F! e" c$ _# |3 M" V5 B
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>4 p8 f& [: w( A7 I  J6 }9 y. `
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    ' u1 H9 D' K( F$ P
  6.     </div>1 H) _9 T% _0 t8 E3 F8 S
  7. </div>5 \2 Q5 R1 g3 l0 ]# x

  8. + U3 |) k/ }4 F  `9 q
  9. <script>
    - g9 B: q" e3 L1 j  j
  10. Vue.component('button-counter', {$ n! k" ~6 w) P; z
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    - I, v* i. {! o' s) C
  12.   data: function () {4 b3 I+ X) ]0 r+ Y' D' n; B3 N
  13.     return {- l) P2 z8 F& ~. p3 d
  14.       counter: 01 _* [2 G( g9 a" w% U1 Q* R3 Y
  15.     }2 B7 i. h% D! p8 s( c# i: |9 _" A6 r
  16.   },
    0 \: V  k6 }' ]5 L/ \% o8 f7 F
  17.   methods: {
    & h% |' G% @( e; w+ O2 ?. ~
  18.     incrementHandler: function () {) a. j- p4 s. C7 A  E# j, W+ M
  19.       this.counter += 1. A, b6 u& c9 U3 D# u
  20.       this.$emit('increment')
    ( c: i# q# w, a
  21.     }
    : j9 \  M7 S) R# t' L
  22.   },
    : e7 h$ [  g1 Y5 l, I$ O+ E
  23. })* I; }+ H' r: \- n' \
  24. new Vue({5 G0 u/ ^/ x) Y1 N, O4 x
  25.   el: '#counter-event-example',& w% B- G7 @- I% l
  26.   data: {
    ) l% U5 j, L6 I/ ~# \; D4 o: d+ ?
  27.     total: 0+ v+ O2 o, V$ A7 Q4 J, N# D* L
  28.   },$ R& T. v4 p* t# V+ t, _% ?7 f& ~8 S1 N
  29.   methods: {% o  [. Z0 f7 J( }
  30.     incrementTotal: function () {0 \: c# E3 C4 ?
  31.       this.total += 1
    - {* a  v( `0 Q8 m
  32.     }: I- ]  i% Y1 }& `; c
  33.   }
    6 J8 X1 F1 D' U# _2 J  x6 U1 B
  34. })& Q$ r: X' Y' L; s+ J
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    " n6 J& }, T& v5 O0 u' Y
  2. Vue.component('child', {  ?. f! d. j$ A* c' d+ S3 |
  3.   // 声明 props; d! z9 V$ ?! ?) E; D0 `$ f! p$ ^
  4.   props: ['message'],
    & Z, d! h8 w& m. z* I1 o9 |, Z
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用$ }0 M+ e' l0 y6 s1 S
  6.   template: '<span>{{ message }}</span>'" k( w" J" u+ z# m& e
  7. })
    0 k3 M, ]# }2 F  f4 q5 G/ v" N
  8. // 创建根实例
    2 R  R4 G6 E6 x
  9. new Vue({# R( R# F  ?4 L# H" b5 U
  10.   el: '#app',
      u  S9 U% {( c! x2 Z
  11.   data:{" ~& Z# u) d. z! J7 {
  12.     message:"hello",5 p" ~: W7 t  c1 _! n
  13.   }
    7 c+ D& C- }" M
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    # M5 {1 ?% w) y8 N
  2.     incrementHandler: function (v) {* H. z+ l" L: Y& s# I/ P0 g
  3.         if(v==1){
    9 h, k, x. B/ R& b3 {0 x+ L6 _
  4.             this.counter -= 1' T: o1 P4 V! ]" M! g9 F. Q
  5.             this.$emit('increment',[1])
    ! {8 q8 @$ A" H6 _
  6.         }else{
    6 D' W9 @/ z( t+ N- S9 o
  7.             this.counter += 1- S  \3 b0 N4 z! M' ~& _
  8.             this.$emit('increment',[2])1 X5 C+ c5 a! ?8 w$ {4 \
  9.         }
    ! E4 m. ]" Y; d8 \! k! ]
  10.     }
    6 J" a* w- A/ {' }1 @/ M
  11. }
复制代码

8 j# N6 [6 h; o2 P6 C5 L: Y. W/ Q) ?: g( m$ v, J- r$ f
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-20 02:57 , Processed in 0.063276 second(s), 23 queries .

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