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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15828|回复: 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,并使用它:
% R2 A0 T- e% e7 B  {, N  W& W
  1. <div id="app">
    / f2 Y8 H* j$ e7 h, n8 T* c
  2.     <runoob></runoob>
    2 ?/ L/ F- X+ I0 E
  3. </div>6 x3 D; K8 M/ f! Y- q6 L1 M
  4. , m! [9 C) R) g; ?5 D2 Q
  5. <script>
    ! o+ o0 @# F( w
  6. // 注册+ @" C0 I7 G' _) Q- z% k
  7. Vue.component('runoob', {) r8 z$ e; a/ T. f" l) H& k
  8.   template: '<h1>自定义组件!</h1>'3 O( B6 Y  s) ~6 \$ r$ ~
  9. })2 H* G9 p0 r, Y: s- `
  10. // 创建根实例
    7 c$ u- m: F9 ^, R' K& n) X, ^; M
  11. new Vue({% z# `& K. z$ @! x
  12.   el: '#app'/ Z/ u, M, ], W9 R8 |  [5 q4 `3 d
  13. })- C+ ~$ q# N& ~( Q6 p
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

( J' d" \8 B0 A8 w8 B
  1. <div id="app">, R! w5 j, ]- D/ _6 p% G- B" z# |
  2.     <runoob></runoob>
    - h) y, ~, L1 |' l) ^2 A+ d
  3. </div>( W" |: L3 p# E5 v& U

  4. $ r! Z+ n) z6 s+ v
  5. <script>
    6 ?9 r7 E5 j9 s& d
  6. var Child = {
      u2 ?$ e; D+ N# c; U5 y
  7.   template: '<h1>自定义组件!</h1>'0 W: a: ?$ v, Q0 F2 V/ p
  8. }
    3 K2 w, l- s' P

  9. 5 r% g' d, A" Z8 o: e1 E! |2 B6 E
  10. // 创建根实例. L7 ?0 J7 X8 y9 P$ h: w
  11. new Vue({1 [6 h; S) l7 \1 t/ `9 z
  12.   el: '#app',
      V% M6 q1 K5 n& _! M* ~2 X
  13.   components: {1 \$ Q! v" v: Y# I7 K6 ?) J
  14.     // <runoob> 将只在父模板可用
    1 u8 ~+ g1 {* _, ?& m
  15.     'runoob': Child- K8 S4 F1 [/ k; l# |
  16.   }
    " M0 x! H! x9 D& k' v4 N9 N
  17. })" n# N  d7 R! S+ H2 W' _
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例1 c; P& H' O2 p/ j& E3 f
  1. <div id="app">
    ' h# y( r) n) i% ~
  2.     <child message="hello!"></child>" h# S- r+ J# N: [3 d0 {8 U0 n: Z8 h
  3. </div>
    9 Z6 z7 h  [1 N2 ?
  4. ! |' u8 n2 I6 s* r5 {- z1 d
  5. <script>: }: R- V+ f+ M
  6. // 注册. Z$ ]) z) ?7 R3 B3 K$ e9 O
  7. Vue.component('child', {
    # P2 b! l& k7 q0 u& c  f7 @
  8.   // 声明 props& P# i1 ]# C- W% Z: F, l( F
  9.   props: ['message'],' f9 Q3 x  U4 `
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用6 j8 ]6 ?: G. D9 i. h) O5 Y
  11.   template: '<span>{{ message }}</span>'8 [  C! w5 _; @1 f
  12. })
    & l; U/ c& y1 @7 I' s& Z
  13. // 创建根实例
    " _! a6 K0 J0 Y7 k( l- @& n
  14. new Vue({2 Q1 p! U9 s7 z; y/ v7 }7 M
  15.   el: '#app'6 e% L1 a. |! K3 Z, [
  16. })3 n& Q- ^1 E3 q5 ^  d4 g$ m" b+ w$ @% M
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例" h9 \2 `& z: r! n, o# U! w
  1. <div id="app">
    ; n7 c4 ~9 D- U
  2.     <div>
    $ {3 m! ^/ h  a) }
  3.       <input v-model="parentMsg">* e$ d* Y- }! [% ^9 A3 v9 [
  4.       <br>6 ]3 }2 n& g* ?# r
  5.       <child v-bind:message="parentMsg"></child>8 u0 p8 q$ l. ^* k- _: M- D# z. O
  6.     </div>
    3 W! U3 K, g. H+ }" A
  7. </div>
    # ]0 i4 G9 s4 j

  8. ( i( }* C9 ^; V' c+ [, l6 O
  9. <script>4 d. k9 d& E; H7 t* y) ]' @. y/ n* v
  10. // 注册3 u2 c+ T$ `; o( ?, {7 F0 Y. @: d$ |
  11. Vue.component('child', {, {9 D3 _, I3 P
  12.   // 声明 props  Y: s5 |$ R; X" e0 t$ C- G: p
  13.   props: ['message'],, c- ?& k" p' ?7 x' ~
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用+ F  Q6 Y8 ]6 K: a0 m3 ^
  15.   template: '<span>{{ message }}</span>'
    6 `: {4 K: q! F: c, N3 z
  16. })
      j, {& Y0 |# r  a# k4 f8 R: S
  17. // 创建根实例$ y: B- _% Z- z3 j3 u3 @/ d
  18. new Vue({
    + R5 h2 L* L/ v5 z! k$ n
  19.   el: '#app',
    7 {5 e$ W! }0 r! L; `
  20.   data: {
    6 {# p5 [$ `% ~; O" c4 B
  21.     parentMsg: '父组件内容'6 e! b# T  [$ g
  22.   }  t* G, k+ r& e
  23. })7 \4 H$ h$ z9 x) h/ o6 @) V  x* r
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例- U" ?  p: Z. y. D
  1. <div id="app">
    ( \7 p$ U( p! k; h
  2.     <ol>
    4 [1 d* A; \$ C
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    ) U+ J2 l5 S" U4 \) y- g& k& n
  4.       </ol>3 B4 f  m% s- Q  A1 O2 k" g
  5. </div>- S: M- P& A1 P& f1 \

  6. 5 L% ^; ~. ~! _% t
  7. <script>0 I% `4 Q6 f: ?) D& @8 b. X+ j+ G
  8. Vue.component('todo-item', {
    2 c: V  B" N. g
  9.   props: ['todo'],
    2 F: ^" i. m8 `# [
  10.   template: '<li>{{ todo.text }}</li>'9 f+ P8 \# t* V: m. C" P
  11. })8 K: f# v% j9 O* r! P$ g
  12. new Vue({- z/ E. e6 ?) ~; l0 D
  13.   el: '#app',4 @$ g5 n6 t( a# {4 t' p
  14.   data: {
    ! P* o5 ], }7 X# l" Z
  15.     sites: [. b( u7 I/ [: P  w& m/ x/ ~
  16.       { text: 'Runoob' },) l0 D; k' |6 H& s, y5 i; J( k
  17.       { text: 'Google' },
    4 C2 B1 P& T0 X( ]
  18.       { text: 'Taobao' }
    $ r: K/ }* r  ^/ m4 _/ F
  19.     ]
    8 p) K$ O5 Z+ \# ]& b
  20.   }$ M8 [: T. s2 @4 g& Y$ n* y, _
  21. }). B0 Q* [% E" Z6 E  C
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    $ S1 M( I0 g5 K  F" @% P
  2.   props: {
    4 S7 `7 |# o; x) c& |, Q2 J) j
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)3 j4 t' A* v4 y# v  A
  4.     propA: Number,
    , H& |& ]" E  q4 Z& e& o
  5.     // 多种类型
    % ~/ X/ M& X, M# X
  6.     propB: [String, Number],, N$ _  g& Q6 u0 x5 T
  7.     // 必传且是字符串
    $ m4 b8 k! Z, t  v, y8 v- ?. x
  8.     propC: {: k- Y& ^0 @& g( E6 y
  9.       type: String,
    & K0 Z0 E+ G6 Q" b( Q0 }/ z
  10.       required: true: y+ p; N4 _* j5 G1 ^, P
  11.     },
    2 t, d, e% {: p  m
  12.     // 数字,有默认值1 N8 q  F; s! C8 |- t
  13.     propD: {
    , z6 _# ~/ v2 g- S1 F5 e
  14.       type: Number,# X$ V9 |8 B7 h; m* Q' O+ G+ j9 ]# e5 R5 w
  15.       default: 100# w- ~% f" K) G) R  D/ {5 p. B
  16.     },! V4 W4 b, b, T- a1 R3 O
  17.     // 数组/对象的默认值应当由一个工厂函数返回* F9 l/ |' t' q) f; L
  18.     propE: {
    : X4 L# `# A( d: d% _1 z
  19.       type: Object,
    4 j& I; _- @' o  W# c) ?0 z
  20.       default: function () {
    9 [' \: D! s& C5 ~  ~
  21.         return { message: 'hello' }" T2 `1 W( D# t8 Z1 Z4 J
  22.       }% |0 @; m2 Q! I" L  B4 [* u$ i
  23.     },9 X# W, G% K8 Z) C  d
  24.     // 自定义验证函数" J! Z6 O) p; q) q( g6 A- Y
  25.     propF: {
    - v5 P) }7 r/ {5 k0 x1 _8 j! J
  26.       validator: function (value) {4 o( \; k2 m. b+ U6 j
  27.         return value > 10# ?7 w& e6 ]- U$ J7 f
  28.       }- c7 c; Z7 C/ Y) T- E
  29.     }' j' C$ g$ n7 X/ i+ Q
  30.   }
    6 e) F, f  K  X
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    . g% M2 B& z" _# u" c  K% d
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件2 Q" s, C9 y5 C. B5 b
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
8 V# |+ C) [/ C" i% @
  1. <div id="app">1 e2 d7 L7 K( E0 U9 a
  2.     <div id="counter-event-example">9 n# I; f, Z. c. [1 ^0 n
  3.       <p>{{ total }}</p>
    ; }) @- g( e/ k( m) G
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>5 M/ ^. J0 w0 p+ c3 A9 F3 H$ Q# Q, w
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>( a; {4 \2 S2 o) f& I) T
  6.     </div>
    ; j: C7 O' B$ _- ]0 k" y
  7. </div>9 b* Q. j8 U* o& n# u4 m. K  E  O

  8. $ a: ^4 n! Z2 {. b- G, s. g" n/ X
  9. <script>
    ' i6 O: K$ V: E" ~6 ^4 F
  10. Vue.component('button-counter', {
    ( p0 E% D& K: J+ s
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    ' u# Y: u3 ]+ P6 J* Y
  12.   data: function () {
    , A& N, A4 C# ]: ~- ~8 p7 z& V! T8 w
  13.     return {
    : S6 }. S5 |6 L+ B. G* M
  14.       counter: 0
    % |8 ~5 l# w0 i9 t( O
  15.     }
    9 A4 T8 ^3 s. Z4 A1 {2 q
  16.   },1 C/ d' w$ j  U$ Y: P  ?
  17.   methods: {: n+ i# M! _  c& g2 ~* {
  18.     incrementHandler: function () {* y3 `* ^6 s5 [6 x+ H
  19.       this.counter += 1
    ( p. Y: J9 l" R; w: W! r: ~
  20.       this.$emit('increment')
    3 Q2 U9 z+ `; k" X" z
  21.     }9 ]0 Q( M! \8 Q' d9 f- N
  22.   },2 \0 A# p. e3 U* J
  23. })8 K" x9 P9 V+ }0 ?7 E# o4 Y/ J
  24. new Vue({0 [" c6 q7 z2 H
  25.   el: '#counter-event-example',1 C' K7 C- r: Y' @, T
  26.   data: {
    ) c0 v, p0 P8 D0 I3 E& f
  27.     total: 0* J# R$ s# ~% \& p- l- s
  28.   },
    # q: X0 R& `+ h2 F: m: _  Y
  29.   methods: {& [$ `# M0 o9 G
  30.     incrementTotal: function () {
    2 |1 e4 s' t' L% `3 q: r: w
  31.       this.total += 1
    + a' n5 V1 T- L
  32.     }
    ; K7 d0 a3 \/ o" {/ l" M/ O
  33.   }; v% E& `" {  y$ s
  34. })  a! N. Y/ {& B# v5 p& Y. V
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册1 j0 t9 _& f1 T4 }* h# V. q
  2. Vue.component('child', {
    - N5 k* W" ~7 ~
  3.   // 声明 props- F2 F9 }& x" Y4 M
  4.   props: ['message'],
    + e0 u/ N! q% [7 e/ e6 k
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用+ d5 u! G6 N& |1 `1 K: j/ T
  6.   template: '<span>{{ message }}</span>'
    + k6 w& V; R2 O5 L
  7. })
    + Q( g8 T5 j4 g6 v
  8. // 创建根实例+ Z6 }+ y& j7 U/ Q5 Y
  9. new Vue({* G! Z5 R) I, p+ Y  ?7 ]- R
  10.   el: '#app',, }1 C- B2 h8 w$ d
  11.   data:{
      M3 U( ]/ _4 ]$ \
  12.     message:"hello",3 r: ]6 Z" q) }2 ?
  13.   }
    1 b( w3 g5 H8 a- p% R2 V0 E
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {' c/ |/ F/ E3 l, u) F' ?
  2.     incrementHandler: function (v) {
    2 r4 R3 [& L' j* T! h( O
  3.         if(v==1){7 x( Q# O& j! E6 C
  4.             this.counter -= 1: b! K4 ~' E1 p4 d% \
  5.             this.$emit('increment',[1])' \9 a+ ^$ [; b: x: s( N  d
  6.         }else{' c( E1 n% H7 _9 o6 v3 v0 J- {
  7.             this.counter += 12 T$ x( d) l9 N* d5 D
  8.             this.$emit('increment',[2])2 f  ^5 w0 g& C% R* @; V
  9.         }2 p) I4 M- B9 @8 L
  10.     }# ?0 Y% C6 P: W4 C5 W. c/ H
  11. }
复制代码
5 {1 E4 V9 S% I3 I1 ?

0 Q+ q# f1 [( W! W. _0 B3 F5 l# j
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-20 01:52 , Processed in 0.070400 second(s), 23 queries .

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