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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15209|回复: 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 t% f9 E9 b* o( g& q1 Z8 ~
  1. <div id="app">
    % V  |8 N5 t' o+ `8 L+ m
  2.     <runoob></runoob>
      j/ l) w1 i8 ~8 B& o, B4 @1 v
  3. </div>
    ; n4 A& R6 f$ t8 h" t" ~7 b% `" f
  4. 9 v& q* ]3 Q4 @- O/ g- G! {
  5. <script>
    & {2 e. N9 V' v' G) P9 p) m1 M
  6. // 注册
    2 y( F# P& h; D7 \) K7 H/ @" l: y
  7. Vue.component('runoob', {
    ) f! m5 {! H, N: S
  8.   template: '<h1>自定义组件!</h1>'
    & f/ l9 N1 T. l
  9. })
    ( `& l! v8 K4 n5 ~9 M1 T
  10. // 创建根实例9 Z7 F1 v- f# w) y
  11. new Vue({
    6 w5 A. ^6 t: _' m& D4 j  @
  12.   el: '#app'
    ' z& O+ x2 n: R4 d" k* O6 O* p
  13. })
    2 n8 h0 r7 P; _2 a
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
4 N. @. O( i- U7 z2 C9 |
  1. <div id="app">
    * k8 x0 ^0 u+ T- M7 r) x( d8 W
  2.     <runoob></runoob>4 U8 X' L3 c2 U7 R/ u- i* o# x
  3. </div>
    ' l" J& R* u: C% a

  4. 6 w$ I+ U0 m7 m5 S4 s
  5. <script>
      v3 M# a  E' b! x
  6. var Child = {! [! M8 D! r+ ~# T" ?7 k$ L- L
  7.   template: '<h1>自定义组件!</h1>'6 [: ^$ w4 {! ]
  8. }4 ^  R# t6 H2 }- t: W" }

  9. . d  E. x& \5 y, z( V
  10. // 创建根实例
    . Z6 f1 y. J% f; O3 U6 M: p# S
  11. new Vue({! p: U' H* G! I2 M6 W
  12.   el: '#app',& U8 `* O/ l7 a  W. c' ^
  13.   components: {
    3 R; {* x" B9 g. ?+ T
  14.     // <runoob> 将只在父模板可用
    : s" H' j( y; w1 Q9 W9 f; H
  15.     'runoob': Child8 u$ d/ Y/ X3 W$ g0 J# b
  16.   }
    9 @/ _" q3 ~1 q! T
  17. }). F: D$ e2 G/ T% s
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
2 I9 m2 y7 M3 Y9 y' s0 n
  1. <div id="app">
    7 r# O% ], y( Q' D
  2.     <child message="hello!"></child>3 t! J3 {5 R. a8 y. C: B
  3. </div>
    * v2 Z2 n2 }% s0 `. q5 e$ i
  4. # |0 T7 t& V5 T
  5. <script>$ e+ g, B2 y& v) \" d; u5 b
  6. // 注册+ M  y5 x6 v$ j: {( U' m$ g
  7. Vue.component('child', {. Z4 y! ~/ N* F3 D, q
  8.   // 声明 props% s; l: k. d: Q4 r" [9 b
  9.   props: ['message'],0 J( [5 j" A2 v3 c6 |2 r
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用# P) f4 i8 O* g+ X4 r" F
  11.   template: '<span>{{ message }}</span>'
    , i; Z1 C  F# c% A  G: u; u
  12. })+ N# c" S4 T4 i
  13. // 创建根实例
    5 S; o8 }* u/ T& r7 c
  14. new Vue({7 ?3 k5 x$ W1 p/ }5 y  e% X1 u
  15.   el: '#app'8 z& E/ F5 s% Z9 P3 l8 |) Z
  16. })
    4 F7 D4 y# c5 N
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例, M' q& @) R# E: ]- u. c
  1. <div id="app">3 n) B" |6 }) t# e5 ?* j
  2.     <div>3 i4 _$ z0 t9 K, M5 g' Y
  3.       <input v-model="parentMsg">
      t; }3 f) m! i( G* X
  4.       <br>
    " o* w0 a1 v& b- N6 ?
  5.       <child v-bind:message="parentMsg"></child>5 ~/ y9 d# i0 G' N9 D) T
  6.     </div>
    , D. q& F; s  P0 b2 q* F% @
  7. </div>
    $ l' X$ S8 I) }* L- R/ m& z

  8. . i* R5 d2 ~3 [6 W5 [% Z
  9. <script>
    7 M  M7 Q6 }) q/ j- ~) F
  10. // 注册3 X9 A9 @" `1 D
  11. Vue.component('child', {0 {1 w6 m9 U- s) s0 H; S5 t- _
  12.   // 声明 props. ]! n2 w& V) X# G8 B5 T
  13.   props: ['message'],
    / ]& h- i5 J3 V2 N, f3 \
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    . e/ z; z- B3 `9 J
  15.   template: '<span>{{ message }}</span>'
    ; T! C# D* G5 X$ v
  16. })6 D7 }3 Y& Q6 [! |0 `, _7 h
  17. // 创建根实例
    ' i# P8 L- w) n: h
  18. new Vue({
    4 J1 A1 X9 `9 T. A# d7 ~( g, B
  19.   el: '#app',
    4 B6 a7 G# x8 p+ p, M
  20.   data: {1 k, Y+ O$ C/ M. T2 Z
  21.     parentMsg: '父组件内容'3 h$ b0 a* O) j- h7 s" P* Q: V, r
  22.   }) N% Z" K$ @& e7 J* [
  23. })
    . {' D8 g1 w8 P% K0 i
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例. ]! B1 ]8 I& k2 C
  1. <div id="app">+ u$ |1 L. Z, B3 \0 C
  2.     <ol>
    + }2 G+ G- n% \  r
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>% S5 l, i9 l8 o+ a( N# r7 T. e; t
  4.       </ol>) O+ u  m8 L' l% i
  5. </div>  F# o6 v4 R4 k* ^- [" a* b; E
  6. ' A8 ]" r2 a+ ~2 N+ w
  7. <script>0 p) K2 B1 q1 P$ T- s
  8. Vue.component('todo-item', {" i1 `' ]$ W' |
  9.   props: ['todo'],* F' D$ N/ e; K# ]5 ?1 W
  10.   template: '<li>{{ todo.text }}</li>': [& @+ w# h# s. M
  11. })9 g2 B/ p% F1 A# c& }
  12. new Vue({! p  J8 A1 S3 ^1 x, E
  13.   el: '#app',
    : r+ c2 H* t1 B" ~% X- z
  14.   data: {5 M7 M; H2 V; e+ M/ i
  15.     sites: [8 D6 c# _+ r7 X) k
  16.       { text: 'Runoob' },
    3 \) }; d$ t$ R. }4 G3 u. Z
  17.       { text: 'Google' },3 t) M1 C3 y6 P
  18.       { text: 'Taobao' }
    / t) h8 k. n8 j- Q4 V
  19.     ]
    ' w% S9 x$ l8 c* }& g
  20.   }) g6 S& h- p+ C& f+ V" s; Q) _
  21. })
    : v" ]' v7 {, Y
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    4 X4 D; [" e" \
  2.   props: {' O9 o' o1 A# l4 z
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)( ~- a: E2 x" s4 @1 i6 g7 E6 X
  4.     propA: Number,
    - B- G; j/ S6 F2 @( t. ~1 ]* V
  5.     // 多种类型
    , n2 u) m2 |( B7 m; ^3 b% d
  6.     propB: [String, Number],/ _# _& [0 z3 Z4 f" x2 C: w
  7.     // 必传且是字符串
    . \( G' a# m' d( Z& R+ G& ?2 H. a
  8.     propC: {' I: [: M$ ^3 w  P
  9.       type: String,
    1 c: v. g' h8 e2 Y. b' T
  10.       required: true) k" t5 ^, Z# V4 v5 l' T
  11.     }," z0 c* j( H: @/ j. M* b. `
  12.     // 数字,有默认值
    ' s, s0 B' j# `- [; K
  13.     propD: {
    " D0 H$ f8 B( V1 r2 {6 @
  14.       type: Number,
    / @3 i7 n& U+ R" v
  15.       default: 1005 C& M3 J3 _! E
  16.     },
    5 u$ l1 d$ {' Z' e# {: _& n
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    : M9 m+ h- j5 Z" c, n/ f; B+ u
  18.     propE: {: @. H  }- o$ C; E5 \& H& |
  19.       type: Object,
    0 F5 R9 `& m! c- L
  20.       default: function () {; S7 q6 r; V5 ^! J
  21.         return { message: 'hello' }
    6 [  L0 T* D: U. q. \
  22.       }
    4 G8 q' a4 A$ D& Q8 i
  23.     },
    + g2 c2 u1 ~8 i& W& Q- X
  24.     // 自定义验证函数
    ) G1 @4 s- P$ o6 _
  25.     propF: {
    - D4 H: \3 p4 e$ I3 E1 c
  26.       validator: function (value) {6 \3 X+ X$ e* a& _. d6 X
  27.         return value > 100 [) \- ^8 X8 B. u! c
  28.       }8 L5 b8 i  U/ d% M# ^* Q; F
  29.     }' L6 A7 s: C0 K
  30.   }
    % Z7 s8 o. A7 T( Z3 p7 {
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array/ y, E; `$ m* t2 N3 E" B7 {7 G
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    & a! V( a  w/ {, A' f: b
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例, m" R; ^: j4 a$ K
  1. <div id="app">* M' `# Z( B3 T% T
  2.     <div id="counter-event-example">* ?' A8 Z! _5 G/ k2 ~) Z
  3.       <p>{{ total }}</p>0 w1 A- S3 E1 Y. G- `* N
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>2 e. Q- ^4 X& J6 v: U9 C
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    ) ^9 i8 X3 x, f1 [8 u1 _- M$ V% A. z4 W
  6.     </div>. M5 d' B, k. ~1 s' }4 X2 C
  7. </div>
    2 w, U& b* ]3 v; L/ _6 n- V- G

  8. , a; q) c4 c  I* O7 w% Y
  9. <script>
    3 [7 v1 x7 O6 L; ?/ S$ j: R
  10. Vue.component('button-counter', {; Y7 s! X8 E2 p6 i7 T! u* K
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',* M7 o, w# a8 l/ |" ?& J  C3 K
  12.   data: function () {; v7 Y, g; r; a1 y$ z
  13.     return {
    1 J* k4 k, W$ U, v4 s" n0 w
  14.       counter: 0
    % }* Z& A  ?5 p& Z& W4 R7 f
  15.     }
    1 y3 F7 Z. F" N  A7 |) {
  16.   },; a: k% J# l# |0 I! n
  17.   methods: {& U+ J" D/ Y* f1 Z# C+ w
  18.     incrementHandler: function () {
    7 F0 i( D. t" [! y9 T% w
  19.       this.counter += 1
    7 ~- U4 Q- _/ }9 s& z5 `- |
  20.       this.$emit('increment')* z- p+ E* E1 `+ E5 q' X7 i& y0 x
  21.     }
    / V4 ?- ?- a$ t; p  m2 e
  22.   },
    0 z" Q* s/ y5 T4 M0 d. H! I! y
  23. })" Y; b4 d. b8 a% t9 k
  24. new Vue({
    6 X8 w7 D3 |) b- b; _1 h9 k
  25.   el: '#counter-event-example',
    " @! ]8 I- C1 _, m
  26.   data: {
    9 M9 E6 k9 ^. ^' E8 t. \
  27.     total: 0
    5 Q! R$ U" a" \  g; ~
  28.   },
    & y& {+ O: s% L3 D) e3 A7 z3 X# C
  29.   methods: {
    ' _3 H8 @" X- r+ z* a6 f: f1 z
  30.     incrementTotal: function () {" S, B4 E/ v/ J% y0 i- ^
  31.       this.total += 1/ a4 f. |6 y6 g
  32.     }
    ' z& Q& i) K) l1 g% l5 D; Q
  33.   }7 m) |. i- Q+ P1 y6 V8 A
  34. })
    $ K# R0 e# y* G" g# z$ s& G
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册; s' i4 J% R5 A
  2. Vue.component('child', {- b4 p3 @. O, f+ M- l* a( @* G
  3.   // 声明 props) o# C0 t8 _7 Y4 v
  4.   props: ['message'],3 V8 H3 C' r+ j
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用% g: \  q8 L! ^* _9 A" I2 K% [$ R; o
  6.   template: '<span>{{ message }}</span>'. \' ?* `3 @8 w2 Z+ r$ f
  7. })6 s! J6 e! D; ]& G9 F: n
  8. // 创建根实例
    " ]- ]# `7 m5 t. E( y6 I) q
  9. new Vue({
    $ Z3 g) f1 P. Q* [* g/ X( o
  10.   el: '#app',
    4 k7 j! `7 m& R+ d9 [4 F+ b
  11.   data:{
    ' L5 D# [3 s* O( J! }' e; z
  12.     message:"hello",
    5 ^! Y( G) x  N
  13.   }/ b- v# T8 h' T" ~- ~0 o/ J
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {( R- x( }+ V0 y3 ^
  2.     incrementHandler: function (v) {
    + d9 S4 C9 o% L& Y' S; l( Q# R
  3.         if(v==1){
    - E5 d; f% u; F& t1 v- h. S! O
  4.             this.counter -= 1% u& l! l$ o* i% r: d! A  O
  5.             this.$emit('increment',[1])
    $ R  l# h  ?# L& Z6 e  g1 t' |6 \
  6.         }else{% N. b: O& Q* n$ r! q
  7.             this.counter += 1
      V9 B7 ?5 s# \7 b" ~
  8.             this.$emit('increment',[2])* y2 v5 R) G% R& y/ s
  9.         }
    0 \( G1 B* t' n7 n$ ?* r
  10.     }. |# x! q  P& n
  11. }
复制代码
, ^' f  X3 k- D9 Q, s

, e3 R$ |# I) x, N, s$ d$ n
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 15:55 , Processed in 0.052155 second(s), 25 queries .

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