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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15206|回复: 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,并使用它:
. s! v9 o. @+ `; {: x5 z, O  f8 u9 S
  1. <div id="app">
    . P. {# X0 ?7 k1 M) M
  2.     <runoob></runoob>
    2 t; H4 _4 ]) u6 N0 R) s# G
  3. </div>
    + H; P* O1 B, Z/ ]7 F) ~7 j2 \

  4. ; ]( ?. j- e! }+ I1 Z2 B: }
  5. <script>
    / F; c, a; ~# P6 q/ X# N
  6. // 注册
    / {7 T1 i9 g( g- @0 k
  7. Vue.component('runoob', {1 K+ N8 U- k, W0 g
  8.   template: '<h1>自定义组件!</h1>'
    ' N! [7 M; f% l4 o; D
  9. })
    ! u/ {1 F5 Y+ d0 h2 m
  10. // 创建根实例: T( o4 J" s* H
  11. new Vue({0 e8 ?# X/ }# c% Y* v# r' q) @
  12.   el: '#app'9 q8 t: j) k2 c9 g
  13. })
    . k  b6 A  Q& u2 E
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
( K# L5 H$ Y' V
  1. <div id="app">
    3 s1 ]/ p- m! b: p& d
  2.     <runoob></runoob>
    3 d' R, R2 }( t, q* J) i7 T
  3. </div>  s  j" F5 A6 N/ M* m9 o

  4. ( T+ b, ]& m/ e. K4 u  |& |- y5 \
  5. <script>3 ]+ ]% A: m" {& R, ?$ o) V5 r0 L
  6. var Child = {8 R9 L5 N6 X  e/ `
  7.   template: '<h1>自定义组件!</h1>'1 u. {; C' |5 I/ Z% c( r) f7 M
  8. }
    2 R3 y* f' s  E% a

  9. 4 _- O0 J2 y- I, G5 A3 N8 q8 ^
  10. // 创建根实例+ T* y5 a6 K9 _# ?2 u
  11. new Vue({
    " d/ ?! z4 W! P1 {9 b; H
  12.   el: '#app',
    ) k0 a9 m  S0 ~' R
  13.   components: {+ \3 R) s7 o- @9 ?4 R7 P- l0 v+ A: Y
  14.     // <runoob> 将只在父模板可用+ L# p6 _  p& U5 W4 U
  15.     'runoob': Child
    ! c4 ?  W, w" F
  16.   }. a  z1 g& L6 r2 T6 t; C( ^# T
  17. })
    ( {5 E- c$ l* R. y2 {$ `9 k
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例! o  ]& k5 o) z6 w$ l) e/ j
  1. <div id="app">' s& |7 G" T  q& s' i, k
  2.     <child message="hello!"></child>
    , b# o9 ?( O0 r/ f: `
  3. </div>+ a) @: z. C2 o; A- I0 O
  4. # h) c+ T& S0 Y* y' I3 }
  5. <script>
    : q: D; S5 q% H* C) g
  6. // 注册- ~6 T% V' [% H% P
  7. Vue.component('child', {
    % U' r1 l3 Z: F: j. ]' Y" b  t9 A
  8.   // 声明 props
    2 L/ |0 v2 A4 l7 W8 t1 V
  9.   props: ['message'],0 q) k4 {' I0 N+ Q1 O/ D
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用& O# b1 }! B7 q5 C0 F- l
  11.   template: '<span>{{ message }}</span>'6 \1 R& a( a# O
  12. })
    % a7 D' {; a6 s& a
  13. // 创建根实例
    ; `9 V9 P6 X6 F
  14. new Vue({
    7 o2 g8 [2 s$ l3 P& T1 C
  15.   el: '#app'
    1 {5 L2 u  s; E5 E$ ~
  16. })
    : E( u+ V  M8 J" K$ {, _5 h7 q
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例" D0 y, {. [& Q1 L  m
  1. <div id="app">
    ! {2 b3 T. `- u: d  X/ L
  2.     <div>
    ; P% ]' y$ y5 s" ]/ L2 m
  3.       <input v-model="parentMsg">
    + U9 G+ L8 `" J# i
  4.       <br>( M! k) L8 i' }) g0 e4 l- h
  5.       <child v-bind:message="parentMsg"></child>
    : V$ s- m3 t8 `$ f, G/ g$ n& m
  6.     </div>! x) E! Y0 Y9 [7 u$ D3 L
  7. </div>, f4 G+ w' }/ R% B8 I* i
  8. 1 }8 [* r0 V4 M
  9. <script>
    4 X/ M3 d- |  L; D
  10. // 注册
    3 L$ W- u3 a) c
  11. Vue.component('child', {" P' E- L9 ]0 i
  12.   // 声明 props
    / p' k( T8 T7 j2 P& @. n9 S
  13.   props: ['message'],' t  g  B' f9 M( v& j
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用3 Z3 x+ x5 ^& o9 W$ ~1 B2 l
  15.   template: '<span>{{ message }}</span>'
    ; A4 r6 F3 a  z. D- [; a
  16. })( ^5 x$ c" U3 r# g
  17. // 创建根实例
    9 S* z$ w- A, `6 @
  18. new Vue({" {; E/ `+ F5 [8 \3 N0 ?
  19.   el: '#app',
    ) {) k" s$ a' J5 O+ K7 Z7 ^* Q
  20.   data: {6 A: b# E& A+ d4 }6 g/ F' ~
  21.     parentMsg: '父组件内容'% F4 b' h% I  ~+ a' X; \/ f7 Q
  22.   }
    , H3 e- S$ l/ ]$ _" E
  23. }). G6 R* S- }3 G" e$ J- R! n
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
# ]3 [, P/ J: _& ^3 ?
  1. <div id="app">; l8 l6 k, D  k9 H- p5 P
  2.     <ol>
    0 y8 j  i. c$ e5 o5 ~
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    1 e# q2 }* v5 |+ x* ]  v
  4.       </ol>
    * V. ]& A& O, K+ I' _
  5. </div>7 S3 B; V$ Y5 R  C% V
  6. . M0 a( P  w9 _% d& R+ `) @
  7. <script>
    6 _6 C3 B& l8 g- P& u
  8. Vue.component('todo-item', {
    9 X3 T1 e# o8 |: T  z
  9.   props: ['todo'],3 E8 s2 ?$ O0 E' L
  10.   template: '<li>{{ todo.text }}</li>'& o1 }, j7 g% M( h
  11. })
    0 l2 g6 ]* ~5 b! M2 D2 ?- |
  12. new Vue({
    * \, {/ o2 i0 v+ q; h2 T: n5 C, @
  13.   el: '#app',
    - {! R3 A9 w8 h: }
  14.   data: {
    2 n6 T: G- ]( A, K
  15.     sites: [6 \, p' c# X' f- s  B! E4 q5 l
  16.       { text: 'Runoob' },
    ; Q9 i! U% p6 l3 [# F% A9 k+ ]
  17.       { text: 'Google' },
    ! Y! h( M8 y1 ^' A
  18.       { text: 'Taobao' }) Z6 b  U6 K0 V7 }, G/ G$ a
  19.     ]
    / a" M/ A* h; K9 Y  n# K
  20.   }
    # v: d: D. }& b4 ~$ S
  21. })9 x: h* B2 }* \7 L
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    6 a# M  |/ L, t4 Q7 `
  2.   props: {4 `9 U4 y* J: t0 Z8 [2 a7 ]
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    8 S$ n7 s, U6 m  F8 G' i
  4.     propA: Number,
    & V$ h0 K7 m+ U% L
  5.     // 多种类型& S. a( `0 o% X: F+ P" u0 H9 q5 M" y
  6.     propB: [String, Number],
    3 _1 b# A8 B2 [2 D  m
  7.     // 必传且是字符串
    ) _2 w5 r2 Q9 D9 Q' r+ A
  8.     propC: {
    2 b8 R) r3 p) ~& a1 r
  9.       type: String,: R9 i2 O3 m% t' g
  10.       required: true- G- Q1 o" Q7 S  W
  11.     },
    : c4 {4 N# Q" C5 }; P( b3 E
  12.     // 数字,有默认值5 q9 G6 o, O) @8 |
  13.     propD: {7 @0 B4 V6 I9 g* O
  14.       type: Number,
    8 K* i0 k7 L" O$ J% ^
  15.       default: 1009 a. G$ R$ T4 n9 y2 Q5 C
  16.     },! u6 |; |) _  |8 T
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    ; U4 Y% X* Q. @$ i) K; P' Y* x
  18.     propE: {4 a1 ?  s5 m3 y
  19.       type: Object,( y% n( {. I8 o# N
  20.       default: function () {
    # g9 S" t1 I% a5 E( z
  21.         return { message: 'hello' }* `* {& K3 G8 \; X0 @' h
  22.       }
    $ h% D' e: c: S" I- n+ c
  23.     },* `9 ?3 U8 t3 D* i* Z  j
  24.     // 自定义验证函数
    & V/ D* r9 e& {8 w6 [/ o
  25.     propF: {
    6 Z2 W6 i" ~4 R8 f3 g
  26.       validator: function (value) {% J" I  W4 t! _3 v# I
  27.         return value > 10
    . q! j2 J( U- E! |# t: L! e6 s; g
  28.       }
    5 {& O: ^' N; K
  29.     }5 {; z% `$ H4 t7 |
  30.   }
    ) @9 d; u' {! ?. j. m+ K0 [4 V
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array7 A( t) d7 q. I) E9 s
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    , Z  x1 R  P" r# o, g
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例. s  Z6 A9 n3 I+ q0 E1 G: J: w! P
  1. <div id="app">
    7 i2 e9 A' h8 m& S. X  N( {9 [
  2.     <div id="counter-event-example">( l0 G6 S) k' ?# Y/ W9 ]
  3.       <p>{{ total }}</p>6 ?* Q2 d$ U; M! ^, ]
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    ( L  C% o5 R4 \8 R( t
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>2 x2 e2 ?6 Z7 g+ G6 o
  6.     </div>4 y+ \! E5 Z9 m* G% n5 ~
  7. </div>: |  p3 N- ?: {
  8. . x( Z* F, f* f2 I# D
  9. <script>
      o/ |- |; A( Z- r1 M
  10. Vue.component('button-counter', {" k. f$ @+ J$ r. z6 C" Q
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    : E2 {6 k1 q+ b, l1 g
  12.   data: function () {
    8 s5 B3 K" Z/ s- C' G: o
  13.     return {
    0 S$ Y( V2 X' I- Y. a& m/ k& _9 A
  14.       counter: 0( u2 a' Q: M& J0 J* B' ~5 ~4 _7 w
  15.     }; n, u! y' ^0 C9 o
  16.   },! U1 U0 c( E. Y: t6 U# O
  17.   methods: {& r3 ^* T$ x* N5 O2 A
  18.     incrementHandler: function () {
    + u( d# }9 i1 F. x% e8 r0 A& p
  19.       this.counter += 1
    ; K! G( `' }' _* I3 ]$ Q
  20.       this.$emit('increment')# @3 J0 Z  G( Z1 S, v( F/ \
  21.     }
    5 x9 x  j' e/ U% A5 J$ Y4 s0 K1 \
  22.   },6 i( N) N- l+ V4 c: i
  23. })9 x* @. \$ x% j4 t, I1 l+ ~$ K
  24. new Vue({% \. p" G) W! X; \9 a, v
  25.   el: '#counter-event-example',
    5 W" U% Y. x# d
  26.   data: {1 c( I9 d; V2 R; y6 n7 M
  27.     total: 0' Y' _" |5 N& ]' W
  28.   },$ I5 b2 a3 l5 ~( R5 j: \8 m0 l( b
  29.   methods: {5 H+ L  a# a" q$ P1 o8 J
  30.     incrementTotal: function () {6 v- {  D1 [7 P  z, B
  31.       this.total += 1
    ) Q( R$ d5 q* a8 u
  32.     }1 o  x7 m$ F6 |  ^% h
  33.   }
    + n0 E$ c$ m3 ^" A% O3 f2 H4 b
  34. })6 q6 j# ?+ v% C- w) A
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册. |1 V, Y- T( K% }2 E
  2. Vue.component('child', {
    ) G, j, L4 g0 U3 ^  V
  3.   // 声明 props; K( }1 H2 C+ o, Z' X6 c% h8 n
  4.   props: ['message'],
    + D3 }2 d: T9 Q% {
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    2 q$ ]- u8 A/ Y' `% Y
  6.   template: '<span>{{ message }}</span>', m2 @, c9 v) X( n% \) ?
  7. })
    + J. j; `+ k. [& Q2 \# I
  8. // 创建根实例2 R+ n6 J$ X$ s0 `
  9. new Vue({
    # S! ]  m) F7 F
  10.   el: '#app',' F5 z& ?, V( ^" O3 S& o5 `
  11.   data:{
    6 s5 d* X% U8 i$ u) k9 B, I
  12.     message:"hello",
    # d3 h6 u( y% U1 \3 t5 l6 y
  13.   }  C2 S+ `9 T/ j2 g# [
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    , O3 Y0 ^' H8 q+ L* ~
  2.     incrementHandler: function (v) {
    ! U2 F! j9 |# l% ]% j5 c) E& A
  3.         if(v==1){
      s" R  D4 |/ L! X/ a
  4.             this.counter -= 1
    ; m; r% J( U( Q9 \; w' ?" D1 R) m
  5.             this.$emit('increment',[1])
    ; O2 o4 q3 Y  p# @7 q: }
  6.         }else{, c" x# _3 M! B" O8 o/ M% Y# T6 Z
  7.             this.counter += 1
    9 j: n4 F$ A! _
  8.             this.$emit('increment',[2])' \9 a( f* y, W) M  f. a4 O9 d
  9.         }* k  z( g9 }; j3 o8 N
  10.     }
    # c7 W) S, l& y9 g
  11. }
复制代码
$ J" j0 A8 r/ K! D4 b6 B

' ]5 |' t1 m+ h1 w/ q
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 14:31 , Processed in 0.062730 second(s), 22 queries .

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