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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 12774|回复: 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,并使用它:
4 j! G& B# A1 m% U, E+ l$ U
  1. <div id="app">
    4 m3 f4 J! i) }& [+ A4 E
  2.     <runoob></runoob>/ U4 C; A, b2 w% _
  3. </div>0 a0 Y$ Y$ {. G- D
  4. 1 R; o: [. I- j3 W- |7 u+ D
  5. <script>! A' y! u6 g. Y3 Y
  6. // 注册
    9 F! x& q; A" J  N# }
  7. Vue.component('runoob', {
    % W1 S" n/ N) Q2 C
  8.   template: '<h1>自定义组件!</h1>'. x& w, k" Z2 p0 u1 b# s
  9. })
    + ^4 h2 C; X. k/ T
  10. // 创建根实例8 B/ ^( t4 l* m- j( u: M1 @! n& |
  11. new Vue({
    , }2 r* d& z3 x" r8 M" t
  12.   el: '#app'
    / Q2 `$ M9 ]8 D4 W& U. n1 x
  13. })
    + [) ^$ q$ T0 B) t: g' m" N) n
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
3 i7 H: ?" t' |  i" U; l
  1. <div id="app">3 e" x0 K3 @* D% r; `$ [
  2.     <runoob></runoob>' d' f  |  j# l: e/ ]
  3. </div>9 ]7 ^+ |( x6 v3 l- d
  4. . d$ ^  ~0 k' O
  5. <script>+ j& f5 Y' b6 b0 N: p; Z
  6. var Child = {
    # L5 z2 K/ Q! q- M4 D
  7.   template: '<h1>自定义组件!</h1>'
    5 V' K# G' U$ Y7 a& p6 O
  8. }
    5 ^# M2 }( L3 C. E+ q) N' U
  9. $ j; l4 S9 O! S
  10. // 创建根实例, ^4 w# e4 j3 ]- M' F. b2 V
  11. new Vue({
    7 b+ X9 ~  e# Q9 g# T' ^
  12.   el: '#app',; D: \2 J; \- Z( H, h8 T
  13.   components: {$ l! ]$ R1 K5 S, v% D6 z  A( _
  14.     // <runoob> 将只在父模板可用8 l! _9 s! a0 \/ f
  15.     'runoob': Child4 D; y' o0 f& M3 c
  16.   }
    & J# F1 Y: n% J# l( r
  17. })
    " ~. P4 S- d! g- ~$ T2 M9 P
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例, I0 }+ z! ]3 d4 T
  1. <div id="app">% I* s1 h0 v! b- g
  2.     <child message="hello!"></child>
    + l: ?8 T/ ^$ J. l0 u
  3. </div>$ q2 n' L7 L1 x
  4. ) l6 u  {1 ^2 V5 @
  5. <script>0 O0 B+ m, l3 C9 {
  6. // 注册
    ( W9 G) t; A4 }5 z$ Y
  7. Vue.component('child', {  W. h5 c  S& h/ Z+ c
  8.   // 声明 props
    0 F) I7 ~( {( E. h& @& O( g7 T1 j
  9.   props: ['message'],* @/ i5 Y/ m0 t  P
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    1 z) i+ T6 l( R) b
  11.   template: '<span>{{ message }}</span>'' Q0 q) |3 ^: X0 _  V
  12. })# z/ [0 V( M) D& {
  13. // 创建根实例" q* w7 H8 r. a6 f* X
  14. new Vue({( C' ]5 y* t2 X2 p
  15.   el: '#app'# j+ F3 w- k  G; _$ V* q# s) v
  16. })- o5 B# o4 K/ d/ c( w9 U+ Q
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例, `' c. N2 Q3 y3 _8 O6 y
  1. <div id="app">
    # o- g6 b( Y$ ]3 u
  2.     <div>
    . Y  J; ]+ m5 ~+ w! _$ t9 l
  3.       <input v-model="parentMsg">
    , D) u) X* C$ p& p7 F8 z; z
  4.       <br>2 }2 r- D+ @: W# b" L
  5.       <child v-bind:message="parentMsg"></child>/ \' H4 J7 a8 r3 F" j
  6.     </div>8 k7 J) X. ^. {) b
  7. </div>
    ' w0 ]+ O4 Q6 h
  8. 5 @/ K1 s7 Z; k. ?6 ]0 r
  9. <script>
    7 X% z- J& a3 ?9 _: c( ?
  10. // 注册( y9 _+ p, f) D7 Z; Q7 U3 x( a
  11. Vue.component('child', {+ Z7 h; w' R4 K+ F4 f  o5 f. n
  12.   // 声明 props
    # v' a7 p4 r/ _/ }
  13.   props: ['message'],5 U( i( w0 w. Z: L: @: O
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    : Q% u1 u+ Y# \6 e7 U
  15.   template: '<span>{{ message }}</span>'
    : i5 Y* r* K4 Q* n9 _- |* }" _/ M
  16. })/ c+ \; |" i8 {. [2 C( }
  17. // 创建根实例
    4 \4 j  X7 U+ J5 j
  18. new Vue({
    7 U5 f2 ]# q: [( ^- v( ~4 v
  19.   el: '#app',
    * D) ?) N* m1 n& S% x7 N! Z
  20.   data: {
    / b1 s9 {) N- w
  21.     parentMsg: '父组件内容'
    5 G' ~5 ~6 l8 o& g% V0 P
  22.   }5 T* R" b$ q1 E+ Z" P- G) e
  23. })% Q' A" D3 G' x) m, p- ~
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
& e- c# O# \, K' y* ~
  1. <div id="app">9 F# b  T( n0 a4 z; c/ }
  2.     <ol>; u% z, j& W3 N, H: H' g8 {
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    ! O0 t  G* ?8 h5 K) u: t3 t; e# ^
  4.       </ol>
    # ?/ y4 S7 S; e0 _
  5. </div>
    1 d& J. n' S$ Y) `2 \
  6. # }  v  p1 ^5 B7 Y% D+ i
  7. <script>' z( v+ A4 y* W0 `2 N, ^
  8. Vue.component('todo-item', {
    % W9 `" u# {1 Z7 `! E0 @. E1 i
  9.   props: ['todo'],7 V  |+ S1 y- f1 a
  10.   template: '<li>{{ todo.text }}</li>'
    2 s  @; q! Z6 C! e5 p2 [
  11. })
    ( j. g4 M+ R6 g& ?- N
  12. new Vue({
    / p6 {4 b/ u9 u" k2 p6 B, R' D9 ?
  13.   el: '#app',6 b, h6 v# v' F. z4 f9 d+ j
  14.   data: {! @: X  U5 Y3 z% m( t1 g2 M
  15.     sites: [
    5 K+ M9 d) F- @$ [/ E# t
  16.       { text: 'Runoob' },
      _4 _+ U7 P3 D- {5 K; B
  17.       { text: 'Google' },# g/ {* c3 i5 v) x
  18.       { text: 'Taobao' }6 c* ]* X4 A& V# B
  19.     ]
    : ^9 ~9 ?  d5 S6 h
  20.   }- w9 e) |( M" r7 O
  21. })+ v' a$ m& q3 w: ?& o' |$ i2 c
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {, c# l+ a) s4 e& r
  2.   props: {  i5 N5 h1 x1 A& X
  3.     // 基础类型检测 (`null` 意思是任何类型都可以): S* J; s" M0 F$ q: v/ a
  4.     propA: Number,1 ^$ ~) N5 }4 @& b
  5.     // 多种类型
    ' \  b6 A' l  Q* {4 {
  6.     propB: [String, Number],# L( z' i' K8 B/ H7 X9 r6 T
  7.     // 必传且是字符串/ f) e1 r5 @/ g- g8 N7 A
  8.     propC: {* |' K# @7 M; j
  9.       type: String,  ~# v. E- y- Y4 G* _2 q4 j
  10.       required: true
    / a  z/ A' f5 u& e: u" n
  11.     },
    & L7 _1 ~4 S( e
  12.     // 数字,有默认值7 A' E! O; [3 N
  13.     propD: {# \& F1 P" f8 g4 [
  14.       type: Number,
    2 k$ a( ?0 l) J# h
  15.       default: 1008 r9 _4 t6 K7 h& v3 u
  16.     },
      A1 P5 `( j. q& t9 T, a
  17.     // 数组/对象的默认值应当由一个工厂函数返回( g* t7 k( ]# l8 s4 b
  18.     propE: {- Z1 Z" R) S3 k( c& ^3 B
  19.       type: Object,
    ) N, n- y* i; F& t; ^
  20.       default: function () {- U5 i. }- i3 h! O. s# M; q; k
  21.         return { message: 'hello' }
    ! b$ l; x& y1 J
  22.       }7 \: B+ H" d) U  Z7 X$ U! w3 ]
  23.     },
    , Z+ N' Q8 m0 U6 x
  24.     // 自定义验证函数2 j4 _9 x4 i+ ]! @) }; J
  25.     propF: {4 Z8 t# h' S8 R4 ]
  26.       validator: function (value) {
    . j& q+ I' p6 E, l6 M, l) O, M' p
  27.         return value > 103 N- U* {  u7 s' p% `& g. t8 B, g
  28.       }
    ; m2 U0 a& x: V$ q  L+ _. ~9 X
  29.     }9 `3 d. v6 m; K* a8 q
  30.   }
    ) N+ v3 S* ^+ Z
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    8 O& ?7 r& Z$ ]9 G! `( S" }* e( i
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    % C8 i* J' v- r( @
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例, K3 Q: C9 I2 l( Z6 r
  1. <div id="app">
    ( q/ I) f) H; ^/ e! D% ]
  2.     <div id="counter-event-example">
    ; r* f3 K7 n! J0 l- \9 F
  3.       <p>{{ total }}</p>
    " U7 z6 r7 n$ G/ o6 f  r9 _- o; C( Q( c
  4.       <button-counter v-on:increment="incrementTotal"></button-counter># O& Z! m0 Q' V+ j& m' h' K; w
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    0 J" [% s& g# ]/ k) V5 e* V  F
  6.     </div>
    * D. E8 ~& g) R" N1 A- o% u/ d  J
  7. </div>
    6 D( w, R3 G  {6 r: ~
  8. . T9 T: c: y% w/ @' h4 P' ^
  9. <script>
    6 {9 @, m/ b) L+ X) X) O/ S0 {
  10. Vue.component('button-counter', {" `9 N" H' u- Y3 Q1 d
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    , |, `' b$ ~3 g  J/ q$ q$ c
  12.   data: function () {# X- A% J# F2 Y+ U& L
  13.     return {
    : D: p8 P$ Z$ d) ~3 `  S1 V
  14.       counter: 0
    - K0 B( P& B3 f  w
  15.     }
    5 W! p1 @- R9 R. `6 q+ N
  16.   },* j3 e2 a/ D- B# ?0 l' g) u4 V) Y
  17.   methods: {
    7 U" M  h) Z# i% m2 _
  18.     incrementHandler: function () {  Z- ~9 C9 h* v5 a) W
  19.       this.counter += 1
    + J' O- p8 F  S" ~6 u
  20.       this.$emit('increment')
    5 G8 b' e% Y+ a: P9 o
  21.     }: L) T& |9 L! h  K# A1 w" I
  22.   },9 w: c! a7 ^8 Y6 l' V  G( C' |' i
  23. })7 [9 @( ?8 L" \6 P2 o5 G/ _
  24. new Vue({0 L0 O% z0 q+ G
  25.   el: '#counter-event-example',- r% I1 c, }/ J/ H: J) J
  26.   data: {% @# F9 O( }9 `
  27.     total: 0
    ; K; ~# N) C- @# l9 I7 u0 h
  28.   },
    * H3 ]' O$ {7 x& w9 I
  29.   methods: {( c) s  B; @6 w0 W# p% _8 i, d
  30.     incrementTotal: function () {
    * T# A# \! K8 U
  31.       this.total += 1. q0 }9 _  ]$ c$ ]
  32.     }! q# B3 z/ b9 b
  33.   }5 u4 c+ v) L4 B, C3 O+ r
  34. })# |: |% M8 s) j/ C8 O  Z
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册  O: h0 I- c/ I9 U+ E- w
  2. Vue.component('child', {
    * Z1 Q& K3 O+ V2 p3 r
  3.   // 声明 props9 l* j' U) z( N$ o% k0 K
  4.   props: ['message'],- c1 l" ?1 i7 N) `
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用$ j* e/ n$ v4 `. r0 @' J7 g
  6.   template: '<span>{{ message }}</span>'
    1 ]% o5 r7 F3 n+ w
  7. })9 O' `+ V0 h0 |2 O$ }) h
  8. // 创建根实例# r6 x4 v. z1 w2 W
  9. new Vue({
    1 h% r6 P% E( m. W2 h/ G0 o
  10.   el: '#app',8 i$ q' R3 D- A& N3 T, R, ^
  11.   data:{5 v7 \6 ?! s* [1 l: C. I
  12.     message:"hello",
    2 [7 z7 k6 V- J- w
  13.   }
    . q6 v# S" T: g% ~+ a7 r
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {  F# I7 _" [7 }1 d$ u" l$ t, l
  2.     incrementHandler: function (v) {) C- x& F7 `8 P% ?, c& h2 U' v
  3.         if(v==1){
    ) l9 q% _4 B5 h- x! @* P
  4.             this.counter -= 1( `9 z1 o/ B+ ~5 x# H
  5.             this.$emit('increment',[1])
    6 B( s# A0 p# B; K" t# Y& M" o1 f* `4 y
  6.         }else{
    / ^% L+ o% L5 Z6 }6 I
  7.             this.counter += 1
    9 H/ D. F) T' A# u' N
  8.             this.$emit('increment',[2])
    & u$ l6 y' j5 m' z" r# [3 _% j
  9.         }! X" D( u8 X+ o
  10.     }3 f8 c4 ]( b! t& h7 H
  11. }
复制代码

8 Q! o( V% D  ]/ N9 J6 @
! q; T* [. p/ D$ H) }$ D3 M* d, F
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 21:44 , Processed in 0.121478 second(s), 23 queries .

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