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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

. j8 M& H, T* m0 R1 P" Y1 {
  1. <div id="app">; Q( j) K# ]$ ~6 h3 a$ Q3 W
  2.     <runoob></runoob>
    : t/ u1 E2 H: j' ~: `
  3. </div>
    / ~1 c# `# G9 N, I* B; m/ N' `! ^, M

  4. 8 z: `, W2 }6 @1 [
  5. <script>* p5 Q+ U5 y# q4 R
  6. // 注册
    4 Q. X6 Z; ^- W5 C
  7. Vue.component('runoob', {
    * a: O: V& l/ k
  8.   template: '<h1>自定义组件!</h1>'
    + }9 E9 Q9 b" Y( K* n; t
  9. })
      o$ H7 S9 B( c7 r  ]; f
  10. // 创建根实例" U/ `. c+ I0 _) X
  11. new Vue({
    / @: `2 U' b# Q- O
  12.   el: '#app'
      e+ `- e+ t9 d0 r9 f
  13. })) m3 U9 T  @  h* M  _# S
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

! V  ~) N( ~( v: Z& f
  1. <div id="app">
    # L& {9 ]: Q4 i1 d) I( @
  2.     <runoob></runoob>, u6 O* x7 ]( P7 y9 O- N
  3. </div>
    0 }) U( t: W* }( E* @9 _; C
  4. - X; A5 p* G4 Y  g# h
  5. <script># L6 c7 p' s- w! }3 N
  6. var Child = {6 g% C; s9 K+ D6 g% l& l
  7.   template: '<h1>自定义组件!</h1>'0 V1 d0 ~+ a9 D4 |& U
  8. }4 o3 r: ?5 f7 _% Q5 B5 H, U
  9.   H/ s& ]9 E0 q* b9 S
  10. // 创建根实例) H) [. u: }( x% p! |) B) Y7 u; @
  11. new Vue({& V& d% ^, r# n2 l
  12.   el: '#app',' @9 t; ~3 O1 C) a; l
  13.   components: {% t$ E  R, k) P/ I6 x
  14.     // <runoob> 将只在父模板可用
    8 _2 o7 Z; V% L6 l" B7 |5 K
  15.     'runoob': Child
    # U5 a6 X/ t1 K- {
  16.   }4 c6 h; P4 x6 R0 h+ ^* z# y
  17. })% N" g  J0 ]/ Q
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例+ F! f+ m( t/ ~& ~6 g3 S, `1 v9 l, g
  1. <div id="app">
    , e3 Z$ p, G" m9 H0 ]
  2.     <child message="hello!"></child>
    8 {+ U6 Q4 E" F+ B
  3. </div>
    7 i8 J) Q! K& A$ U0 U

  4. ' T: Q0 j9 {- `7 m8 z, s# s
  5. <script>
    ; a; p% I- \& i# V6 X
  6. // 注册+ L. o9 u1 y6 I6 v1 P0 k
  7. Vue.component('child', {; h$ t8 c% I+ f$ F
  8.   // 声明 props  V9 g* y. K* b$ _
  9.   props: ['message'],( W3 p  d4 u! g; {1 p- z# Z4 ]
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    3 m( y4 t) @6 e: @
  11.   template: '<span>{{ message }}</span>'! i" n: q) ]5 d+ o) q; l
  12. }), m  Y; u; u4 y1 s
  13. // 创建根实例$ g/ y* {0 |3 w: {( O+ ~
  14. new Vue({3 U5 z" l: O/ H0 x7 ]. C
  15.   el: '#app'+ F( s0 x7 I6 t9 |/ j! B' e" {
  16. })- e1 [2 Y# P8 S/ @
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例( q/ [- I( J7 g1 r: G7 D' i
  1. <div id="app">) x% w5 y( V0 M. Y
  2.     <div>
    ) n% S% w- `8 e5 u) x. q. g8 @
  3.       <input v-model="parentMsg">
    - m" ?+ O& \+ a( E7 d0 n
  4.       <br>
    ) g9 y. E* P& `/ |+ J. D( R
  5.       <child v-bind:message="parentMsg"></child>; x9 K; L& u) q' z9 i; d
  6.     </div>
    5 \& T7 g. k& |4 M6 {
  7. </div>2 s% |: t' Z; z

  8. . c( c+ G0 \$ X5 v' F; h. V
  9. <script>
    4 n  |/ `1 q7 s3 a6 C- Q8 P
  10. // 注册
    5 T/ }! P. p& ?$ T. ]! `
  11. Vue.component('child', {; x6 O+ e. Y3 R
  12.   // 声明 props' V# g; Z/ L/ @- W: N: m) W
  13.   props: ['message']," W; k; \2 o' d
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
      }$ X3 u. b% i! A/ X' E
  15.   template: '<span>{{ message }}</span>'' s7 u* e$ x: m: O7 s
  16. })
    & Y$ o1 E9 [! m4 N
  17. // 创建根实例& X6 z  ?  j) [
  18. new Vue({
    ( X, u# a/ c! f# m5 x: U4 E5 S, I
  19.   el: '#app',
    8 `. ]0 D+ l" t( q. ^' V$ h- K
  20.   data: {6 M2 E) f1 }, T8 S8 s
  21.     parentMsg: '父组件内容'3 o% y* b2 ?2 d- o7 f' b
  22.   }* q. V+ m4 g9 A0 w' e
  23. }), a# h  i2 N5 {! N; R, x5 [9 O
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例/ {6 l4 a5 k' J8 ]( b
  1. <div id="app">0 H9 M, i& {: [+ O1 I
  2.     <ol>
    + s: v' M5 x- w+ W! F  v
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    , M. h+ v) j# d& }& _
  4.       </ol>
    ) y3 y( |4 }# V9 l! g, o
  5. </div>
    8 _/ D( ]9 Z6 B. x; n2 y
  6.   V9 E$ X, y. E; {' }6 ~6 x' s
  7. <script>" E0 x, h2 G$ I3 K" k# O6 C( r, |
  8. Vue.component('todo-item', {
    4 U8 ]; ~# A6 V' w7 J3 {9 E
  9.   props: ['todo'],
    - m6 H2 Z8 W" K  F5 \
  10.   template: '<li>{{ todo.text }}</li>'% {" b; W4 U8 M% y1 k) K
  11. }); L% T) w6 f' V4 i" {2 Q
  12. new Vue({* {& w$ G/ e8 u, z
  13.   el: '#app'," Q* S  Y  u. Z1 a" k  g- {
  14.   data: {
    ) h5 e' M. E  t( f9 U0 t
  15.     sites: [; X( ?: _+ e: a* z, I+ C* X
  16.       { text: 'Runoob' },
    : y3 \1 u4 K" D" S
  17.       { text: 'Google' },/ Q5 @- W) n+ A3 w
  18.       { text: 'Taobao' }- t9 [. ?% k9 L" F
  19.     ]
    6 D7 J% _. ^" Q6 c5 P' U6 t0 D
  20.   }
    4 K3 v% P9 b9 d
  21. })
      L1 I" [: i) t2 j1 u$ U
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {% `- v( B/ i8 ?7 Z
  2.   props: {
    , @. ~9 \. z  @
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    ' B% M7 U; {  ^' \# Q+ C3 `
  4.     propA: Number,3 e; n) U9 b3 U+ q
  5.     // 多种类型! }' h* E) @, T& l
  6.     propB: [String, Number],* c- W" ^( K: _& {2 d2 V1 V$ N
  7.     // 必传且是字符串
    7 ~, G, {) Y) D
  8.     propC: {, G4 B# V% d) [) G0 f& q3 k- D$ `
  9.       type: String,. }' \4 \# ]# b. i
  10.       required: true. a) x) Y2 f7 I& a+ a8 M  P; S
  11.     },
    + f5 p- b5 z, i1 K& p/ q6 {/ Q
  12.     // 数字,有默认值) s& K0 J5 N1 X+ z
  13.     propD: {
    ) ^0 V- J& G4 S' `8 ^) P" T
  14.       type: Number,
    ' v9 F8 r3 a6 Y! K. W: Q
  15.       default: 1009 v. D3 K+ w; b  E
  16.     },7 a% e+ e! |' o; j. ?8 `/ Y6 ?
  17.     // 数组/对象的默认值应当由一个工厂函数返回5 r9 ~! Q. p% w3 W: g; i& J5 D
  18.     propE: {
    . A# x, r1 O+ f& F6 P
  19.       type: Object,
    - G8 \) @8 d# y* U) Y) ~* [
  20.       default: function () {
    + ~3 a. f. ~6 H1 [1 _! x: F2 C# |0 e
  21.         return { message: 'hello' }6 T! |, y2 o" f  [0 ?( X) j+ B- e
  22.       }
    3 U- I# d1 q+ h, v, b
  23.     },% {* l3 I2 {9 D( ?1 p4 V1 o
  24.     // 自定义验证函数- {/ ~4 @' B0 F" w7 J) [$ o
  25.     propF: {
    & T5 O. h) m; \3 t$ }( W) F" F& t
  26.       validator: function (value) {$ l8 N3 ?  w: L$ f1 ?
  27.         return value > 10  i7 P0 f) H$ j. E2 J
  28.       }
    * f* G& i- l- t+ w/ W! M
  29.     }
    " w  Q0 u% X2 B% {3 b2 H" g( K3 K8 l0 ]
  30.   }  Y! @/ W# z' q0 R" _
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array) n' Y: k- h# q1 q9 `2 I/ s1 e- z
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    ( s: G0 U' ^8 X6 v# K  y& G3 J( q
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例: ^  v  k3 B/ H! Z- v) g! o
  1. <div id="app">
    $ x. W' l2 m9 k$ c% ], Q
  2.     <div id="counter-event-example">& {& `7 L0 Q8 I9 d4 j6 m
  3.       <p>{{ total }}</p>, ^  k; E, h, j0 |: T1 Y, }& o# S
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>; g! U2 U" c( y7 D4 n, r& _! B
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    7 b1 q: C4 M! q6 i; G; v
  6.     </div>* \9 Y$ r; T7 @4 y' u3 v1 F2 M; J
  7. </div>8 t$ A6 P2 \- h. |* h

  8. * h! k- q& t/ i. [/ V7 @3 N
  9. <script>
    ! N. H  m) D1 k" H/ w
  10. Vue.component('button-counter', {6 t( l2 ?- y* [5 q* @5 p3 h; w
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',: q2 x, w7 `* c
  12.   data: function () {# ^; Z/ L5 b  f1 S+ s; q" @
  13.     return {8 Y3 \* T$ }9 f( Y# X: \+ v+ |5 E
  14.       counter: 0
    ' a5 K. @' I; I" W9 E' y
  15.     }
    6 E# n3 V4 k; @7 j
  16.   },$ V6 E5 e% i3 j# i# c! S) j
  17.   methods: {& c; a& U2 w( j; n" k; {' v# P
  18.     incrementHandler: function () {
    ) e% S$ N2 M, f( J- A) a# x- D+ @
  19.       this.counter += 1
    - A+ M0 C7 @! J! O) h) u
  20.       this.$emit('increment')& k; F6 A- M: w
  21.     }+ n' S! a) R5 R' R& g
  22.   },
    ) W3 F; O, r0 `5 J9 a8 B% s
  23. })+ C6 y4 x8 y6 X; R( B( p
  24. new Vue({  I) N$ Z) G" p+ P" w; @
  25.   el: '#counter-event-example',2 r, }5 Z4 x4 M7 x2 H. Z( \, Y
  26.   data: {
    5 K: |- N( N9 o( ]5 z* e3 t
  27.     total: 0+ e9 c. H" d% D0 i$ S# h3 z
  28.   },
    4 g5 {- n- l4 t* Y9 @. V
  29.   methods: {
    * P) ?; k9 v' Y7 L; l, p$ ^
  30.     incrementTotal: function () {! I6 n0 j% E5 V1 F+ ]
  31.       this.total += 15 J6 @1 f4 v9 R
  32.     }
    2 i9 R3 c; n5 \- H9 Y' f- M
  33.   }
    3 @. J3 [/ [# d* _8 |
  34. })
    7 \: z0 p7 G  y! U+ L+ ^+ S
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    3 \5 K0 N6 ?. }! f
  2. Vue.component('child', {
    # [) ^% Z& ]2 F; p
  3.   // 声明 props
    . e2 A$ V6 A5 D' e# i7 a  Z+ _3 F
  4.   props: ['message']," Z# i4 ~- o5 w2 T& o9 E' b/ X, @8 Q) J
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ( w" R6 }) A( T) ~
  6.   template: '<span>{{ message }}</span>'
    / E$ p! Q- C5 h# O$ D  E
  7. })7 A/ G0 ~) g" x  q- V$ y" Z4 L
  8. // 创建根实例
    ) z9 u" k4 H- s8 w
  9. new Vue({
    8 ?1 C5 y- c( C" F% U5 b+ _
  10.   el: '#app',* h- R: F3 k, c  L. B! ]# p0 h
  11.   data:{
    1 c' M* C+ H- y6 |7 }
  12.     message:"hello",+ m& ~" T  m- g6 c. A. \' g
  13.   }8 d' i' C& w- H* G- X" @
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    1 `! S7 h1 L" t5 S
  2.     incrementHandler: function (v) {' u  b$ p) P& Q% Q( S: E
  3.         if(v==1){
    3 A" L6 [4 }% ?/ s1 U
  4.             this.counter -= 1
    9 l% q) c5 i+ }" l$ _: `9 R
  5.             this.$emit('increment',[1])3 v9 j( F5 ~/ h6 g
  6.         }else{5 [, J1 d9 |. w- D1 E) @
  7.             this.counter += 1
    , t- M7 B( t  c
  8.             this.$emit('increment',[2])- g; k( X1 [7 s' m+ |
  9.         }, M- ?5 o1 a! Y  O1 c8 J7 s, }
  10.     }+ {" j4 M0 P1 V; t  G- y1 @1 e4 Z
  11. }
复制代码
# v. F3 M- ^! P5 T
' t# R( P) q( R+ f6 @
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-4-29 10:56 , Processed in 0.135169 second(s), 22 queries .

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