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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

! q0 k7 R4 e; R5 i6 ~: K8 H
  1. <div id="app">. J9 b) E3 R6 K! D) D( ]
  2.     <runoob></runoob>( x  r' v& S2 R8 h! P. ?
  3. </div>% U" L. e, }2 P. T

  4. 1 g/ |) P1 _8 t" c5 v8 O$ O
  5. <script>1 N! B6 M# R# H$ i# Q9 U6 s/ R
  6. // 注册& u3 `; e4 M  r$ F
  7. Vue.component('runoob', {
    & l$ g7 [2 H) k6 i) D' j' X+ h4 p5 B
  8.   template: '<h1>自定义组件!</h1>'* ?" P. S9 @" K0 p
  9. })
    9 [+ i& [8 z9 o! D/ n" b/ M
  10. // 创建根实例
    0 h  |* V1 K' m9 H1 J% h+ L
  11. new Vue({
    9 @& l  Q* m: q; y! Z" H: \. r! w' u
  12.   el: '#app'
    ; p4 D, K6 x- w! m& B6 x
  13. })! l! \' y& A4 W" C! Q! T
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
+ E6 |: o) K4 G9 w
  1. <div id="app">% o9 r3 E9 v- J: i
  2.     <runoob></runoob>
    ) M( B1 U% A/ a' \2 O6 s
  3. </div>
    1 H; j; N9 H6 B2 s) i/ g1 E/ U1 i

  4. * T; d- c5 M1 d% U( g" M' E
  5. <script>
    & b3 k- u  Q* {! ^
  6. var Child = {5 O1 x4 O# c- ]# |7 g; q+ R0 U
  7.   template: '<h1>自定义组件!</h1>'# ~: L3 `4 ]9 ~, X
  8. }% z% l1 G$ e* ?, ], @$ J8 t$ N! a% c0 _
  9. ) u( T, }+ x& Z( N
  10. // 创建根实例4 }* M$ B  A% f+ J
  11. new Vue({
    % f; O5 D; W# u% h0 V: I' G3 ^  d
  12.   el: '#app',
    % h. l& r8 [2 z7 ~
  13.   components: {
    : ?( Q1 O  f3 d& H% s& F2 Y/ c
  14.     // <runoob> 将只在父模板可用3 ]1 F$ K6 q2 P! R
  15.     'runoob': Child
    ) x4 i# f" v) H8 P
  16.   }
    ( e: w" ^  R( G: B- _
  17. })
    3 F9 q( ?' G$ Q- D7 ^% ?1 `" p
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例# X) |3 k& W$ b) g1 Y) M- {) r$ }
  1. <div id="app">
    - ~; L0 a2 W/ h0 u! _% t3 E
  2.     <child message="hello!"></child>. Q6 h% I# _" w9 O8 u
  3. </div>
    6 ]' V' [' y5 I" \

  4. 9 J! i+ y  T$ N: g6 M; h
  5. <script>% l0 c6 @( k* k4 y1 ~
  6. // 注册
    4 F% p5 h0 p: p( a2 c4 m( ~
  7. Vue.component('child', {
    & A+ C. V" W# S+ j, _
  8.   // 声明 props) H/ X( }; \+ x& y
  9.   props: ['message'],
    ' B6 W' l; q( X
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    0 D1 a! N7 R" Q7 V8 m( C" f! Z
  11.   template: '<span>{{ message }}</span>'
    2 G5 [1 j2 o$ H7 t" T
  12. })% s/ X- F6 x- E3 M7 R
  13. // 创建根实例* c" o& s4 Y3 L; U. ?" l
  14. new Vue({" |: X, H3 I7 ^- o& k& |
  15.   el: '#app'0 \; e; M9 c1 t; O# v7 D# H
  16. })
    . F5 d  |, h) r+ P& F8 {3 X  }( F
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例. t8 A0 ?3 p( o
  1. <div id="app">! f% |" J- R# W  c# X  A9 U! o/ d; A! ~
  2.     <div>) f, e2 w8 Z( @2 `
  3.       <input v-model="parentMsg">
    : l# ]( Z" D) J) r
  4.       <br>
    0 O- t0 G# j7 P
  5.       <child v-bind:message="parentMsg"></child>; {$ F. C1 }5 Z( n
  6.     </div>
    5 n: i% V/ A& Y& \. f3 P# F0 L
  7. </div>5 y% W" a. Z& t, U
  8. % l( T) `* }/ [8 o& P
  9. <script>' I) f  K' @+ V5 s# T6 w
  10. // 注册
    3 V6 \9 k! W  U: c
  11. Vue.component('child', {
    $ I2 v- Y0 F4 H* f; `- L, e) _
  12.   // 声明 props
    7 U$ t7 ~- t/ ^% [/ K! |7 t
  13.   props: ['message'],* f5 Y4 {/ q; P' ]. \
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    + A& k: d: D% G3 R: i
  15.   template: '<span>{{ message }}</span>'
    0 C% _  Y6 k% D; x
  16. })5 L+ p0 r5 N' q: I( P
  17. // 创建根实例- m" O6 K4 F6 k/ K. ?% w
  18. new Vue({7 _1 }" Z1 ~8 S- Y% U
  19.   el: '#app',
    6 m" Y, {3 [' q* w! E
  20.   data: {
    & D2 b0 O7 T4 M+ Y& M$ _6 u
  21.     parentMsg: '父组件内容'
    ' C1 O1 \) E4 Q1 m' i
  22.   }
    / e! |: T4 m7 d1 \% ]
  23. })8 C" b( J1 S  l, u! ?: L
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例* n% e& ?+ r( ?9 [: ~
  1. <div id="app">/ m3 @# ?$ z! y% T0 k
  2.     <ol>8 x! V, O: \/ D2 w4 Z
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>9 K' p# y+ f7 _$ k3 l
  4.       </ol>
    5 }. V) f$ X! ?' f# [0 Z
  5. </div>
    ) w" c3 W: v2 Z; k: k
  6. * t3 M4 L  ]/ p% D5 F
  7. <script>
    / F# v& e+ _4 R! W5 Y3 s. m+ L
  8. Vue.component('todo-item', {' G0 a; M  M. L# J' L' {) A0 ~
  9.   props: ['todo'],
    5 x$ [( E8 B* Q9 g5 `3 ]8 L
  10.   template: '<li>{{ todo.text }}</li>'  s$ ^5 g6 H, k6 H0 Y
  11. })
    - W+ R# j8 J$ ^5 M1 _
  12. new Vue({* y+ r2 @/ M- R  W3 {' i
  13.   el: '#app',
    9 I# D& n! n6 z9 c5 k4 d5 {
  14.   data: {
    / }+ F5 `3 L) o! y" K* ]
  15.     sites: [
    , n$ U% b1 _- T' v' [7 m
  16.       { text: 'Runoob' },/ ?! ?- e' o# j
  17.       { text: 'Google' }," M0 }5 l8 O1 h3 w! g+ Z( J
  18.       { text: 'Taobao' }: g1 K6 D$ m; a1 m6 b9 T; Y' b
  19.     ]) E. F0 v' |! Y. E
  20.   }
    5 M2 W1 V- ~! `+ T  r
  21. })7 t' [+ t1 F* C
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    0 i; w, k5 J8 B; y8 Y1 q
  2.   props: {7 @% A9 |2 \6 w4 Y
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)2 N" G) p/ u9 y1 S, T" A
  4.     propA: Number,
    * ]" ~( X6 F0 a& g2 Z: Q
  5.     // 多种类型
    2 z2 H# D" e( X
  6.     propB: [String, Number],; N. H4 |; Y3 p1 _" r3 w  e
  7.     // 必传且是字符串
    2 R: {6 ^  ]' w& r
  8.     propC: {$ ~. H+ {* _( l& v. Q) c3 p
  9.       type: String,- |9 \8 D" {7 Z
  10.       required: true
    # q* i, V2 Q  ^8 W
  11.     },
    2 I. n6 C  }% j0 q
  12.     // 数字,有默认值
    1 J; r& P; l2 {3 \/ r3 c9 O$ ?
  13.     propD: {
    , _$ f6 X. b3 @9 Y$ g4 O
  14.       type: Number,0 P4 u: S8 h6 D7 m$ a; v
  15.       default: 1005 N; m; p0 N+ s- {9 J) G& _
  16.     },' ]. U; I" a) c  Q
  17.     // 数组/对象的默认值应当由一个工厂函数返回" W+ _3 ]- W1 t. b8 o
  18.     propE: {. Q( V( Z4 F6 z
  19.       type: Object,
    ( n9 e5 @) F+ f. n
  20.       default: function () {
    4 S- K: \- b1 B0 D2 x/ ~
  21.         return { message: 'hello' }
    / X1 a5 w/ x; a! c0 |
  22.       }5 ~3 Z! U& h* h. a8 J& A6 F
  23.     },% D8 @0 [( E( }. l8 r
  24.     // 自定义验证函数% S7 G1 [- j/ n5 O- m' R& A) a; S
  25.     propF: {% M1 w' u7 R  V. y, L
  26.       validator: function (value) {
    3 t4 Q+ g6 `" L& |9 p
  27.         return value > 10
    7 u) Q% i- Q7 |$ E
  28.       }( R. g) J5 \9 }2 Y0 A( w. v1 d, i
  29.     }5 R( V; `0 ^  _$ a
  30.   }
    ; A' x+ J( c4 k) |& ^; M3 R, Q% x6 r
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    0 G0 s& n4 S* K( G7 E) j
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件9 M; u( J2 \( v& {2 n; T
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
9 q( E1 W6 k4 T. F: d5 Y
  1. <div id="app">
    , i$ G8 X, ]8 @9 U
  2.     <div id="counter-event-example">: c6 u' J/ Y1 d) w, ~. t* [
  3.       <p>{{ total }}</p>, c9 U% @% O& m$ B3 ~3 j5 ?1 p
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>5 ^0 v& J$ r) o
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    - L9 |* s$ G" f# c9 P
  6.     </div>1 m7 @% k/ n+ C3 P, q/ a. _
  7. </div>
    1 k) s. K  e# M! L/ a4 J# {

  8. * E' J# I5 v: |- I" q" j: k- O) _& q
  9. <script>$ s# H& n* h1 {: u7 x1 I
  10. Vue.component('button-counter', {
    # A8 q5 @/ A' r2 o* {6 A
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',0 ?; T# C5 F/ x6 W8 C
  12.   data: function () {4 s  n  v- H# K# `- v
  13.     return {+ f; b! W7 t8 O% f! @  t0 L, Z# s
  14.       counter: 0* P5 `% f9 T6 Z( }- Y0 A# s
  15.     }
    ; j! Z, ?0 E  r0 [& V4 G# M: \
  16.   },
    3 U% \- U8 U/ h' p
  17.   methods: {# L2 F9 g9 s5 G  e; L
  18.     incrementHandler: function () {: l3 H# a6 `8 p
  19.       this.counter += 1) w+ }0 A/ i# J
  20.       this.$emit('increment')
    $ ^# X  ^: {  r4 }% V6 n+ b9 m$ u
  21.     }
    2 H2 T$ Y( w$ m  m7 T" e( L% }
  22.   },
    ; W$ ?, m! U! r1 v% s0 g
  23. })
      [) f1 T0 Z3 E* \$ b0 H/ `& `/ h
  24. new Vue({
    2 n7 r9 D. ]: S5 w, l
  25.   el: '#counter-event-example',
    % \! p  }. B  H( N5 z! a( o  g3 _
  26.   data: {
    % t" L. ^/ s* p8 G7 F: ?9 ?& j! n
  27.     total: 0* ?4 o% k& H4 P" j7 T, R1 x
  28.   },
    4 F* z& R. C) `1 g8 a7 b
  29.   methods: {
    1 y* k) B. B' L6 L9 ~
  30.     incrementTotal: function () {
    / M/ [! ^  ^4 ~3 W
  31.       this.total += 1
    ; Z& Q) @, ^$ L: n6 S  }* H5 \
  32.     }
    , v' L' [( y- m- u% A
  33.   }, G7 E3 g: m" B3 h
  34. })) K5 X3 ]1 L1 q- P2 \! V
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册% i9 ?6 u9 Q7 K2 L% @
  2. Vue.component('child', {
    : c5 M0 O$ b- P; o7 c9 U
  3.   // 声明 props
    ; j& E% b3 G, X3 l/ o
  4.   props: ['message'],3 Q) X5 Y+ z# Z; ^9 t
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用& k0 [0 R$ \. M6 J4 ^) a0 ?
  6.   template: '<span>{{ message }}</span>'
    6 E( J; q* g* F1 G/ L
  7. })9 k6 l" ~' c+ ]; U$ d0 u
  8. // 创建根实例* A! a& e& j/ t
  9. new Vue({- l# ^3 D4 P; E
  10.   el: '#app',, {* l2 H; V/ j: a9 P  p( ^
  11.   data:{
    " t% n( i9 }. c: G' T% O$ x, }. K
  12.     message:"hello",. [. s3 r7 ], S# X! H
  13.   }+ S" r7 n! C- A- Q+ `0 a9 Q" {
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    6 t6 i0 o6 F5 s$ B
  2.     incrementHandler: function (v) {
    1 ]. B4 X: g7 C2 G9 S. k
  3.         if(v==1){
    7 m, W! `) [0 y
  4.             this.counter -= 1! R( v& S" g/ r6 r
  5.             this.$emit('increment',[1])8 M: f; d, i! y5 t2 T8 o
  6.         }else{0 i0 m9 _9 {6 j( M
  7.             this.counter += 1
    1 D' g/ D- y* S4 O- ]" t; H. @, J! q
  8.             this.$emit('increment',[2])3 C+ p6 X- C0 i/ n& C% x( |: }
  9.         }
    # O4 M7 a9 n2 R
  10.     }
    / J4 Q2 I- k' k- B5 s- T( e* H7 V
  11. }
复制代码
) x" O  P; [0 o

* A% o+ ^$ a: J5 Q6 `# e# n
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 21:16 , Processed in 0.123178 second(s), 24 queries .

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