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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15647|回复: 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,并使用它:
$ w! V  f7 b$ {" D/ y( Q+ c
  1. <div id="app">
    0 m, x# L$ g/ e
  2.     <runoob></runoob># t" {) c& e: T; F
  3. </div>
    ( B8 ~8 }. ?" }/ b! u  \
  4. 4 U9 [3 j5 d  L/ p  J
  5. <script>- \' e# C; L5 d
  6. // 注册
    ; w2 ^, Z. y* ~/ d5 r8 B& F* p
  7. Vue.component('runoob', {
    " r1 y4 _) O8 e0 ?) v8 \9 b
  8.   template: '<h1>自定义组件!</h1>'
    9 W" D: T) ]$ v
  9. })
    : t0 k. {$ ?& H( x* V0 o
  10. // 创建根实例1 \2 N; w' A% K5 x
  11. new Vue({
    ( d5 I  n: G; M5 o2 z0 e, R! @
  12.   el: '#app'( @& O+ K7 e" J
  13. })
    0 @. f. J- f  \2 N
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
+ A+ }* a1 {' h( w$ k7 R
  1. <div id="app">: Q+ V( R( B  b1 \6 j3 E6 v
  2.     <runoob></runoob>
    $ N: J8 I& o: D0 S! C) D: k
  3. </div>* L. N$ Y+ W; g9 m) @
  4. # Y6 H  u, M& J, b& B) _% o( m
  5. <script>
    3 n1 o8 T* z/ m* m2 H$ S
  6. var Child = {+ |/ C% I6 g/ O1 B$ p4 f) `
  7.   template: '<h1>自定义组件!</h1>'
    ; M& P: t! J- w) @
  8. }: s+ D+ v. c( L. i% b% q

  9. & D8 `6 ?6 Q7 M* z2 S
  10. // 创建根实例
    8 Y/ [  \5 `+ b
  11. new Vue({
    / G. A( v1 F7 h/ f  J0 {6 f
  12.   el: '#app',
    ' u- v& C# E6 u/ Y9 _3 G7 v
  13.   components: {
    5 z5 v. {: t3 R& n' D
  14.     // <runoob> 将只在父模板可用; O) B% B( b7 W4 i5 R$ A
  15.     'runoob': Child
    % t, g: D2 _9 F' ?& e0 f- X
  16.   }1 E- h2 |( N* ~7 d2 J3 s5 |, A
  17. })5 p9 H4 W+ x( @% |0 B
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
+ m  `+ f0 ^  T, d9 \! b5 n6 b6 v
  1. <div id="app">
    " w! ~' l% b3 Q# l1 ]/ X
  2.     <child message="hello!"></child>1 K8 C' V- e: L+ C
  3. </div>
    . E; c: H0 T) c
  4. % v5 c" S& m) }2 ~% |% \+ {8 A
  5. <script>5 P4 q4 w  L. o9 I
  6. // 注册
    + g9 _* ]! y9 Q/ K' h% f# _" M$ p7 C4 W
  7. Vue.component('child', {3 h% A7 J* O) c; {
  8.   // 声明 props
    4 a. Y" N. N5 q$ J6 V( Q/ L* ^
  9.   props: ['message'],
    , r2 E1 X) s8 z+ J7 Z9 T
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    3 _) u+ V2 J& S% K: Z! C) ]
  11.   template: '<span>{{ message }}</span>'
    8 G+ `$ F+ o( u) V1 c/ B, ~" G
  12. })# x! B8 y7 j, j8 z, E( T
  13. // 创建根实例
    7 u" ~. k2 e# ?' N2 A
  14. new Vue({
    ( Q0 k" e$ G1 K
  15.   el: '#app': T5 u9 o+ n4 L' f$ _- l- B" W
  16. })5 e1 O$ y  I/ r  _
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
: x4 W; e' `. Y! z
  1. <div id="app">
    . }, a' k/ ~+ J
  2.     <div>
    % X3 M8 Q& D4 L2 V! V# f+ a$ d
  3.       <input v-model="parentMsg">
    ) E. `5 ?+ W* q8 C" p5 O
  4.       <br>
    5 J( {2 A+ h, ?  b8 a3 |- g
  5.       <child v-bind:message="parentMsg"></child>
    0 N7 V; f1 ~7 ?6 P$ {
  6.     </div>
    ( [8 `' D* e( P6 z5 @, d& O
  7. </div>1 S% F7 Z5 G: y" \4 N1 h
  8. 3 B# H2 |3 ]2 V0 c% A0 m
  9. <script>/ D3 v2 I# C9 N* U- m8 b' d3 Q
  10. // 注册
    * `3 H8 k% E1 m; U( K# o
  11. Vue.component('child', {
    ) X/ H4 O+ i5 M2 l, U5 A# U: v) n. Z3 l
  12.   // 声明 props$ v/ i9 c1 g2 W( `
  13.   props: ['message'],
    5 m2 F! ?2 Q$ D, b- Q0 f' u
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    $ @/ @3 m9 {" `- \& b1 e9 r
  15.   template: '<span>{{ message }}</span>'
    . `, n0 b$ Z) u# @7 j' Y  P: s
  16. })1 F0 f2 K8 p. }. q9 r( N$ S/ \9 x- ?
  17. // 创建根实例
      ?. e7 ]' E* q* @4 i; @/ N" ^" {$ W
  18. new Vue({
    . s$ K) b  x2 Q( t9 c
  19.   el: '#app',
    % w4 e: C; X) V) g2 I9 X
  20.   data: {9 L( u0 M" X( \! F  L. @: R
  21.     parentMsg: '父组件内容'
    , l6 m, O. v% N# Z- q0 b. f% Z2 U: J
  22.   }
    ) @: S1 ]  `1 f8 h4 `
  23. })
    + R; q& \" E4 N6 P& s
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
# V8 W# v) a/ D6 q6 S0 m
  1. <div id="app">: L7 u, O6 I) E2 u" v
  2.     <ol>
    4 R$ n. H! ~! ?# H4 _8 q4 d
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>+ |" R  g# N5 z8 K' z4 p
  4.       </ol>
      H! \. S7 s' z/ R# f7 e9 a0 G- Y
  5. </div>
    6 Y/ h( Z" S( P3 S6 T: L6 ~: i

  6. & p2 B! g7 b' f8 }* q
  7. <script>4 K, N- N$ p! m" N7 G! _+ k- }) K
  8. Vue.component('todo-item', {
    / a1 ~  ]0 z; H7 u( j; ^2 o- b5 T
  9.   props: ['todo'],* s8 B4 `9 ?7 ?% x& e0 x) c
  10.   template: '<li>{{ todo.text }}</li>'
    9 @# F. t2 Q, w6 s! j, U8 y
  11. })
    # i- I! A) l' g
  12. new Vue({
    ; {6 D8 E2 I' I7 Z# [) ]/ q# t
  13.   el: '#app',
    & G' s3 R& d3 ]+ ^0 ?
  14.   data: {
    9 d/ J8 \& U% s: w
  15.     sites: [1 Z! m- w- r! N
  16.       { text: 'Runoob' },
    1 `/ y. D* _+ n" V: H) o
  17.       { text: 'Google' },
    2 w+ T0 ]: M' x5 u
  18.       { text: 'Taobao' }
    2 t2 l( z1 [; D4 E2 p& T: d( U
  19.     ]
    % X4 c+ s( U. y
  20.   }
    % d7 y, _! H+ H/ _# u7 v/ V7 ]
  21. })
    / h. G: \! k! c9 s
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {3 R  L+ x  E3 x& l. a7 h
  2.   props: {
    / }1 Q6 o4 u- I" _  w+ P! _
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    3 b6 }! u* g  q. W
  4.     propA: Number,8 ~; ^5 X8 R6 Y- u1 u
  5.     // 多种类型( s; A: R" ~! v/ Q6 Z; p
  6.     propB: [String, Number],
    " m! ?" J: _+ d
  7.     // 必传且是字符串0 s. x3 e1 k' R" B
  8.     propC: {
    5 Q* V5 K1 K7 Q' S2 R3 i
  9.       type: String,
    5 M& F, c0 b" t4 }, {
  10.       required: true  P5 A7 C( ^( v3 q
  11.     },# Y" P$ F; o+ z$ Q( f, C9 ^
  12.     // 数字,有默认值
      O! F6 _% `) l. A
  13.     propD: {* x' K: F: |! y7 L
  14.       type: Number,# T$ n* _) A- K$ F# T
  15.       default: 1009 d2 N6 n+ |3 I$ t5 \4 c
  16.     },: y, L" Y% |  s! H1 {2 }
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    / k. I1 z6 N8 }0 @/ X5 i2 C
  18.     propE: {
    ' M1 X, d& W7 O
  19.       type: Object,
    / J1 h; t' X6 m7 t3 u2 @
  20.       default: function () {: l# ]: G5 J8 ?7 I- m7 k5 `+ K' r
  21.         return { message: 'hello' }/ n4 H) y& e; k0 G7 d; u, F+ T1 e+ e
  22.       }( Z7 k; L4 Y6 X9 g9 P/ o9 c/ j& m
  23.     },( z" \' q+ D* g, T) e9 }9 `; C
  24.     // 自定义验证函数$ c0 k+ M( _8 N+ ^
  25.     propF: {8 A5 A( H/ p6 {5 P* t4 _* ?
  26.       validator: function (value) {
    6 b* v$ B# e, T: A% `9 L; |
  27.         return value > 10
    8 Y6 Y+ }/ {3 z; S% I1 L# L
  28.       }4 p) G& A0 @1 }; D
  29.     }
    ! v0 o- m1 z2 M" n9 L
  30.   }: l+ D6 j# R" `5 E9 q5 z( v
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array# @: ^+ i7 K; o' j# Z# @" X
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件% Q5 C/ _% O% {* J: u0 d
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例8 o4 S8 ]9 Q: ]. I8 E) x4 A2 p
  1. <div id="app">
    / d! F1 u& \1 _
  2.     <div id="counter-event-example">6 o, r+ r, G' S: l9 C; A: `8 T
  3.       <p>{{ total }}</p>
    8 e! ^( x( o0 f  p
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>; I, w7 ^% X; x& w& g: J6 x$ W
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>3 K/ ~2 t) l+ B: @
  6.     </div>
    6 _7 y# U9 T& m2 B- l3 \4 w
  7. </div>+ k0 u) r9 B* t; j- S" E

  8. % b  i2 r  U: |& I$ g
  9. <script>
    4 S" }8 J2 M6 D
  10. Vue.component('button-counter', {
    ! U& a3 Y- }8 e2 K! L5 X' S7 T  N) t' r
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',) o* V; o9 D3 G2 g
  12.   data: function () {( \2 i6 q2 @/ Y8 @* ^- \; H* ~' F
  13.     return {: c9 r: e8 W2 L
  14.       counter: 0
    1 c% s1 x9 Z; j& v. n8 x3 C9 ]  T
  15.     }% q& J( C. n( y& X5 H  J  c
  16.   },
    2 w' j' W! S" F
  17.   methods: {
    6 r% g: F$ P. T# B
  18.     incrementHandler: function () {* I5 G8 I9 g; \; o/ u- H/ r
  19.       this.counter += 1. P' ^' H2 o( l: E; L. J- T
  20.       this.$emit('increment'), p, T& `4 A6 B8 x1 \; V
  21.     }
    0 P  U1 Q5 ?) S: g
  22.   },
    & y. z% i: o" M- G* s1 a* @" @
  23. })
    2 j) g- ^5 u- D& ?2 \
  24. new Vue({
    / L% V: O& E# P# W% z: E4 b
  25.   el: '#counter-event-example',1 c9 |4 b9 V" m) r. Q
  26.   data: {; c$ v' o- P  o: ]5 \
  27.     total: 0
    % r. b& H$ T1 G0 e) D4 [- M9 U5 Q
  28.   },
    ' c2 q% s6 L* {
  29.   methods: {
    # E# C6 _1 w1 O
  30.     incrementTotal: function () {
      L9 d  I& l+ i# N1 ?, B# K
  31.       this.total += 1: J+ ~" z8 f: f6 u, X" H
  32.     }# c( W/ Z0 r( \" o
  33.   }% @+ c  B: h* g& b
  34. })3 D0 X. C) y% [4 ~3 f+ U
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    2 O, h9 q( V7 Q- \; A- z
  2. Vue.component('child', {
    5 x: J7 e) d4 c# J( @1 [
  3.   // 声明 props
    3 F$ G' N$ a' u9 T. V0 e6 D
  4.   props: ['message'],
    ! S" J+ ^+ C; f) p" `) y/ @4 D8 x/ Y2 f
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    , G) ?# Z( G& l0 k" G8 I, ]
  6.   template: '<span>{{ message }}</span>'
    8 {9 M& p6 r+ H
  7. })5 A1 M* o' K1 h( l6 i
  8. // 创建根实例) Y! p% O. U' a& p6 |1 ]1 \; a
  9. new Vue({% _) k8 r3 m0 q. I" ]
  10.   el: '#app',
    * j- E2 i2 p1 |
  11.   data:{
    4 ?/ t6 G1 ]( {+ p
  12.     message:"hello",% r* M6 Z; O8 |
  13.   }
    & Q! a" _# N1 f" k) f- G/ M
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    # }9 C. i/ A1 [" z
  2.     incrementHandler: function (v) {
    - X2 X$ ?& z0 N: \- e
  3.         if(v==1){
    $ F( s& W/ f/ F: |1 M, l
  4.             this.counter -= 16 {% i! V* l9 P0 h/ S: e! |4 o& E4 |
  5.             this.$emit('increment',[1])
    7 ?1 E3 F9 I: `4 B; ^# ~7 h
  6.         }else{
    9 E! A* H9 L6 o6 E9 L( Z* e
  7.             this.counter += 1
    " k9 q) u8 J1 g5 o# \; h
  8.             this.$emit('increment',[2])% X/ S! e. V4 `* w  N, M, }
  9.         }
    5 O! e: N0 u- C% U: y! a
  10.     }+ r1 ]* [' F9 w  d" S/ R  \8 Q
  11. }
复制代码
) {8 f% a2 h2 s( b4 b" t
! H* d! ], x% ]- U) [+ h
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-4-30 19:57 , Processed in 0.072641 second(s), 23 queries .

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