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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 16292|回复: 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,并使用它:
3 j! o! T* @( A6 Y  `3 l; r  g( G( o
  1. <div id="app">2 ^# C/ G! i6 A$ P3 z
  2.     <runoob></runoob>7 N/ `  X# l. O. C/ O  b+ ?
  3. </div>
    0 @5 {" _) ~! `1 d- l9 k* l
  4. 6 S; A3 [% |; ~$ H" _
  5. <script>
    : n! m. D7 A4 O- d, N
  6. // 注册
    8 c; N7 a$ ~8 n. M6 V) `
  7. Vue.component('runoob', {
    3 S1 B) ?& }1 E: I9 G
  8.   template: '<h1>自定义组件!</h1>'
    7 W; Y. Y+ z/ Z7 L/ s; ~, }
  9. })
    + V& n' H& ]* P3 p5 y- `7 U
  10. // 创建根实例
    ) g9 f0 ]6 m) m* a$ e4 G" O
  11. new Vue({/ l1 [7 s4 n: ]: Y6 @
  12.   el: '#app'8 y- ~" t* X# r
  13. })3 \3 C% i9 t3 w% D/ {; A/ ^! Z) h) y' N
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
& d3 m  z7 A' y- H3 c% v5 d: a
  1. <div id="app">  R5 T+ Y# q# t: e
  2.     <runoob></runoob>: X! F: G' V- K/ @' \% J
  3. </div>. g0 Y8 @) l; c  F0 Z
  4. 4 ~* ~- p) x( T+ F- e
  5. <script>
    2 v! k& R! ?3 x* Z3 E
  6. var Child = {1 K* h' k, m/ W7 F' J: e: e7 |
  7.   template: '<h1>自定义组件!</h1>'7 ?6 J1 Z# w! \1 \$ Y2 I
  8. }
    " E( d! U) x: F8 C: d
  9. 4 h/ _2 A7 v: u2 a* q! s
  10. // 创建根实例. R- U, }. t1 s0 m
  11. new Vue({3 u9 U. c" Z+ o, a  i, M  h( d6 G
  12.   el: '#app',
    0 u( V8 m  D5 r8 F
  13.   components: {
    3 y% M5 ?# ?8 ]  l
  14.     // <runoob> 将只在父模板可用
    * h2 j1 s2 }* u4 k
  15.     'runoob': Child
    0 G0 n6 i4 ]2 }* |
  16.   }4 O! s4 G, k6 j2 ^
  17. })6 a+ m' A7 n  |+ w' Z! S
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例: d5 E( A! g4 ?/ r
  1. <div id="app">
    8 R1 `/ j8 \- k1 G# T
  2.     <child message="hello!"></child>
    : T3 W. [0 f0 {( [2 ]! l& k
  3. </div>% W' {. N) t1 c$ H' Y8 F6 {9 P$ N
  4. / s: l# n* G3 s+ ^+ Q# ~% b
  5. <script>1 k5 B) P4 e5 I9 O
  6. // 注册# h( F3 ]1 w' f% ?( T/ Y
  7. Vue.component('child', {
    " [' ]! j7 \- I6 E' F+ J1 G* ?/ k
  8.   // 声明 props
    + l4 Q5 @7 Y/ Z9 |/ {8 m
  9.   props: ['message'],9 ?1 Y' {4 v, f, |" w
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用) w' T/ h8 T  i0 m! M4 _
  11.   template: '<span>{{ message }}</span>'
    2 P3 m  G1 B9 @9 \8 O. m, U
  12. })
    ; Y) J4 g0 u$ i2 h
  13. // 创建根实例
    9 ]3 X/ q" P. i3 E+ X. t' {
  14. new Vue({  V( d! W3 B% Z0 ]/ Q+ `; F
  15.   el: '#app'
    % T* {6 q. B: _9 ^3 [; f
  16. })4 f$ i8 b9 ^: B4 w3 C; V9 L1 _
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
( P( l$ T7 D" r' t- Z/ x. m* T" d
  1. <div id="app">1 x4 }1 _) M) c6 t8 a. H5 R
  2.     <div>" y! H5 A$ l" j, P( d
  3.       <input v-model="parentMsg">) B! W8 v, \1 U( p: c7 l. w
  4.       <br># d* P2 B' V8 {7 I# ]* O
  5.       <child v-bind:message="parentMsg"></child>
      r+ ]- S* P6 m: ]
  6.     </div>
    7 J- D0 }) L! ~# C8 M
  7. </div>0 V( t! A+ f4 B% o$ m
  8. 7 V* n4 s3 d; D3 E0 s6 U% {
  9. <script>, r. N' n3 K3 X  B
  10. // 注册! z: h8 H3 v; C' p- M- M0 U3 B6 ~
  11. Vue.component('child', {
    ' m9 y* D8 ?1 e7 I, M1 S9 t
  12.   // 声明 props$ A; D' V) l& E6 N7 ]
  13.   props: ['message'],( H5 h2 e& s& Q7 ^, S& Q
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用9 b/ u+ x+ L0 K* E& d, L5 }
  15.   template: '<span>{{ message }}</span>'9 I6 k5 f' p# O: L! s- x& ~
  16. })( _- N: Y2 V* K/ W! c" {
  17. // 创建根实例
    7 z9 a) t. l2 }& W% |
  18. new Vue({
    3 \& d+ @4 x7 h7 b' \, X, f1 q
  19.   el: '#app',2 t( f' L+ j, j. x* G
  20.   data: {3 a* v0 \5 p) c2 k
  21.     parentMsg: '父组件内容'
    ( l0 c* F2 F7 [  n4 H" `
  22.   }& x: F! m) F" J
  23. })
    * ?9 D& i2 R! ?: J* L2 ~7 O
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例- g' T$ @- V: Z; O2 |0 K; M
  1. <div id="app">
    ! S- Q" t2 U4 ~8 v6 R% A
  2.     <ol>; a! F7 _: V0 y5 Q
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    ) P7 v3 \  S- \8 U& w' Q
  4.       </ol>+ _0 j1 `" I) A7 G% l1 _' _% N
  5. </div>7 t. `! ~1 A) i9 X/ B

  6. , T8 V: z7 k- Y; t& W1 \" |
  7. <script>
    ; T9 C: k3 Z5 |+ L- J& ?
  8. Vue.component('todo-item', {
    1 d* n/ j! D. c# n6 \3 b
  9.   props: ['todo'],( }- t5 Z) E; M" p6 d/ ^8 L" ^: V
  10.   template: '<li>{{ todo.text }}</li>'4 R! V$ @* y/ ?
  11. })
    3 u' A# g. {7 f$ b- a
  12. new Vue({
    2 j8 W- D0 h* @, s2 n7 s
  13.   el: '#app',6 G5 F* V3 a7 s# _" E
  14.   data: {. J8 M  o3 q/ _) u) b
  15.     sites: [* g) d! }2 D; a8 [8 d- M  {# M( f
  16.       { text: 'Runoob' },2 l7 N1 P* T1 @6 B% C' |8 h$ B8 a
  17.       { text: 'Google' },4 }6 ]; k) S" [1 f' h
  18.       { text: 'Taobao' }5 n6 C5 V6 M7 K% f2 J' H
  19.     ]
    ; d3 f" S" s$ f, y4 a& o- \
  20.   }( q, {: y6 O, w3 j( w
  21. })- H! j& S8 D& A: I
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
      W' d: b3 p) f; J- |# P/ p% Z/ f
  2.   props: {
    2 p3 ~* T. Y( L6 V, [: u6 g
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    * b5 v: D; Z: X" D' \, w
  4.     propA: Number,
    6 p/ U5 t- r) ~: n/ ^$ O* Z
  5.     // 多种类型1 H# P  g5 t- S  K. g
  6.     propB: [String, Number],$ h5 ^* F* H  j6 @
  7.     // 必传且是字符串9 S9 f& p/ D# U- \# K
  8.     propC: {+ G+ w- x/ J. b% H' w9 f3 M: g) X
  9.       type: String,3 ^* z2 |, z6 w) ?4 x. D
  10.       required: true# h1 a' I$ |) |. t2 _5 g0 n
  11.     },
    + d( o" |' P6 i* M$ T
  12.     // 数字,有默认值
    8 f; J! b2 S4 \7 ]
  13.     propD: {, s% ?) X6 s' m6 [% C- h$ W
  14.       type: Number,7 c7 h( q& d* O, F) t' f, e$ Z
  15.       default: 100; v9 o, y/ O& b! z! U3 \. L
  16.     },$ _0 ]7 V# P' @, T
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    * H9 m$ ^. y' E7 D  M* S6 D7 [
  18.     propE: {
    ! o) h* I9 \8 T- j
  19.       type: Object,
    5 {% ]1 w# `. V9 x# u$ a
  20.       default: function () {
    1 W4 [$ \7 ]# v, [8 u1 O
  21.         return { message: 'hello' }
    * q8 w, p+ l  r
  22.       }
    ; X) y- \' S; ]2 V4 y& [/ g6 s' ]
  23.     },! {5 ~# v" R$ ?$ U, Z1 c
  24.     // 自定义验证函数
    5 A7 H9 N3 y- ]
  25.     propF: {
    8 B, R1 V  y3 o* A" C
  26.       validator: function (value) {
    ! K) X* r3 d, x% x* R( ^2 X
  27.         return value > 105 V" G2 `1 w9 A& G& Y! r
  28.       }" a$ u5 m1 A9 K& Q& f; |( v( [3 i
  29.     }2 b9 `- a' L6 h; l
  30.   }
    ' G1 m2 R' M. f4 F  f9 N& [4 G
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    8 o  z; `+ v# `8 `) ~1 W) Y
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件8 ?# B0 `) v" O5 b4 u+ M
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例3 c' i9 F( A- n3 t2 @* p: U& W
  1. <div id="app">
    7 F. |( u. E- }
  2.     <div id="counter-event-example">
    , A& B8 W1 O/ O. r9 D
  3.       <p>{{ total }}</p>1 b" S' v4 @8 |) D# N0 J1 L; y, O
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>- J, |9 z0 a. p1 S/ t& B3 J
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>/ Q$ L* |4 m+ m0 j& s
  6.     </div>6 k% B" l6 g! S( r
  7. </div>
    * k$ q& E2 I" {$ u9 A/ W3 Q
  8. 7 O8 k" Q: g& |! W+ Q! M0 l
  9. <script>
    9 A8 g5 M( g* q2 o7 V+ `! S: ?
  10. Vue.component('button-counter', {
      b& \0 [7 m2 p% Y4 l6 ^$ E
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',7 \4 @: G" ~& Q/ R( n5 z4 ~% K
  12.   data: function () {
    - [5 ?2 q, P% R( r8 a2 G  ~# P
  13.     return {9 N% u: W7 e9 t/ ^8 e" _& t
  14.       counter: 0
    / V( b0 T8 c6 @& A% F: K
  15.     }0 e2 h; M; I' f7 ?) z
  16.   },
    9 q* M: [; Q/ K9 `- A
  17.   methods: {, C) {* ?  F, ~, H& E
  18.     incrementHandler: function () {
    7 Q/ h/ K- {9 A4 ~1 ]0 E2 o
  19.       this.counter += 1
    . K$ B8 S7 ?; E% E" ]8 K8 t' k
  20.       this.$emit('increment')% \# j# R( g; _* f$ K
  21.     }$ |" |0 S9 `9 }9 U0 ?7 c
  22.   },
    3 Z/ W+ ~+ {2 y  h8 n# U! S' R
  23. })9 W7 }3 r: T1 q* o$ b
  24. new Vue({
    ( K0 w3 F+ i6 a0 w6 B+ k0 E* N* b
  25.   el: '#counter-event-example',
    , N$ K# f7 E1 ]$ \
  26.   data: {4 `) O( Z; i1 L1 l- F/ R) Z, l* @5 I  o
  27.     total: 0
    ) F: P0 `8 _3 |
  28.   },* M4 ~& o" _9 E" d, E
  29.   methods: {
    ' g5 i6 f  d" f" C/ c  J
  30.     incrementTotal: function () {8 N# n  H6 z) k
  31.       this.total += 17 @$ g$ V# j" {0 s/ H' W+ p
  32.     }
    1 D: H) `( ~' r6 B3 [( V/ \
  33.   }
    6 a0 s" I8 {1 E
  34. })
    . a- N& v9 C$ \; u# `3 R
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    9 B4 S  W9 J4 H8 w
  2. Vue.component('child', {$ U2 N+ r( E3 ?0 p4 S  P
  3.   // 声明 props/ m9 l: r5 L$ `5 X& Q7 l
  4.   props: ['message'],
    0 b8 _( L) K; ^" H# ?, _& N
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    " r+ K" k' q( k( l, ]
  6.   template: '<span>{{ message }}</span>'
    ) t3 M5 u2 U1 ?! u5 j
  7. })
    " V$ W% u% D+ G9 p! l
  8. // 创建根实例
    : C$ f7 J6 `& X
  9. new Vue({) s* Z4 I! n1 i& o- n. y7 @
  10.   el: '#app',# M) L8 `  q9 ~4 ^6 [  y
  11.   data:{
    * s* [5 |1 g' O4 M4 H
  12.     message:"hello",. p; L6 z. ]# }2 n
  13.   }* o6 t: p9 r6 S& y0 v/ }  {" e
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {, l' t' r( \/ ~, v
  2.     incrementHandler: function (v) {. p! `- q8 x' u3 O
  3.         if(v==1){
    ) i! O# `; C9 s/ z
  4.             this.counter -= 1
    # I2 C* a, B, [' g( I% n. j/ u- Z' x3 A
  5.             this.$emit('increment',[1])
    6 L( ^9 N  T& F1 I
  6.         }else{
    & g! }2 ~% {8 B. t, _& h
  7.             this.counter += 1
    ! H# Z) n, |7 O- A% p
  8.             this.$emit('increment',[2])* _- {  v. ^0 K) z
  9.         }
    8 c, ?& _2 u& w. b8 I
  10.     }
    - T6 E6 ^! ~3 K1 q6 J8 X5 T2 O, f
  11. }
复制代码
8 M0 U  ]  ~  t4 t! k  W( E

/ X( |3 g3 t' b7 E- c& x
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

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