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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

! t! ?0 J/ K8 Y
  1. <div id="app">
    # h) D7 _+ C# W  h. t+ c. b' Z
  2.     <runoob></runoob>  ?* W' v' ?. \# b# h- S  x: k( I2 G1 e
  3. </div>0 t; x6 t1 H8 N- f
  4. & x, O( x, c' ~% P% y" `
  5. <script>
    % B1 T( v2 {1 p  }' {: t
  6. // 注册
    & u7 l+ `/ L! i* N9 m
  7. Vue.component('runoob', {/ m6 u2 n2 {5 o- Y5 s- m; n+ G
  8.   template: '<h1>自定义组件!</h1>'
    * y; O; M! }8 V6 ^
  9. })" H1 J) F9 B1 Z& p+ D
  10. // 创建根实例
    4 P0 }" Z" U, q. J6 E1 F
  11. new Vue({, Y( U4 J' f; j% O
  12.   el: '#app'! r7 ?9 R/ O' M) p+ r$ A. B2 s) Z/ T
  13. })- o6 K$ T: V% E3 W. X
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
( Z# N" Z8 Y0 I" `
  1. <div id="app">$ [% H/ z& D1 S% Z
  2.     <runoob></runoob>5 K, [" [0 K# t3 W0 F; c# V6 o
  3. </div>
    / J0 I5 d( u( `
  4. $ [, z/ k, g# b3 V0 P
  5. <script>
    3 r, x9 z( |; [  d, B
  6. var Child = {* p5 t6 F, ?  U1 q2 {/ j6 e  B
  7.   template: '<h1>自定义组件!</h1>'! M, w. B1 s$ k
  8. }/ ~, I; u9 \# S( V1 S
  9. / H$ |; ?5 T2 U. I
  10. // 创建根实例, B: n- `* T- r8 r) \5 Y( x
  11. new Vue({' ^/ a8 \5 C$ {% C
  12.   el: '#app',0 P1 o: L* t! f6 h9 h
  13.   components: {8 y; w! f  ?- y( ^% f
  14.     // <runoob> 将只在父模板可用& b8 S+ I% ?: U3 ?& W
  15.     'runoob': Child" t: \" k& ]( Q
  16.   }) M5 l2 X$ L4 O! P# h* K, \7 W2 n! H
  17. })4 _3 s/ `/ f% c* _" h' k# g$ C
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
* w: }$ Y' r' y8 g9 a" C
  1. <div id="app">
    , @+ q  M: E$ Y; p2 G
  2.     <child message="hello!"></child>
    : G/ i( N& T& S5 a$ g1 S
  3. </div>
    & y& p& u: P1 O0 ~
  4. + R) N; @* n7 q- V0 k* S' f
  5. <script>
    / x* J& l* x+ D6 i7 |/ y
  6. // 注册
    1 O' L' d) Q4 m; `& r5 b' \7 Y
  7. Vue.component('child', {: F' t5 |9 P9 l
  8.   // 声明 props9 U1 I7 H. J2 r8 `) W5 W
  9.   props: ['message'],. P( w" L: r  ^: r9 M
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用, r* p! T: v4 n5 @
  11.   template: '<span>{{ message }}</span>'
    7 p6 O+ Y3 [# n6 f" p- _. D5 P9 V6 y
  12. })* S7 x; a; l& ^7 ], K4 }
  13. // 创建根实例
    : K: ?% y& F2 g% v
  14. new Vue({
    , `8 Y8 T2 d6 L: h
  15.   el: '#app'
    6 ]) G8 {: ~" R' f( e4 Q0 ^
  16. })
    * v% x" ]* G' ]; [6 Z0 D
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例1 \6 v% |/ m$ \
  1. <div id="app">7 T! ^3 ?7 h" Q6 V# H% P5 ^8 a( H
  2.     <div>/ I& K2 S1 X0 F' e' V/ k0 Y/ o" E
  3.       <input v-model="parentMsg">0 k6 A; u1 o4 M8 n, v3 U& q
  4.       <br>  w/ b6 y: p) A3 p
  5.       <child v-bind:message="parentMsg"></child>8 [& Q3 p" I* u. H
  6.     </div>
    3 U! R9 y  c6 g* E
  7. </div>9 a7 O( E( ^1 D1 [" N

  8. ) [7 f  P( Q. H& g& W& {) H  c9 _
  9. <script>+ o! p( Z' ]; W, Q
  10. // 注册
    , K1 I, {5 }: k( \1 I
  11. Vue.component('child', {
    5 u: F3 e" X# M2 }+ p! C: F
  12.   // 声明 props
    . B5 A# k8 t0 G  X
  13.   props: ['message'],. t7 J* D' J% Z
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用; y1 d8 ~2 d0 Y  a$ ]
  15.   template: '<span>{{ message }}</span>'
    * J; @- J$ T- V  J8 v
  16. })
    7 ~1 ?* g. B1 w9 o: J1 X
  17. // 创建根实例
    : L. A; z3 Y( G
  18. new Vue({
    , c+ T  z: {) _& X6 @9 N7 F1 f/ H$ L
  19.   el: '#app',- _, L" k6 E1 `+ ?# q
  20.   data: {  w& t0 R% f- O3 ~% G. |+ _
  21.     parentMsg: '父组件内容'4 I& J% A5 ], a+ o1 X9 |" P* c
  22.   }
    ( }, {: R4 a" v* X9 ^. U
  23. })% R, Q0 E$ f3 X3 ?
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
! n1 N3 S; S' n( G$ w+ t
  1. <div id="app">& N3 }- x5 e: O8 f. T% M
  2.     <ol>( M( S& r2 x% t3 B
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>6 D- I. L$ k, S2 R7 {# A6 ?
  4.       </ol>
    ) N9 c4 g; f- N6 d
  5. </div>
    3 B' g: O* o: @; b

  6. 1 t) {. m% v" b7 ?  q
  7. <script>6 P) B9 ^9 Q3 c/ S# _4 j
  8. Vue.component('todo-item', {
    ) B$ M- h1 p7 k) F
  9.   props: ['todo'],% Q" t+ B2 x- e# e
  10.   template: '<li>{{ todo.text }}</li>'
    / M& I& x% E+ `8 K7 M
  11. })
    ; a, h9 ~* y# s
  12. new Vue({& p' U6 h1 e% Y
  13.   el: '#app',
    1 e) M/ g" q9 r2 R8 J
  14.   data: {& S& f8 O1 a! _, W7 _- u
  15.     sites: [% H& f& s' `/ u* S! F* a
  16.       { text: 'Runoob' },
    " a- ^5 X8 j3 |6 Q( q# O" f2 `( w
  17.       { text: 'Google' },& p' _4 s5 \$ g( h
  18.       { text: 'Taobao' }" _# ]8 N7 B5 d. g9 i4 B( y
  19.     ]+ h/ }8 C2 j- O% a$ q
  20.   }4 b: L6 L" P3 b' o/ M& H
  21. })6 s6 A/ J$ Q0 X3 p
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    4 m7 r6 T% t9 X0 l0 ~- k
  2.   props: {
    $ [- s0 A1 V3 p( g
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    " `3 a% K$ x  c& t
  4.     propA: Number,
    " h' G7 `' ~' k" D& q- w4 l" c5 }5 A. r  J
  5.     // 多种类型  `# U1 `' n' u
  6.     propB: [String, Number],  K3 t; p8 q9 z% B. Z- q# k, B
  7.     // 必传且是字符串
    ! e( x$ e; M5 Q
  8.     propC: {
    , }4 o0 z6 W, z5 {  s
  9.       type: String,5 H3 j" r2 G2 \) b; ?; u7 ?" H* R/ M
  10.       required: true
    " u2 r. h0 |: b4 E
  11.     },
    ; J2 ?. p; n$ B3 z9 o
  12.     // 数字,有默认值& u# ]& Q- `7 R
  13.     propD: {$ v( a, ]2 {9 t& Z$ h6 l1 P' q
  14.       type: Number,* A% H$ I& K0 k+ ~  q1 ]( ?# q/ c" e
  15.       default: 100
    : I+ W2 ~0 X# L8 d
  16.     },$ q  b2 u1 i1 j; d# f# s7 M
  17.     // 数组/对象的默认值应当由一个工厂函数返回# p2 ]. |) b1 Y' D5 ^. I8 A
  18.     propE: {5 t5 U, W) S+ C, w1 a% ~
  19.       type: Object,, Q* F. X, c# U% t
  20.       default: function () {
    ' @+ P# O/ O  q
  21.         return { message: 'hello' }' u1 i% w/ b0 O+ W3 [3 M' M
  22.       }
    7 T" q  G; L8 D" @6 x
  23.     },. i. o9 J$ z2 C1 G
  24.     // 自定义验证函数2 H( E1 N7 m/ v% p+ O; g7 X4 d
  25.     propF: {
    % H: ]" L  q& e! x, E% C
  26.       validator: function (value) {
    % c$ W# v- y- g0 Z( O8 W+ f* k
  27.         return value > 10- S$ y7 t) W" \4 \& T4 Z. `$ x- R
  28.       }' N. g6 q+ q1 u$ N; x
  29.     }. B8 B$ E0 H* P2 |# [
  30.   }  W# J0 R! F0 w/ F5 R
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    ) d: ]' @' N4 M+ ~
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    * m) W' B/ T0 @, X8 T$ r) J
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
1 l0 c5 w# Y* W# y. K& B& C
  1. <div id="app">
    5 C1 _+ S: F; ]! K
  2.     <div id="counter-event-example">4 ]* R8 }! }+ [8 \, M
  3.       <p>{{ total }}</p>$ B# Q0 T; ~! R3 l2 H! k
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    - ~$ c* p4 w# d/ q7 r4 ^
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>9 C! l& n7 f& F8 }9 c
  6.     </div>
    ' d8 Z- n5 y) \: Y
  7. </div>- @3 ^) Y# V! k" l8 |0 q; m+ m
  8. 4 f0 n; R4 b# P# J* ~- B/ [" T
  9. <script>
    % W5 K: b5 A6 S  T
  10. Vue.component('button-counter', {7 D1 U) y3 @! F7 _) M
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
      P8 \0 H- {5 [! K% A# J
  12.   data: function () {
    + ]0 e/ g( n* F1 Y; v+ ^, P
  13.     return {% i2 Z0 E9 a$ m# W
  14.       counter: 0
    0 M1 `! X6 O9 d& G
  15.     }4 |" s, i. U1 K  W6 u6 a- G5 @5 T
  16.   },4 J* R: ~; G3 K2 @' z( }, g' }
  17.   methods: {9 K9 f% f3 I+ `- w
  18.     incrementHandler: function () {
    9 ]4 r5 d6 T) ?2 D; v
  19.       this.counter += 1
    # n  X9 {( C( h# b
  20.       this.$emit('increment')1 ?; J& o6 }  c& d
  21.     }5 L8 j: a& a) R: I5 e
  22.   },
    : C; [7 S5 V; K  F/ N2 N7 c
  23. })
      V. B2 s$ L% f6 Z
  24. new Vue({
      k& P7 o# u* c7 h. m
  25.   el: '#counter-event-example',4 }% ^$ f( V  r7 D
  26.   data: {, e" n, K, a5 C. m& z
  27.     total: 0# O' n8 V, u' \/ e& _( f& S  m
  28.   },
      `& r; ^9 H, o2 J1 n  h4 J2 H
  29.   methods: {6 \: D. Q9 G/ n; [* z4 I
  30.     incrementTotal: function () {) F) Q, g6 P1 @+ K5 D, a$ T
  31.       this.total += 1
    6 H. E6 O* ?, @
  32.     }) ~  k- M. {5 U
  33.   }
    2 S  T  h' |! r- h% J+ `7 J# V
  34. })! [3 y9 s  O6 d1 w* W
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册" m$ ^1 B- r; Q
  2. Vue.component('child', {
    9 }# b$ q  s6 ]/ W8 s3 M% B
  3.   // 声明 props( K: Y/ V! ~" r% U. |) N
  4.   props: ['message'],. s3 w- V9 [; c- p- v$ p" h% w
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用1 @# h  d$ @) {# R1 L# Y/ S
  6.   template: '<span>{{ message }}</span>'4 {2 J; l+ T/ d0 U
  7. })
    8 }3 C) h  B3 z/ N; o1 C
  8. // 创建根实例
    * z% R1 D4 C* e& k$ T- o8 A5 n# J3 k
  9. new Vue({5 P8 m: _. ?* j/ @5 i1 v
  10.   el: '#app',
    - s8 O8 C" L! ~; c5 d( y) L" ^0 Y
  11.   data:{
    - I, H# f, L4 K4 T1 Q
  12.     message:"hello",! A6 [) k$ L7 i5 K' F/ }
  13.   }
    % ~0 \! v' [& E* k
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {5 R- n, c( y5 q0 _: r$ q- p
  2.     incrementHandler: function (v) {% e2 a; y+ l, F
  3.         if(v==1){
    5 V2 I' O" J9 I4 p+ @) X! h' d
  4.             this.counter -= 1
    9 e5 G0 ~. T; {( L9 h, \
  5.             this.$emit('increment',[1])
    2 ]7 e( u: X! y8 ]: Z; E3 e9 E! U5 U# E
  6.         }else{9 Y: P* |0 W8 G+ N4 `. {% b
  7.             this.counter += 1
      S" ~9 B7 U. z* d4 k! i: ^
  8.             this.$emit('increment',[2])0 j+ T2 O5 R9 t/ w- i$ V
  9.         }
    ' x9 R# p" u) M% [9 V
  10.     }
    0 n$ \0 R2 e' [. L4 Y
  11. }
复制代码

# T, ], u/ b% _" K& ]1 o% R
* I) j& A& A8 }* C
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 11:39 , Processed in 0.088896 second(s), 23 queries .

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