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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

. S) Q# @0 U8 v& b% K0 ]9 O
  1. <div id="app">0 q4 V/ N' P, [2 V$ [5 B# U: P& l
  2.     <runoob></runoob>
    1 f  ~! v* ?0 a" D+ Z: ?
  3. </div>
    8 F9 d9 }9 J6 r) Q- u8 v

  4. . C* l" I- p( W
  5. <script>4 Z: j0 [8 C. W% U6 C4 [. N
  6. // 注册
    6 g( J) Y6 Y) |! g2 p7 @% L
  7. Vue.component('runoob', {  F# y. K5 K8 L5 A4 L& Y* U
  8.   template: '<h1>自定义组件!</h1>'
    - k! O5 a$ J+ C* J
  9. }), C2 t$ S" ?3 C# K# j1 L
  10. // 创建根实例
    : K- v, c5 g8 P' w& ~+ d
  11. new Vue({
    ! P% b5 F! L7 O  v+ O6 N0 p" x3 p/ G
  12.   el: '#app'5 F1 \7 h& b1 R6 O% e
  13. })
    5 I; ^: N$ M5 L6 ?1 ~
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
; o4 ?4 G; A6 |/ B
  1. <div id="app">
    3 f( V- U- C$ B) d/ b3 p
  2.     <runoob></runoob>; _7 s, g6 r0 ~8 t- i
  3. </div>7 a) a2 y& x" x3 h

  4. " a, b; i! T# W% k9 g
  5. <script>
    % ^. {  j. ~! [& l! j8 v
  6. var Child = {
    ) d( ~6 ~9 V( W6 R( j
  7.   template: '<h1>自定义组件!</h1>'
    0 y: `( ^) q6 C! d) P
  8. }
    , X$ P0 E4 r+ I: v

  9. & |( f1 k. z2 _6 Z9 u
  10. // 创建根实例
    2 h$ X7 O- w) [( m# e' b8 \& I
  11. new Vue({) q. v( ^* H6 m& @8 n; Y
  12.   el: '#app',# I3 L. \0 B7 ~$ m4 J9 M! a* @
  13.   components: {
    : Y; Q3 C8 P. x( W7 q- Z
  14.     // <runoob> 将只在父模板可用5 v5 w  V' s; g  C6 \3 [' E2 h
  15.     'runoob': Child3 s  k9 a0 K* Y& ^) f
  16.   }
    * Q& n; K1 Q- R+ [  Z
  17. })$ C  P! M/ ^3 a7 }
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例9 G& Q2 q! G6 X$ ^7 D$ o/ l* A
  1. <div id="app">
    % J7 L  |: A' F- n
  2.     <child message="hello!"></child>+ G" K7 D+ [- v) I
  3. </div>; P. b! \1 U6 M# ]& O
  4. 3 p( g0 Z* I5 @) @* R
  5. <script>
    7 D: s7 N6 y  ?& y2 V
  6. // 注册
    - ?" @' d$ q, ]9 s
  7. Vue.component('child', {
    $ D+ h+ Z, r- G. D
  8.   // 声明 props
    - m' |  a/ M7 o" x* ]+ q
  9.   props: ['message'],
    % E7 Q  W% x$ g9 k
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用2 }7 h* h! c- H5 q3 y
  11.   template: '<span>{{ message }}</span>'! e1 ^$ q+ I. A& x! L+ n
  12. })7 ]' L8 ~: W4 e% k) R( d# [4 v
  13. // 创建根实例$ {% P  T2 l) m0 G) a3 j
  14. new Vue({
    , ]" Y7 b/ k5 |& @9 U0 z1 a
  15.   el: '#app'$ s# K' k, q. _7 N- t  F
  16. }), {" `. ~& f/ r5 [2 Y% f
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
. _# D. E9 B' ]/ Z
  1. <div id="app">1 c* e$ p1 e* m) s# N: B
  2.     <div>
    ) a( y$ B5 V( u- S6 U4 }# i2 f
  3.       <input v-model="parentMsg">2 ~$ j; f; A$ R
  4.       <br>
    + k) }+ v1 O# s$ t+ }, h7 A3 u# l, \
  5.       <child v-bind:message="parentMsg"></child>3 D: E2 F- {; ?5 u/ F5 ], s
  6.     </div>
    " J' r- _; r/ i0 K& _6 r/ D
  7. </div>
    / q4 D, t7 G" S3 v( ^' z2 ~( b

  8. / r2 Y' Y. I/ F
  9. <script>
    & M) O5 l  q! c5 U( a$ b
  10. // 注册
    % P, [: h6 [* `
  11. Vue.component('child', {
    1 g% j* z/ x6 }/ ^; U' l
  12.   // 声明 props
    - t1 f! h3 a6 R. k2 e; n; T- j) v
  13.   props: ['message'],
    0 \7 c! W9 @$ ~  O( ~
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用. }6 D' ~+ z4 L/ M
  15.   template: '<span>{{ message }}</span>'( T4 |9 y, J: [3 v
  16. })
    . m$ `8 q8 g; x  y
  17. // 创建根实例
    0 s, p( P5 p) S) X! a% [
  18. new Vue({$ A7 A6 |  N$ w8 e
  19.   el: '#app',8 N& k2 p- w8 q
  20.   data: {
    3 D& `' R8 t- c" U) s1 X
  21.     parentMsg: '父组件内容'/ A4 T5 J; k  o, G" c
  22.   }& @* {4 i  j3 G1 w
  23. })
    ) r. Z7 _$ i7 v5 N! a  \
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例5 |# t9 ~) b2 G! A8 C4 S
  1. <div id="app">% {# W( Z% u' i
  2.     <ol>* i& Q( L* K+ ]' |. n' I
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>9 D4 _+ `9 y" f/ q0 R
  4.       </ol>
    & j- r4 d- v  u% x# u/ m# y& y- i
  5. </div>
    6 i: b4 D, }& n
  6. 6 `3 e! D& z  c! X! C& X
  7. <script>/ Q. P& U, u; n2 j9 }
  8. Vue.component('todo-item', {; E) O* ]# m& @
  9.   props: ['todo'],
    : Q+ z' I3 q" }0 ]" t+ A
  10.   template: '<li>{{ todo.text }}</li>'
    ) h, B. D) A0 [- N
  11. })
    ; Q# W* R& b& b' J0 l
  12. new Vue({6 m! {, u0 }. ]3 w: j, T
  13.   el: '#app',6 S! c. v) j1 u
  14.   data: {
    ; A" V- y% ~; d6 J. Q
  15.     sites: [
    7 t7 V- K6 a8 M
  16.       { text: 'Runoob' },
    % @6 p- W8 D7 D* C. v' [
  17.       { text: 'Google' },6 W/ U2 y* z4 a+ H
  18.       { text: 'Taobao' }
    : G( C9 g- K! |* N
  19.     ]2 c4 F( O' s- c, p6 F9 |, ^
  20.   }( I# k9 S$ e0 K. i  U# s1 S9 G' v
  21. })( y% q! h6 d( r' C1 m  X% i  H
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    ( P& o( z+ `0 I8 G# d: g0 R! G2 h" B
  2.   props: {
    5 [, f/ I! c" M7 F
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)( K4 H: q. L  s# q" k! o; f% n
  4.     propA: Number,
    + ]3 t/ V6 y6 q
  5.     // 多种类型
    $ n3 y: n0 P; r; R6 J+ C
  6.     propB: [String, Number],
    , s# l7 V6 S& P/ |4 ?$ z
  7.     // 必传且是字符串
    3 J$ U3 h. j! {5 R  J" a. s
  8.     propC: {
    . R6 w5 D1 O4 @( G; n# t6 c. M6 ~
  9.       type: String,# E3 K& `0 Y% x1 w$ N
  10.       required: true, q/ o, j$ U7 W
  11.     },
    ) q# Y; {4 f% P% X; I  _
  12.     // 数字,有默认值+ ?' }9 e% S/ s6 _
  13.     propD: {7 w$ e" U1 h' c. D/ k8 a
  14.       type: Number,
    2 _8 m# P& S4 C; B# u0 T, D
  15.       default: 100
    / S" V0 s- q7 V2 x* T3 y
  16.     },
    1 m/ F" Z; `/ s8 n: V  b
  17.     // 数组/对象的默认值应当由一个工厂函数返回3 R" O& |% \0 _% b2 Z
  18.     propE: {
    ( Q& O  q# P5 b# W
  19.       type: Object,
    0 ~2 i( \) [, H) t+ I& d
  20.       default: function () {1 Z/ y& V: y; v* m- M& y4 s
  21.         return { message: 'hello' }
    : [+ i6 l+ c/ |! i0 x/ B
  22.       }
    1 e. ~% U% v% I* G* s
  23.     },1 H# t  b5 o3 E* I8 b
  24.     // 自定义验证函数
    , p6 ]: @1 A+ a& _
  25.     propF: {
    ; N4 I, I6 i- ^8 t
  26.       validator: function (value) {
    : H/ B6 [. N8 i; d( w
  27.         return value > 10! P/ d4 F  y- v
  28.       }
    0 @+ S5 X5 y: c9 }$ Z8 v
  29.     }0 \5 g% u- m/ x
  30.   }
    4 J$ @; \& V- c, H! q5 K+ X0 }
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    ( K* B$ a2 E0 x8 a; b% T
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件0 B2 l+ O1 ?$ G% f4 ]' V; ?
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
* G' k3 ^8 T2 ~- o. G
  1. <div id="app">2 `6 ~. j- o9 p! M. V& {
  2.     <div id="counter-event-example">0 _2 ~. K  N$ c  Z# o. i2 I0 E
  3.       <p>{{ total }}</p>, M" T) s  k: g. F: _
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    1 U3 s& g! X& |
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    & [- O) ]8 s1 P6 ~5 f7 S* _
  6.     </div>
    % B! L, n6 D) A7 j) Y0 Z; |  D
  7. </div>
    / R) b- d: Y6 J% F( q  u
  8.   u5 @. A' n: d/ `. f/ D, h$ W. d
  9. <script>2 n" k. i9 q$ w" i
  10. Vue.component('button-counter', {& @( ]- T- J2 q, b* o) f1 F/ F
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',8 K1 J  F4 o( Q: t
  12.   data: function () {5 s& Y  \5 v2 l' o/ n( j# l
  13.     return {' j* r4 M# z& y7 F/ p' A! _6 e
  14.       counter: 0, ~# a# N6 c( M- I
  15.     }* N9 n& Z1 d9 X9 ]9 ~
  16.   },
    ( \  p" T- c4 T( e0 E
  17.   methods: {
    / @6 _/ S8 [+ d5 Y: |1 s
  18.     incrementHandler: function () {
    2 z+ L& G. `) F5 m4 `
  19.       this.counter += 1% N( j1 m4 B: _* v# X0 `
  20.       this.$emit('increment')
    ( s1 a1 N1 r- l' R5 L6 H
  21.     }1 a' y7 q8 `. m
  22.   },- Z) T3 i5 V" Y/ V
  23. })  W, o) Z& E; |' D8 `
  24. new Vue({
    . ]# J- @3 V! {# M) _
  25.   el: '#counter-event-example',
    0 D& K: O3 G# p+ G7 ]; q
  26.   data: {. S5 u) X# s" f2 @2 K
  27.     total: 06 Q3 K' U4 \8 R
  28.   },
    : @' d; ^% f! _. a8 B4 e
  29.   methods: {
    ! ?9 r% L  X+ P: d  \3 t0 J3 Y
  30.     incrementTotal: function () {8 f" l& f4 Y! x% u5 }
  31.       this.total += 1
    " s" Q$ Z# g1 e* _( a. D
  32.     }) m) n8 L1 M7 K! o% x
  33.   }5 h! a; y1 E+ x7 q$ g
  34. })
    1 U8 w; Y* r' {, B/ h; c
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册2 _: Q+ D* V3 }2 |1 {
  2. Vue.component('child', {" s4 j, Z/ |9 D. p' ]) O
  3.   // 声明 props8 M9 k% A) Q" ]& P: }
  4.   props: ['message'],
    $ P% {" i1 q3 @4 o/ Q: Z  r" z
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    1 s3 X! ^$ E( p2 T  g% C8 E4 k, q
  6.   template: '<span>{{ message }}</span>'3 X' ]) ^! v" Q! _! I) N
  7. })3 o6 |' S2 x# S: G- y/ w
  8. // 创建根实例
    9 l: |, \" m; P
  9. new Vue({
    5 v/ c" N$ ^& a. f
  10.   el: '#app',
    ; b$ [8 C/ I$ ?/ ?0 O+ v
  11.   data:{
    + c7 N! J" R8 c  u
  12.     message:"hello",
    + R0 L9 ?, w" m6 G2 v, @( z$ ^" Z
  13.   }, J) v: ~3 E2 c& `# J) }
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    3 E9 S* y1 l  g
  2.     incrementHandler: function (v) {  i. Y9 v( }! i
  3.         if(v==1){) x5 g3 X- ~1 J$ P% \5 G- `; o/ N" a
  4.             this.counter -= 1$ d- O' l* w: C& c8 [, w2 z; a
  5.             this.$emit('increment',[1])
    / n# g5 n% R$ l4 Q
  6.         }else{
    $ w& |; g; d  c- n
  7.             this.counter += 1
    - C7 P  j8 d  L# F9 \7 T% P8 [- l
  8.             this.$emit('increment',[2])7 g/ x1 R+ v+ w: q0 k9 a
  9.         }
    2 I# a  O7 N2 {0 T& g! U
  10.     }
    ) S5 _7 S. Z& t. [) l. b
  11. }
复制代码

" O  B& B5 m* O: A* @+ g) x, {7 o, B1 [& j
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-8-4 08:12 , Processed in 0.089723 second(s), 22 queries .

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