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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

2 v# v& _* B8 l0 R$ O5 e
  1. <div id="app">
    8 C; R/ [  D1 e# C4 o9 ]+ K
  2.     <runoob></runoob>
    # v6 d3 i+ G- ?( ?
  3. </div>  g6 T, W! T: b  @( c% R

  4. ' Y, l" p/ O, e# o5 T% m9 p
  5. <script>  R. h; D% ~8 `* q, X# H0 P
  6. // 注册; p3 O' \( I, `- `2 R% o- R
  7. Vue.component('runoob', {$ K: ?2 ]6 h' P, |9 ~2 o* `
  8.   template: '<h1>自定义组件!</h1>'+ y/ w! B) g7 v9 j
  9. })
    ( A* S1 E4 X7 U- T0 k
  10. // 创建根实例
    4 ^- H* z1 ]8 {, o& z
  11. new Vue({6 m/ w( m1 e9 E5 _2 }
  12.   el: '#app'
    & D3 ]/ h& ]  d9 ^. D! q' b( V! I
  13. })
    2 ~+ S( }# e! C7 g- r4 q9 l
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
9 [( P$ J; |" F6 r5 V5 @- F
  1. <div id="app">' ^: ~) @* t8 a4 E
  2.     <runoob></runoob>( i, B7 R; E% X" W1 S% L
  3. </div>9 m4 `6 G9 _8 b, w7 M9 U; e6 Y/ U

  4. $ C6 B+ V9 _5 f6 |1 B! _  t
  5. <script>
    * x% {5 |' e$ f$ U* Z
  6. var Child = {) R. J# f: u  z1 S1 B
  7.   template: '<h1>自定义组件!</h1>'
      v% J0 C5 A; C1 b0 X
  8. }
    - c  W& v" o5 V( s$ B
  9. 0 _$ R1 z# f4 J8 Y" q/ w
  10. // 创建根实例0 O; e# q- l, g1 v" P
  11. new Vue({
    " ]. \. F* s. U- M% d
  12.   el: '#app',
    9 o$ e$ M( e% `$ N
  13.   components: {
    7 `8 O) K5 x6 m1 H- s
  14.     // <runoob> 将只在父模板可用* k8 ]0 M$ @9 G4 j
  15.     'runoob': Child. t. p, B/ n' G, t7 ^' M9 T( ^
  16.   }( |7 U' u$ p0 D' `8 e% q
  17. })
    0 O* Y# h9 }! ?+ p$ l
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例! g* t% _9 `3 i' A% A! ^  y* j6 `
  1. <div id="app">
    9 e2 t% U) A( n9 y
  2.     <child message="hello!"></child>
    % d& Z  q* U' W) E3 N: k
  3. </div>
    ! e7 \1 y% N% i' R, f
  4. 1 Q/ U1 @8 o6 E' a' d& Y
  5. <script>: T7 W+ z2 e9 P- r; S1 ^* p! z, N
  6. // 注册
    # X5 g! ]$ p$ F8 U/ x; Y5 o
  7. Vue.component('child', {
    ! z' b- J4 G9 _# x/ E4 I
  8.   // 声明 props
    " Z5 a  ^" Q* ~9 O$ e$ J
  9.   props: ['message'],7 w" w# b; p1 E. U9 k0 {; O2 e' K2 _
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ! B9 N/ M8 R% ^  P: C) N) v4 k2 F
  11.   template: '<span>{{ message }}</span>'
    ( s+ Q+ p1 v, j: [8 k/ S7 B; J
  12. })
    : O$ k  C8 A$ t; I
  13. // 创建根实例
    & O9 B0 q7 H1 c- }6 ]4 Z
  14. new Vue({$ U2 L" d0 W. _# @# ^( b& `
  15.   el: '#app'
    4 f% ?7 w8 l1 H! K: W
  16. })  f" e/ w! O0 n5 C( i
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
. ~% k1 F0 ~% ?, ^; S2 d+ Y1 ?
  1. <div id="app">7 a$ c! N$ j9 G3 L4 h* n  V! a
  2.     <div>
    & w/ W+ ~1 e% {; @; [! N* ?0 A
  3.       <input v-model="parentMsg">
    / o" F8 W  u; q! c) m3 P0 x, c% E
  4.       <br>
    ! o' O( S8 F. k4 [
  5.       <child v-bind:message="parentMsg"></child>
    " X7 b( n  c& Q% q# ?2 [- R& N
  6.     </div>8 s1 m/ u: u& G- I4 M8 Z5 H
  7. </div>5 K& |! Q/ ~: o. P' B$ ?# d- u0 b  l7 \

  8. # T9 B. z- Z/ z% p* c' f6 T* K- F
  9. <script>+ W; t0 o; U& O: C, ]; Y- n5 f
  10. // 注册8 n0 @" Q8 B) y' q: Z+ @
  11. Vue.component('child', {
    ( D' B1 C% P0 D5 }
  12.   // 声明 props
    ) u# t3 g6 q- A3 E0 `
  13.   props: ['message'],
    5 x! L! H) y3 g7 Z, @3 h8 P2 k
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用* T9 v# n$ m! q) u
  15.   template: '<span>{{ message }}</span>'( e7 C$ V8 a  O- O
  16. })
    9 g, g* ?' m2 z- X: u0 M
  17. // 创建根实例3 t- f: g$ D7 r# ~: G' E' ]8 d
  18. new Vue({
    & |( @6 b; p& @3 U* g) |
  19.   el: '#app',
    , Q( \7 I8 F) J7 D5 L# J
  20.   data: {
    & f6 l  d& R% e; \- Q
  21.     parentMsg: '父组件内容'
    % r7 P- V" q6 N, k6 `; P9 Z9 z
  22.   }
    4 F* ^6 d5 I! P8 a% N1 C
  23. })7 {8 A0 C- G& \$ X
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例: `9 P0 R5 W% R* x6 E1 @" C$ X% Q
  1. <div id="app">! }2 I7 \3 |" K9 H0 b
  2.     <ol>6 F9 i( C  ^. B2 c, D# e2 I, z
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    , E3 b9 U  D6 H1 v; v. t6 v: t
  4.       </ol>: Y) }* t. R, d- e  z
  5. </div>
    ( s. Z" S9 X  n- b0 m/ S- y4 H
  6. , m1 S5 R6 L6 o: v  S
  7. <script>
    : ]! F% z: [8 x6 h2 ], a7 _$ a
  8. Vue.component('todo-item', {
    " G3 D3 v/ M8 i# R
  9.   props: ['todo'],
    0 p4 {" m7 ]5 V! J6 M
  10.   template: '<li>{{ todo.text }}</li>'  H0 y7 W7 T- ?  ^% n
  11. })
      ~3 P$ l: n- J: }& f
  12. new Vue({& t6 s1 Q+ K7 b! H4 W! g
  13.   el: '#app',! ?% l( E3 H" N# Y' a; q
  14.   data: {2 V! E2 A# `3 m; i0 _. c
  15.     sites: [
    $ O" i; q$ C2 i5 y" `
  16.       { text: 'Runoob' },
    , t% n$ G* j7 I1 o2 [( E8 R$ d
  17.       { text: 'Google' },
    $ _* c' ?8 h4 g5 f. n! o3 y/ M6 c
  18.       { text: 'Taobao' }& N6 c& r* _$ P1 i
  19.     ]$ e; ^( r0 _) T" Y2 j
  20.   }
    , X9 t0 ]2 d4 R' L  w7 x6 d( P# C
  21. })
    $ F: k1 I, J& L
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {7 L; d2 H' z7 V1 f& V
  2.   props: {
    5 Y( s) c/ `" z, R( N6 B: F' A0 b
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    ! b4 a6 @9 G  m" g# o/ D
  4.     propA: Number,
    , e  g6 }7 g( K& O/ x4 O
  5.     // 多种类型1 j0 y5 C: h0 ^; ^2 o; M! }2 N
  6.     propB: [String, Number],
    0 s5 N; U+ n5 P
  7.     // 必传且是字符串
    7 c+ p. C- e' `' |; s! q
  8.     propC: {
    ( O+ Y) T" C# d3 L1 d2 S% e
  9.       type: String,
    + c$ o* q5 w( ?
  10.       required: true
      Q0 [% M5 ~6 n% m
  11.     },4 q8 O) g& T6 ^9 b
  12.     // 数字,有默认值! R: c* }) M" {0 @  h, j4 i; M
  13.     propD: {
    9 A, q4 ]' Z7 g/ Z! }
  14.       type: Number,: j1 C# |9 E1 F6 m4 _! ]
  15.       default: 100
    9 x: l# _/ N9 p; G, P* h4 W$ a
  16.     },. ^$ c% ~* i/ m5 p6 B
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    + j. A; x& h- H9 G
  18.     propE: {
    9 h, A* ~: e: v2 a0 }4 {* a
  19.       type: Object,
    ! i8 [' y- E0 B: _5 P8 d' t
  20.       default: function () {, S9 }4 _) A. v) ^. G% g6 a
  21.         return { message: 'hello' }
    & I) z- k6 T* g" L+ l
  22.       }) ~* a# d2 ~7 a# G' w( @- a
  23.     },5 q( @1 _. ^8 z9 v% P! c
  24.     // 自定义验证函数/ `' h3 T4 S2 ~7 {, a& \
  25.     propF: {3 V+ ?  N5 d+ n+ S% z; j) `- t$ B1 f, C! s
  26.       validator: function (value) {
    5 Z8 ^3 e% ^1 G4 x. E! i
  27.         return value > 10
    7 p$ {/ ?3 X) @( [
  28.       }
    $ N9 }( ?! F4 G; i* c: T
  29.     }
    # l5 d4 ~/ |! v5 W( I
  30.   }2 o, K& E4 Z1 i8 {
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array. l( I& B( E1 H- c; n
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件7 \5 ~9 y0 j4 `
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例4 y0 g- m$ G. a$ }
  1. <div id="app">: N$ x4 H" B3 {6 l+ g* w: _, G
  2.     <div id="counter-event-example">
    ! b  y0 Q& N3 @
  3.       <p>{{ total }}</p>/ h# c4 k, b% Z
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>5 t5 R; C7 [6 q2 O8 C9 E
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>1 s) W: f) B1 Z, Z# k8 _
  6.     </div>
    8 ]: k/ ]# C( w! [  p
  7. </div>) a7 i' @) o& ]) b* s

  8. ) f$ F4 J9 g8 ^* s% ]
  9. <script>% c5 f! ?1 u+ W' Z
  10. Vue.component('button-counter', {0 `8 O8 z/ C% g: P  q4 t
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',, g3 ^! j: v! y+ C4 t; s- J  |
  12.   data: function () {
    9 K' M' \7 y" K( x3 G
  13.     return {
    % x6 m4 m9 R% O6 t8 s/ J. A9 a. _
  14.       counter: 0
    2 Y: d5 H! R5 e- d: {  G
  15.     }
    ; q( {2 _0 @7 A/ T$ D+ T
  16.   },1 l( R' {5 ^9 Z; L+ I; ~3 d
  17.   methods: {# D- O4 n/ ]4 V8 z% d9 l5 [. f
  18.     incrementHandler: function () {
    * v; o8 Z4 {: i) m- U  a# s
  19.       this.counter += 1
    % Z- a9 [0 I% D" @+ C# e
  20.       this.$emit('increment')
    2 ^! D) R1 N5 }) s6 O, z8 d/ B
  21.     }- Z- o2 L( g) n+ q& ]5 k; ]( x
  22.   },9 f* [- s8 p; Y* Z; K+ X
  23. })6 Q  s# e8 O8 q3 _% e# E. m
  24. new Vue({
    ' t  {8 y4 W+ o
  25.   el: '#counter-event-example',
    0 L) X8 H6 {+ o& s2 ^
  26.   data: {
      @/ N2 ~3 ?+ J" i7 Q3 d
  27.     total: 02 I& t/ }9 g0 g  b- V( r: m8 ^& t
  28.   },
    7 d9 z2 H' B" H% M- h
  29.   methods: {
    1 p9 u* y; b- N; e! {
  30.     incrementTotal: function () {- z9 ~9 n1 Z- r: b1 ]( K, S: Y
  31.       this.total += 1; v; F, i. V4 b# s' k
  32.     }
    % J. _% g* }9 |; j' ~3 r' U9 ^
  33.   }2 [7 O6 m+ B  V; K8 e
  34. })* H; ]7 p/ L' a5 S) R' T8 u
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册- D0 k3 j8 l4 w
  2. Vue.component('child', {
    ; y1 \) m+ A# o1 l
  3.   // 声明 props% V# ]3 D( m+ ?' S
  4.   props: ['message'],
    8 ^' ]: q0 V5 o# {' }
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用# F% t9 [- f( ], z% \
  6.   template: '<span>{{ message }}</span>'$ ?! x2 o, B3 w4 d5 @# p' m
  7. })% c; x% D! C# g! k7 o8 }
  8. // 创建根实例& Z( o8 N5 [$ `
  9. new Vue({
    2 d2 o4 q$ ]" w/ F6 E# ^- V
  10.   el: '#app',
    ) `  ~/ ^/ ?3 n  a* }! c) N
  11.   data:{9 k6 m1 i5 f& m; V
  12.     message:"hello",
    . y1 L2 h5 t1 ^2 n
  13.   }
    6 J( z- C  t7 ?
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    & P' x& W# x" s7 H+ E$ t' k
  2.     incrementHandler: function (v) {8 u+ I6 d( Z# S. m4 h
  3.         if(v==1){
    ; i7 {, b: N8 g9 D
  4.             this.counter -= 1
    5 n$ ?1 P0 |3 ^- `0 Q" M
  5.             this.$emit('increment',[1])
    2 @' W; Z' f8 e' s- F) l" b
  6.         }else{0 R/ Q- |8 m/ r: B: s
  7.             this.counter += 1
    8 m' I) m9 l9 D) T* D& C' A
  8.             this.$emit('increment',[2])
    3 X' Z$ g& x& V: Y- X
  9.         }+ d& Q3 y- z( J* x
  10.     }
    - I. {/ b( T, U* |
  11. }
复制代码
( W6 \/ C; m" Z0 o: Z5 I7 e
) l2 ?3 [3 a0 H- O  x7 z
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 16:30 , Processed in 0.130492 second(s), 22 queries .

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