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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

" Z. r$ `1 z/ I* W- |7 K) }$ F6 d
  1. <div id="app">
    ; h1 W) X6 [6 g. I
  2.     <runoob></runoob>1 L$ \% C! O4 l3 Z4 w% G, j4 a, H
  3. </div>
    ! h: L" P/ p7 X: o- F/ Q: O( U

  4. ( S9 Z, y! g$ c# |2 N2 {( o5 b% {
  5. <script>
    5 ]) y, `6 n* y$ }' T$ ~/ {
  6. // 注册
    7 G% U; W2 V7 b9 r8 b
  7. Vue.component('runoob', {2 ~* H4 H, r7 ]7 [
  8.   template: '<h1>自定义组件!</h1>'
    % Z+ m0 U. @) `. f. v
  9. })8 g0 o8 U; F/ F9 U- X% h0 A
  10. // 创建根实例3 D& A$ `: H% B& M( N+ k2 q
  11. new Vue({! L9 h+ v) }9 |
  12.   el: '#app'
    * R1 j7 _" A- u5 [0 ?/ A- j
  13. })
    : ^6 {* |  |+ d% c5 h
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

; R1 E  z: ^  e1 {9 f2 h
  1. <div id="app">. n/ X" ]; t2 |: w
  2.     <runoob></runoob>
    , E. }* M$ Q* y" f; s8 ]: W
  3. </div>
    , {# k) _& a% e7 D

  4. ! s" R% n6 j; t
  5. <script>
    , G9 H  o" O- d: P$ T
  6. var Child = {
    ( p6 g/ W5 @6 P
  7.   template: '<h1>自定义组件!</h1>'; ?) ^+ R0 K3 _8 {5 Q; |
  8. }
    6 l" r) W+ p" H% _. w5 k
  9. 5 J+ r' g8 v$ n% N
  10. // 创建根实例% ~8 i. T, ], d, o* |8 b7 R
  11. new Vue({8 }: R; Q) F  u9 r) F
  12.   el: '#app',2 @8 e* H; F- i4 m/ C
  13.   components: {* E0 _) S; b$ J) ~
  14.     // <runoob> 将只在父模板可用
    6 ~( i2 F' ^: @1 j9 o) C4 L
  15.     'runoob': Child
    , N0 O! L% M9 ^: a/ g, O) f
  16.   }
    5 C4 d1 i" n$ S# l5 i: B1 L) J0 v
  17. })
    ( K& }. Y4 X& e8 Y9 q% V3 I% C
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
7 ?+ Y0 [; T+ ?7 A
  1. <div id="app">
    8 S# o$ I  [9 W2 c1 [
  2.     <child message="hello!"></child>
    . v0 O, P0 e. k
  3. </div>
    ( v/ G' _' m9 S' L5 y
  4. 1 M% p* [5 n2 {& X0 U" J& h5 u
  5. <script>
    # X3 Y$ w1 A" T/ w: o
  6. // 注册4 g0 O& |" j9 x
  7. Vue.component('child', {9 H+ c# L0 o& Z+ c3 K2 ?6 @% [  C* e
  8.   // 声明 props8 Y3 ~" h/ u/ @% k3 Y* B9 \( b
  9.   props: ['message'],
    6 D1 l# J9 a' g5 }9 V
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    % k3 g/ e) z3 v8 j! U9 A' F" M, D
  11.   template: '<span>{{ message }}</span>'/ {" u, q2 `+ h7 @6 c
  12. })
    1 z5 W. p0 j4 k
  13. // 创建根实例) V" m- w' r% i8 s, E: F
  14. new Vue({' [  N2 H' ~" @# [8 U5 Z
  15.   el: '#app'$ c4 d# J( D; W2 f8 ~5 i& ?$ R! P
  16. })
    ( @  C- v. i, {: v  a. E" H$ i$ i) ?7 P
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
$ B! k% o* F5 A
  1. <div id="app">
    4 A6 {  M% f/ O
  2.     <div>1 D1 T- [, X# H" M3 U
  3.       <input v-model="parentMsg">
    9 F* D3 _) R( ]$ j
  4.       <br>
    - [4 I" H8 H; |% y' g7 p8 @6 Q
  5.       <child v-bind:message="parentMsg"></child>
    - X8 J" N- Z0 E6 P8 g
  6.     </div>; t) {- L" r' m6 u
  7. </div>
    0 u7 K/ I* j5 ^, _( d' p

  8. * K* p0 A7 d! s0 n' Y# s: B
  9. <script>
    " J) q$ y: o6 M7 l
  10. // 注册
    , P$ o* ^+ Y5 g2 Q
  11. Vue.component('child', {' a( \1 @0 c" s$ @, w% I6 u8 ]
  12.   // 声明 props  [9 W, n5 F+ n- ^8 Q
  13.   props: ['message'],
    5 ^. K+ J' {2 J( E" e! H9 s
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用  y, t1 K1 F3 O1 }! W
  15.   template: '<span>{{ message }}</span>'* P4 @1 T1 d& i" S' j
  16. })
    , n. ^) x4 R& Z4 X% M/ |
  17. // 创建根实例
    ' n; M& @, |  Q* r6 D
  18. new Vue({3 m4 y2 K6 r( G8 T1 Q
  19.   el: '#app',# ]8 O6 c1 W- u: P+ i# X4 }
  20.   data: {
    " T' Q+ K% l. S. {, u
  21.     parentMsg: '父组件内容'  @: y3 G; \4 c' S- J* M+ V" d
  22.   }
    / V! G( ^8 _/ ^1 p, v
  23. })
    2 K+ \; Y  ~7 L" \: L
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例5 E- t4 V( h( n6 N- u8 z* b
  1. <div id="app">
    6 X+ @. D; Q1 R3 l
  2.     <ol>
    4 ]8 }! N' w2 A2 S) _$ [
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>4 u9 ]# R! e: }6 Z
  4.       </ol>
    , k6 \9 I, b! `
  5. </div>
    ) z, }% r. x0 x) h4 p

  6. , Z; E! \( D3 B& i: ?6 ]- [
  7. <script>( g- q8 H9 s% X! C
  8. Vue.component('todo-item', {
    6 W8 y$ p' }* n' u: y- I6 d  \: x( h
  9.   props: ['todo'],
    0 P4 l( h6 I# @1 x+ G4 W
  10.   template: '<li>{{ todo.text }}</li>'
    8 [6 T* G9 x2 w/ |$ `- d# I
  11. })
    " M- S  N8 ?7 x6 n' f9 J3 D
  12. new Vue({1 X( f8 d* B) N. h  R* E+ q
  13.   el: '#app',
    1 H) r+ p$ z( w
  14.   data: {
    7 z8 {9 h: a7 Q* e* ]
  15.     sites: [; c! C* d( d0 d& [
  16.       { text: 'Runoob' },% l0 c( r7 t. O
  17.       { text: 'Google' },
    7 ~4 q4 h1 w2 k7 k" n: I1 ]+ |
  18.       { text: 'Taobao' }- d( Z3 g" R2 j, P
  19.     ]
    0 X/ I  |# v9 F
  20.   }. G! E6 [1 p$ ~: g7 a
  21. })  W6 u, a8 w1 `0 F9 q6 `% `# p
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    4 D+ `, o0 U6 O
  2.   props: {# A4 ]7 j2 G# C% {' B( n/ |! a
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)( C( O& q. O# t% }- ?
  4.     propA: Number,8 U; O' I5 `1 P7 k& n/ U2 _
  5.     // 多种类型
    4 J' Y" K/ j2 L8 w) L
  6.     propB: [String, Number],
    # \( O1 b+ [% n- K- l; w
  7.     // 必传且是字符串
    " j% j) D# ~0 L: V9 H' r' G' `+ i
  8.     propC: {& H& r$ l& f: D
  9.       type: String," J" }7 m) N8 s
  10.       required: true3 M1 ~/ x: ^9 D6 h* V
  11.     },$ o; S6 C* K- w: F
  12.     // 数字,有默认值8 a8 M8 x& ?  e/ h
  13.     propD: {
    + S  }- s* f* D. }: G. i
  14.       type: Number,
    " k! _; m: O" M# E
  15.       default: 1009 k# o" w' t/ Z# i
  16.     },
    0 U# `3 D' s. `- V  @7 b2 ^
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    3 X, Y2 i* ]6 V/ F' K1 u- `
  18.     propE: {
    - }* H' t  o7 `. p# y/ B4 y
  19.       type: Object,' u7 j, o( C% \+ f
  20.       default: function () {$ H5 }) ^0 j) d$ q4 k
  21.         return { message: 'hello' }
    5 F: y! A+ p2 p" R5 k' M) }% [6 N
  22.       }
    6 R5 |% z! x' C! K
  23.     },, L* z  G8 l4 h8 {( s! V; k
  24.     // 自定义验证函数
    5 d3 Q% b+ T8 [* h
  25.     propF: {
    / j6 Z1 ]! p9 q" ?# d7 N7 Y* b2 I7 O4 o
  26.       validator: function (value) {
    $ f) p! O1 L/ ]9 L" T  @8 w
  27.         return value > 10
    ( H/ [' i) b1 `: o% K2 M' o
  28.       }
    7 L0 J: Z0 K/ E. @
  29.     }
    $ O% O7 S7 f3 U
  30.   }' K. ?& V# D7 A. ^8 ^
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array8 ]+ W. x+ d$ h# W" |5 w2 X+ Y" k
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件2 a: m: ?& v9 A
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
( c5 `, E5 i% D3 U) r( |9 m8 G' D
  1. <div id="app">0 }# d, Y! o" u# X, x3 u5 r, t( a
  2.     <div id="counter-event-example">
    ! n' M  a9 A% A% `3 P* [
  3.       <p>{{ total }}</p>
    : ]2 T( l  M4 P4 s6 m
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>( U3 C" b) n4 K2 G* G; B+ O
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>" o+ F( \' L5 X. |. J6 @
  6.     </div>
    4 R4 r0 n7 }5 @8 ?) _3 p6 o" A
  7. </div>2 Y  |: b2 T% o6 P+ K3 L
  8. , C4 t8 L5 ?& J) U6 K
  9. <script>  d6 I' B# B+ N4 N1 \$ H& c
  10. Vue.component('button-counter', {1 P( _; u- l5 k% R+ V1 P7 ]6 H# Z
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',2 D+ y( d% t( o$ j
  12.   data: function () {
    4 }5 X/ z. H7 k
  13.     return {
    5 n4 G. E- {  p3 C) S# G
  14.       counter: 0
    % b' O  A8 {* R8 W/ I& v# c2 E
  15.     }0 C  v; J! l/ x4 L0 l, T
  16.   },
    : f0 r! E- n, i7 X% p. s# L$ D. ~
  17.   methods: {# j: `: m2 g" ]
  18.     incrementHandler: function () {
    ( t4 O' n. k; J9 f& `- J" W9 c1 b
  19.       this.counter += 1
    ' I# l( z3 G" ?% d
  20.       this.$emit('increment')
    , E( {: C: G+ x& w. m
  21.     }3 c& W. n$ r# [, _1 B" |
  22.   },
    ' z1 A  X3 Y0 A+ u/ W) C
  23. })
    9 c, t, E  N3 F! W' H1 `$ c: ]
  24. new Vue({
    - X  A7 s! A% L7 \, {1 y
  25.   el: '#counter-event-example',
    ; L/ N/ K$ H+ e
  26.   data: {
    ' x* j9 `% g& o+ W0 w
  27.     total: 0
    ! U3 N8 c+ O0 ?; p( A( s* T
  28.   },7 J/ ]' @1 ~; v& Y% N! c' f
  29.   methods: {
    & i! O8 o9 t" }
  30.     incrementTotal: function () {
    7 }) H! E! w7 {
  31.       this.total += 1
    : e0 e) v; u& ~0 r: s$ b1 t8 b
  32.     }
    8 ?* R3 M6 ^; ^7 b' a
  33.   }
      @% p* C8 q$ W2 v' P9 V7 j
  34. })! f4 z, {2 Q4 o) m6 H6 _
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册2 e$ ]  s: {5 |
  2. Vue.component('child', {
    + ^; Y4 g' N, W; Q3 V. v
  3.   // 声明 props: _2 J+ y4 ?" T% p/ O- U5 a5 Y" b
  4.   props: ['message'],! \& O/ s, V* S7 M3 C. E5 ]
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    6 `+ U, A. g) ?
  6.   template: '<span>{{ message }}</span>': p5 `) @% [4 f- @/ e/ B
  7. })+ O+ f' I) z- {  G+ A7 Y( @
  8. // 创建根实例. B$ U$ s" N/ V( Z5 j% ]
  9. new Vue({
    ; |: u- j/ U* S( x" z6 P
  10.   el: '#app',
    . }% @: l. z- m! G2 w
  11.   data:{
    ( Y' F% t- S1 ~7 r0 N- P
  12.     message:"hello",
    9 W# e1 W6 y) a% S
  13.   }' n$ C8 v  O1 R9 f7 F. B+ z9 u
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {; a% k; k+ G9 {
  2.     incrementHandler: function (v) {
    # P4 p! e" q  g" Z
  3.         if(v==1){
    4 \. o* h( C: r
  4.             this.counter -= 1: O# Q" [3 w! O; C  x$ |: i4 i
  5.             this.$emit('increment',[1])% ?4 t8 ~' d/ h) x, M4 |
  6.         }else{
    - K6 @/ _; S. ?& P
  7.             this.counter += 1
    9 g, K/ z' h7 l8 S, ~! e, c
  8.             this.$emit('increment',[2])% o1 A4 X" V, C" D% v" H
  9.         }
    5 A8 i- H( X# S- j, P
  10.     }
    0 r  Y9 q4 H9 F- g
  11. }
复制代码

- x6 w$ X( R. U9 Q# [6 ~/ p, d& ]9 |4 ~
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-11-1 11:45 , Processed in 0.138325 second(s), 25 queries .

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