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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

5 X8 c9 D4 i5 C2 }7 C" u
  1. <div id="app">- ?- v% T5 V& w' P
  2.     <runoob></runoob>& D) T" D% x7 N
  3. </div>5 ~! E/ B" c5 ~. P% K

  4. - _* }$ ?0 n- Q3 N
  5. <script>' [  R" l- s: J( t: |7 }' q
  6. // 注册
    - Y5 c3 X! \& w. t
  7. Vue.component('runoob', {; B$ ~3 n6 g: |4 `2 ?
  8.   template: '<h1>自定义组件!</h1>'' Z. q9 X2 l1 y9 m: }7 T
  9. })
    ) P$ F8 J" [# Z5 f  ?* p/ ^5 N
  10. // 创建根实例
    + p/ y( V! \: w9 _3 f# i
  11. new Vue({
    0 {/ r7 G- u7 I+ z  e2 @( \  a+ ^
  12.   el: '#app'3 P( I% R' _5 a) x8 Z: x8 j: Y
  13. })7 D8 L' o; P& @- d# P2 x. s7 a
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
" ]- x; D7 F4 \& o( M& O: g/ l2 n$ P
  1. <div id="app">
    ( r- c$ C2 Q& I+ ]
  2.     <runoob></runoob>2 Y. ?" L# i0 O4 q6 b- c1 `
  3. </div>
    3 R- S% t8 U* q# B# [2 [7 h  R7 X
  4. ! S1 q4 \' l8 d9 V. N
  5. <script>1 {  F3 N# p/ b3 j: s7 U) Q
  6. var Child = {
    6 V( p7 W$ `0 }& x. L
  7.   template: '<h1>自定义组件!</h1>'! G1 S5 `: V! z- P, \9 K4 h  W
  8. }' v8 B$ _! W7 f* P# \( G0 C. p

  9. 3 r! ]; J4 p) n
  10. // 创建根实例* g. `2 W4 S7 \; W9 w
  11. new Vue({
    + e, D( P+ n6 }
  12.   el: '#app',$ ^& B" g1 H) _9 n& v, T$ R
  13.   components: {9 V% B$ k  m+ j  Q  o
  14.     // <runoob> 将只在父模板可用
    0 ]4 {  w+ Q) h4 b
  15.     'runoob': Child
    & Y% T' I5 Y1 G7 `
  16.   }
    3 }- M! `1 @) ^$ h4 \, c# n
  17. })* _* E8 d* G3 `5 k8 O6 q
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例" ~: [2 J/ T9 k$ O
  1. <div id="app">
    7 l+ d/ K3 M3 L+ T+ E
  2.     <child message="hello!"></child>+ C# P0 r( D: y: |3 ~4 W# T7 V
  3. </div>1 C$ s& G$ X% E0 @0 G3 W% B7 b; f

  4. - z. P5 @* v# ?2 r( d' F% D, }. v# g
  5. <script>
      u+ t+ n. J8 g
  6. // 注册
    * L. \4 \/ y" y: N( s7 ]9 K
  7. Vue.component('child', {
    . S5 o- Y5 [/ P' ]
  8.   // 声明 props0 y2 p( ?' V- u+ u# Q( u1 h6 o1 _4 c
  9.   props: ['message'],
    & K: V; ^6 {% Z# ?; t" H# t
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    / G( G& c2 }1 x
  11.   template: '<span>{{ message }}</span>', O2 L' H9 X, q/ e4 f
  12. })
    $ O4 Z' E+ Y5 @& o
  13. // 创建根实例1 E# M' r, K; ^8 t1 T! `
  14. new Vue({5 ^+ P/ K: k$ `% [
  15.   el: '#app'1 [5 `+ Z" {8 c- `$ m" e! D5 O
  16. })4 ~. r4 |9 {4 V) q1 i4 ]/ T/ F$ ~
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
$ H' U8 R3 ^& `  N; `$ r4 ^' I
  1. <div id="app">/ a: N& U4 o$ k+ E
  2.     <div>7 l; S# b) J9 g! j: v2 E
  3.       <input v-model="parentMsg">" }) m9 B! M, d) t, N
  4.       <br>& x# Q+ \( i& L0 n4 o4 z0 R
  5.       <child v-bind:message="parentMsg"></child>
    * E- L) k, g/ g
  6.     </div>
    , A, |) T4 x( p5 s& O6 S( i/ J
  7. </div>/ C. n. u1 B& {
  8. ; W; z0 A& o5 B; ^4 d$ L
  9. <script>9 ~2 o' `# k) _! l( K: ~" `' R
  10. // 注册. E) D* M: c0 _( A: ~9 ^5 J. W
  11. Vue.component('child', {
    5 M! ~9 h/ d, v7 w5 O+ m
  12.   // 声明 props4 \6 `$ \4 `- P& l! d+ M
  13.   props: ['message'],
    8 I4 t. T. \5 r7 z8 @* n  I
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    & \  t+ N, F6 G: k8 \! f
  15.   template: '<span>{{ message }}</span>': j- O- p6 u/ j
  16. })
    * G; A4 z: m1 r& b$ T
  17. // 创建根实例5 s3 @' L# R, l; b# ^1 N! ]
  18. new Vue({' _% T6 Y% E" {& {' C$ q
  19.   el: '#app',
    4 `: s, z+ K1 x' b2 _# C
  20.   data: {
    + n6 G# G- K; H0 v, t9 r
  21.     parentMsg: '父组件内容'
    4 |. D3 m0 @/ v0 S1 ?  K" _# a; m
  22.   }
    " k) b, V7 K, C7 ?1 M
  23. })
    4 E9 B0 Q7 _& V6 Q; c
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例6 L& |! X; L2 s. l
  1. <div id="app">
    : \/ S0 T" M( V3 Y0 R# Q
  2.     <ol>
    8 E# W) V0 G: g( u$ M, y) |
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    3 I* S7 Q/ u' L" |, M
  4.       </ol>0 X  V' x( q. ]4 Q! D
  5. </div>! j" {8 Z" G: `% m( i0 K: k6 |

  6. 2 M. _+ |' [/ M7 k
  7. <script>
    : L/ ]9 H. M" F' N% k3 X6 `
  8. Vue.component('todo-item', {& V9 J% V. u+ ^) p0 l* z( [. @
  9.   props: ['todo'],) h3 }3 }5 f, b1 J; O  C7 A! i' `
  10.   template: '<li>{{ todo.text }}</li>'* e! s. f  x, w4 S* U& g. v
  11. })7 m. u+ y9 [* u" ]
  12. new Vue({
    , R) J0 [1 P% S/ y/ R
  13.   el: '#app',% V8 Z2 L+ }  _2 E9 W* W! B; _/ T
  14.   data: {
    - x4 p) h. k' J* y
  15.     sites: [( E# z  C# V9 O+ a# q" d* ?# Q
  16.       { text: 'Runoob' },
    ; U5 w$ J- i% \- z6 E+ ^% R
  17.       { text: 'Google' },
    & U4 I, N+ ^5 h" q1 i* m
  18.       { text: 'Taobao' }1 H  h. t; l3 c4 X
  19.     ]
    . k9 a7 v! P9 B
  20.   }+ q/ m8 \8 g4 s( Y- E1 N; U; D) y
  21. })! `; I; e( U" B) L7 H5 `
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {( }/ v' k, p: P# Y
  2.   props: {
    6 a! E: X5 y, W; u
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)- V) u" p! C7 `) D  E! P$ Z, \0 o
  4.     propA: Number,
    , p; v0 K* Z4 {1 O1 I
  5.     // 多种类型( O4 M$ W, Z$ H6 y) ^$ Z, [
  6.     propB: [String, Number],: y5 Y% y9 h8 \4 Q! m; O/ r) T( l
  7.     // 必传且是字符串
    6 Q) w, E% y% ?" G# X' u
  8.     propC: {6 p( N; K/ i+ @( z4 ^( }  I7 S: g
  9.       type: String,# Y, ]( `/ {" j5 m. G' B
  10.       required: true
    8 R  e+ T3 ?4 ^4 O1 U! M
  11.     },
      L4 D  o5 c3 G% Y
  12.     // 数字,有默认值4 @+ X- H* i& J% h
  13.     propD: {
    / Q( K, m. w& J* [! c  s1 J& w
  14.       type: Number,4 a; T! v5 O) F: K3 d  @2 G/ H
  15.       default: 1002 a) {' s6 M4 h+ [: F
  16.     },
    % D0 z8 f. |1 M) C
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    7 T. U( z1 b4 y' B' }( R0 ~% }4 w
  18.     propE: {$ r& ^. m7 _7 }9 J+ `
  19.       type: Object,4 j* Y4 q% P% M1 x5 N1 q2 ~
  20.       default: function () {
    ! T  \( b- n% R; l8 P1 `
  21.         return { message: 'hello' }
    ! H9 a  n9 `% ^0 g
  22.       }$ }" F0 S4 |' |
  23.     },
    ' _% P* @. ~# {" |& H4 n9 {/ U* H
  24.     // 自定义验证函数$ i2 J) K- ^! s' C* R2 Q
  25.     propF: {
    2 C4 x) \, n% r! O+ r4 i! A3 W% t
  26.       validator: function (value) {
    6 w+ a- ?6 ^3 v4 |
  27.         return value > 10
    0 Z; g6 i8 X7 X0 e
  28.       }4 {* c& ]( \. R$ ?( `, b
  29.     }3 |# A1 N* F$ i, h/ b: g5 R: |4 @
  30.   }
    ( L2 S* Z- h  e2 T* z2 H" n
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array4 b. a! Y. ^" Z: ^3 i+ i! a
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    6 p1 i6 Q' t: Y, R
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例% b( i6 E, a3 U& u
  1. <div id="app">
    6 _( K* {9 g6 G
  2.     <div id="counter-event-example">
    - ]; T* v8 L5 V4 _* Z- N, u) ~3 Z
  3.       <p>{{ total }}</p>
    4 j2 Q' R9 V" ?9 S4 k8 U
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    : m; U) D0 ~/ U7 A
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>' C2 p! O1 L, D
  6.     </div>  h% D- ?+ m) a2 ^" v2 D
  7. </div>0 V6 z  \  e3 F+ l
  8. : y# S' k+ F" X' V. d
  9. <script>( T+ w- P" `9 k# |3 ]: n3 p
  10. Vue.component('button-counter', {
    . I3 B; D* ?, ?3 A3 ?3 m* F" m2 d
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',  U2 H7 u* L* j1 j
  12.   data: function () {, L; Y) p6 W8 ]- r5 @
  13.     return {; E" r: H; `, K
  14.       counter: 0
    0 `+ l+ n3 |. C# Q8 f; I1 J- A
  15.     }, C$ w& h# H8 r  g* E; A
  16.   },
    . U- {+ X7 U  S) ~1 }4 o
  17.   methods: {% j5 D( a. m. O% w% @# i) [
  18.     incrementHandler: function () {
    $ P& d# P# f# [" R% g$ P3 S6 k
  19.       this.counter += 16 N! b' j9 a  n- f& s8 w2 M4 q
  20.       this.$emit('increment')6 k. E- N" h' b" C7 @* v; T8 {: E0 D
  21.     }1 l! ?! u3 W# I  b7 _' q# Y: [
  22.   },) J1 V. J: K! n2 b4 N
  23. })
    5 q" t3 u. d" d0 D1 y$ H
  24. new Vue({2 c# O; N! V9 n  }& Y! R! H4 N
  25.   el: '#counter-event-example',
    7 `, E% x3 Y- Q) S" d) w  ]
  26.   data: {* ]. N6 K/ c' X4 c  l; t  x' ^
  27.     total: 05 W! z3 r! W2 `0 Z8 ]0 A
  28.   },* Z$ Q8 S) @5 z# N, r' X! b9 B
  29.   methods: {, d! D! C  [) B, j( H) G# E
  30.     incrementTotal: function () {+ b" E+ C- ?: e: f; G
  31.       this.total += 1
      Z0 \4 g0 D. N$ W" n8 ^# C) U
  32.     }. w% N; x  W+ R- A4 \; q
  33.   }
    , j/ i; E$ K: e; W6 m' V! ]4 c
  34. }): n( E* n$ x* u* @3 N( k
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    ( N& k4 J# ~; w+ I6 o8 c" X
  2. Vue.component('child', {; Z6 p" T& A' q+ m0 o- s' K. V- n: h
  3.   // 声明 props
    ) S  Q$ J' Y0 T) j! ~
  4.   props: ['message'],6 ]8 c: b4 x( O# w  G3 k# d
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ) C: v" c; Z4 L6 K% n
  6.   template: '<span>{{ message }}</span>'
    9 _9 _5 n; O) J% t" o
  7. }): @0 `. u1 l9 f7 i: |
  8. // 创建根实例$ X0 B6 q; h) K8 R. U# M
  9. new Vue({% g* [3 V1 w1 j. @* s" O7 `
  10.   el: '#app',5 {3 T$ X2 Y1 L3 q! u- [0 n6 @
  11.   data:{
    * r' h5 J- W" Z" F. t
  12.     message:"hello",
    ) t" E# h& x$ U
  13.   }0 h/ ~) D2 |! s/ U/ [- |$ U8 B
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    ) }" F$ k, s& H1 e
  2.     incrementHandler: function (v) {
    . k- j  i, ]' r
  3.         if(v==1){
    6 p" R' Y! l" ^
  4.             this.counter -= 1
    , o8 \1 [& ~& l) U
  5.             this.$emit('increment',[1])& Y' ~! U7 o1 \& y6 D
  6.         }else{
    7 D6 _" Q+ Y( N: K7 g' n& d: X: M
  7.             this.counter += 1
    % T2 M1 g3 E, m' o' b8 Z3 I: Q' {
  8.             this.$emit('increment',[2])0 s5 E; Z4 i. r* ]$ E
  9.         }' l& \3 n$ d. O; _% t# z" W9 H
  10.     }
    ! ^1 B. K& |8 w9 ], m% I$ |& R
  11. }
复制代码

# C" U  q5 |! K: o% u. }% {. V
1 K% `" N& z& b: k0 {3 Z- T. D
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-9-21 03:19 , Processed in 0.059341 second(s), 23 queries .

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