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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

% m/ O9 s1 d5 L7 F
  1. <div id="app">
    2 R( D1 ^- [6 ?: c6 c5 W
  2.     <runoob></runoob>
    & D) L+ h/ O/ L/ M, y
  3. </div>
    + K& P- p. ?) X0 c; L' p8 M

  4. 9 r9 h7 U8 O9 b; x3 f: i
  5. <script>
    9 |+ _; w3 Z% F1 p. V7 o
  6. // 注册4 i1 s( Y' I$ s4 O4 R* P
  7. Vue.component('runoob', {% q7 t! r) V- u& K4 O
  8.   template: '<h1>自定义组件!</h1>'/ x1 J2 X* ^4 ?+ Z$ W' R9 ?
  9. })# V! |6 T) v2 f2 b+ e( U8 @3 I
  10. // 创建根实例
    & y0 _8 _; _5 V3 R
  11. new Vue({
    7 s/ j  V3 L7 l+ U
  12.   el: '#app'9 L5 H6 p1 h3 }) ]4 o
  13. })
    2 Z) S9 P; R1 Z1 Q5 t4 j
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
/ o: e1 J4 m1 l$ T* Z0 L( V
  1. <div id="app">
    . K; k" J5 @! G) k
  2.     <runoob></runoob>/ `- z: Q* s$ O$ r$ |
  3. </div>1 k: i2 u. H& T8 g7 x$ h
  4. 6 k% e$ Y, q# c9 H
  5. <script>5 r6 ?! S8 Y/ j; D
  6. var Child = {
    ) b, S4 }  {9 `; U+ t- g. P
  7.   template: '<h1>自定义组件!</h1>'( p8 p; o5 v0 d7 [* U
  8. }* ?8 T+ ^: S: c& `" _

  9. ; y' S# e9 l& w, y; a! _4 b0 B& Z
  10. // 创建根实例
    6 v' W! m$ g$ e" E) h, P2 M
  11. new Vue({
    0 y0 S0 B, y+ p& Q
  12.   el: '#app',/ u" a, Y- `% Z1 Z3 U7 {( a
  13.   components: {8 a. H/ I4 o1 x5 f# m# G0 f
  14.     // <runoob> 将只在父模板可用. X6 K8 `' }" S. f
  15.     'runoob': Child6 Y& F7 i) |. o" F6 `
  16.   }
    7 j; j8 N0 l$ L' L- F3 V: A
  17. })
    $ q8 v; q) n9 L9 t4 ?
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例7 C' o# U% G, e
  1. <div id="app">; n! ^2 c# o2 E5 }1 o3 _
  2.     <child message="hello!"></child>
    8 }2 l$ i5 l0 U: l6 p
  3. </div>
    % ?/ G, [7 l: }! S: E, a" ^
  4. * S+ h5 R5 d- {/ t: o+ c, J9 K- H
  5. <script>
    0 D1 ?5 O6 r( }6 C0 o2 n- q, V3 ^
  6. // 注册4 h1 L, o$ D8 M1 Q
  7. Vue.component('child', {; S6 d/ z/ Y; V* m/ w. x* g: Y
  8.   // 声明 props
    0 O' _0 X& c7 l% e" T* b, |7 l
  9.   props: ['message'],
    7 A  t- ], K4 m: d1 a% {0 s; U
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    7 Z4 h6 Q' _8 N+ X7 d$ t1 ?
  11.   template: '<span>{{ message }}</span>'
    . K7 g$ {' r- z1 v
  12. })( B; q4 Y% S( p# j8 p! H
  13. // 创建根实例% T; z5 q  k7 M% M  C& y# {
  14. new Vue({
    * m2 e) W* f  b( b1 W7 w: P; ]( V
  15.   el: '#app'9 s9 E3 C) v! [) [8 C
  16. })/ b, |) }) g# q3 Y6 ^% c, N$ `
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例0 A3 K0 s0 @5 v) g4 `+ w
  1. <div id="app">
    / X: ]8 F1 P( G
  2.     <div>3 v+ Q2 L8 }7 P/ ]
  3.       <input v-model="parentMsg">& @2 e. S& N! n3 j+ o6 {- b. W4 X3 z
  4.       <br>; Q4 E2 W2 s( ^7 a/ @+ h  }
  5.       <child v-bind:message="parentMsg"></child>$ G$ _/ Z6 C  F% ?! k! p
  6.     </div># F. c* v2 c0 l; u+ c  q
  7. </div>: n* o$ C3 j7 C/ @

  8. 4 L* p; A- O8 Q9 f( f
  9. <script>
    3 u. U$ ^# I% E1 H' O0 Z# E& d
  10. // 注册
    8 _, W9 W, D/ M' n
  11. Vue.component('child', {2 A# v8 G) `' h, E" _
  12.   // 声明 props& o: a7 W2 N- E+ J$ u% N) |
  13.   props: ['message'],
    " W; q" t: p6 f; k* D
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用6 n1 i; [* p: L6 f
  15.   template: '<span>{{ message }}</span>'
    7 X. ]3 d; x) u: ~+ H* q
  16. })
    5 j- e( ?" b* C8 C; G8 L
  17. // 创建根实例8 D# K+ j6 V& D$ s8 q! Z+ V
  18. new Vue({# y0 I# M& z9 O
  19.   el: '#app',- |* x' U: x6 }1 {& U# y" S7 p+ E. q
  20.   data: {9 [* f& L+ D& I9 {; q3 N' {; G7 q
  21.     parentMsg: '父组件内容'
    + f, r  a; f1 H' t
  22.   }
    , U" M6 L0 u( a& T
  23. })6 a' j' r( O. D$ o6 i& X' j
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
1 u' i& [% S: \# O  {( q
  1. <div id="app">
    " m* L% n5 r- v1 h' j
  2.     <ol>
    0 w) y0 B3 Z7 j  }, t3 j
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>1 X+ Q" I8 h6 s, Z
  4.       </ol>6 |! I, o1 b9 L( ^- J: ~, Y
  5. </div>
    6 v. Q' x# ]1 ]' D8 |! s
  6. : z( n  ~( f( {/ C  r& N3 Q
  7. <script>% H) ~) g1 u& Y- H8 O# L2 u
  8. Vue.component('todo-item', {* D5 M1 W. g3 j6 r$ b
  9.   props: ['todo'],, }' ^  v) n7 D1 v$ Q7 A7 d# S
  10.   template: '<li>{{ todo.text }}</li>'/ ?7 x& C- O+ i( N% [' ~' e0 }
  11. })
    . u/ |" x/ X- E
  12. new Vue({
    $ [7 E( J1 ~6 d6 L- L
  13.   el: '#app',, R  P5 r$ U- l
  14.   data: {! l: `' V- b" e
  15.     sites: [
    8 {) Z1 o; _9 J; F0 U2 t% u
  16.       { text: 'Runoob' },
    ' T( Y/ s7 {# \( b) J5 O
  17.       { text: 'Google' },$ d. H8 k/ A2 t) ]; e3 B
  18.       { text: 'Taobao' }+ k- u! v3 D" ?! C: V7 O
  19.     ]
    6 y% w6 S4 v% [! Q& @5 s  A
  20.   }
    8 a# v1 v* |4 T) p: o! X0 o5 J
  21. })
    + ?3 b$ M8 k" G7 Z* M- S6 R
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    % ]: {! e! e8 N$ y6 {
  2.   props: {
    : B+ i) j% ?7 e* }4 b" W! \  ^3 x
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)4 F4 W5 q$ z& s
  4.     propA: Number,1 j( s; t, W/ g6 E
  5.     // 多种类型  m& L2 b: ]& ]3 v3 y
  6.     propB: [String, Number],7 i4 h+ A: u0 v+ q2 B9 I
  7.     // 必传且是字符串
    : z* e# V& K* T" l$ [5 E& t
  8.     propC: {
    ) n6 B4 ]" F/ p9 g, C# z
  9.       type: String,
    - c: J" f( P8 n
  10.       required: true
    4 [" e, S) f  T9 H, d
  11.     },  x& J1 Q& _2 e! ^
  12.     // 数字,有默认值
      g' K; r1 C, W
  13.     propD: {' X. T- `" p! R- `, b" Q" E
  14.       type: Number,1 I) Y0 `8 z6 C4 O8 s5 E
  15.       default: 100
    % \- O7 G9 X' v( _9 J( @( U7 M  R& P
  16.     },
    9 Q" v6 k; [  {4 G7 E
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    ' e( Z. m- g: B, }0 q1 x
  18.     propE: {
    6 M9 r  X- s5 ~" V( c2 S6 U
  19.       type: Object,$ J6 p- u1 Q' U, `8 k
  20.       default: function () {6 M% ?2 J3 Y# R6 n
  21.         return { message: 'hello' }$ r# p5 t% i5 P" F0 F: q
  22.       }
    , [. ?6 L/ N  C$ q9 Z
  23.     }," k# i; {' ]' B, b; }9 v  V
  24.     // 自定义验证函数
    6 y. J, p; y$ ?+ k5 {5 f+ N
  25.     propF: {
    " y/ i/ M" `) W* X- h
  26.       validator: function (value) {; a; q, o2 `; c! `
  27.         return value > 10# y( w8 |! Z1 V% g4 ?% o
  28.       }" L# b& Q+ i! n  V: ]/ Y
  29.     }
    5 E2 v' ?9 K' E6 F; B8 v1 ]* M( d
  30.   }
    ' M2 M( T! n4 A: s$ o4 R
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array3 g2 ]2 l6 l3 P, @
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件0 q1 x0 e9 D- w9 O
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例: J! }. h. S6 U2 D& T+ [
  1. <div id="app">
    " U: S1 o# m( J4 |) C1 R
  2.     <div id="counter-event-example">
    * ]1 T, U% @9 H0 P+ t. {/ K& C- N
  3.       <p>{{ total }}</p>" V3 u0 M9 Q8 G, `9 i$ K" \/ P' E
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    + }5 {' q# n0 ^  L, a+ I3 h
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>+ @" Q' z  L: K! c9 K
  6.     </div># W! c3 \2 W0 F3 D0 n
  7. </div>' Y) A  @7 H" ~0 u: G

  8. % W# Q) N0 \! N( X/ ^  s! _- d8 ]
  9. <script>+ ^. X( n; `; z0 L( @4 Z
  10. Vue.component('button-counter', {) B& h9 L( Q+ b5 n" E( }
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',$ P& H" J& y, }% W) k9 C2 L+ \
  12.   data: function () {" O( N7 O5 r/ j+ [' g, R% v; P
  13.     return {9 c7 b5 \& E$ l, d0 f" j/ \1 ?
  14.       counter: 0
    - V" w0 x. V9 {
  15.     }3 K: g& P) T* H* N# `( P1 u
  16.   },/ ]1 i) K! A* y1 W
  17.   methods: {; `3 I% r$ Z" |' S) S1 L: g
  18.     incrementHandler: function () {
    ) i  l* F7 b5 ?1 [
  19.       this.counter += 1
    & f* j. A. Q4 [% k+ e4 l$ [+ o3 b
  20.       this.$emit('increment')5 ^2 ?/ k% y$ J& n4 E
  21.     }, K- J6 u0 l; }; e: o
  22.   }," J3 k# F- Z+ V6 |. }$ f9 P/ a5 F( {
  23. })
      K7 J3 ^0 B  {0 c: U
  24. new Vue({
      Y" o* l" A, x, |. W
  25.   el: '#counter-event-example',
    ' @0 E* ^( h5 l  r9 x4 A8 v
  26.   data: {4 Z4 `$ Z" Z. e2 C/ q& P) k
  27.     total: 0
    ( _  B" y+ c( E6 Z- y
  28.   },1 R( z$ F& o/ C3 D+ v
  29.   methods: {$ @' c$ i8 W3 O/ _; s- q* }2 J
  30.     incrementTotal: function () {
    ! q0 _; |5 Y3 `0 q9 }) f+ j: `
  31.       this.total += 17 R0 @' q* {+ S5 o: K
  32.     }
    . i: E4 k' }1 B6 e0 L5 \3 y
  33.   }4 S: G% a7 Y0 Y
  34. })
    / W9 O0 l7 c$ C1 a" A$ g3 G/ i
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    $ L) R+ S$ v$ C& P& I$ t/ e9 }
  2. Vue.component('child', {: p, ]6 {- t! A
  3.   // 声明 props
    9 L) D2 c$ `3 f% v- M
  4.   props: ['message'],) n- x# u) t# K" W
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ; Y. A( }3 n, x" H% z
  6.   template: '<span>{{ message }}</span>'
    $ V* g( s4 s& e6 n1 ]" h
  7. })* j" a: r9 X. Z) \6 Z
  8. // 创建根实例
    + P  _; T. h3 u. ]- \/ ~# Q
  9. new Vue({; l7 y: H1 I# Z& O
  10.   el: '#app',- `) w' C8 q8 l/ P4 A, f2 i
  11.   data:{% c4 o; v* |, q5 S! |6 D1 O
  12.     message:"hello",
    7 e/ @; a. r1 [7 J+ B  J
  13.   }
    7 b6 K* _" {5 o1 T" M# L2 }3 ?
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    ) |6 F0 _" D+ D) l/ V! F8 H$ b
  2.     incrementHandler: function (v) {  g% D4 G5 Z9 [' N0 }5 Z
  3.         if(v==1){9 w6 \  i! _6 m8 R! i9 J
  4.             this.counter -= 1
    " j" K' f3 K( |& N; m% P
  5.             this.$emit('increment',[1])1 v# W4 S) H, c2 L
  6.         }else{
    : e& ]4 r) u( R1 g% t& h1 @
  7.             this.counter += 1
    6 E' l* V0 j9 [6 V
  8.             this.$emit('increment',[2]); L4 z  o' h! X$ F$ i9 u: R' x
  9.         }7 K+ [- j  c, f, i/ N  \
  10.     }$ l; @3 Q# F; y) f& R, x
  11. }
复制代码

4 v$ F; B' h! }: z) E* m7 p6 ?/ k( l  f, R$ A
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 16:01 , Processed in 0.071600 second(s), 23 queries .

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