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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15212|回复: 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,并使用它:
* k2 c/ z1 p1 p! \% h
  1. <div id="app">/ P! z5 M- O# ?9 i" L
  2.     <runoob></runoob>
    ( V4 a- C1 b  k7 i3 z" a/ Z
  3. </div>
    0 [, j! T  E; x* y" c5 h+ w

  4. ' v" g) J  b8 K' P2 a$ ^. i
  5. <script>& O4 U" z  O( x: y2 v( W( d3 C
  6. // 注册
    + P+ b- D# k! f1 m" i: U# l
  7. Vue.component('runoob', {& d$ T; X* q* l& u7 m7 n  `
  8.   template: '<h1>自定义组件!</h1>'! b  u# y9 F9 Y! ^2 g! o1 J; Q8 C" U
  9. })0 t& ?) y9 R/ c
  10. // 创建根实例
    ' \. q0 Y8 Y! W& N
  11. new Vue({3 n# P  S# F. h1 K! R
  12.   el: '#app'
    7 w+ j2 ]" S, K1 p
  13. })
    % Q0 p! G4 s5 z# X
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

5 J& b1 d. z* [! J' n
  1. <div id="app">
    3 p$ A& X' a. k# L/ E% n) b
  2.     <runoob></runoob>; {8 l& M. U6 r6 T5 e
  3. </div>  t6 H7 _0 Z# x9 l7 V
  4. ' R+ ~" i5 q' ?) _) v8 E
  5. <script>
    & k4 O' [5 y  c7 t) {$ g; n0 Y9 K
  6. var Child = {
    6 i, x8 ^# U5 k6 Y1 @
  7.   template: '<h1>自定义组件!</h1>'
    & x) _3 ~+ p5 u+ m( m
  8. }
    6 G+ x" s  |* e% H

  9. 2 z% J1 J. ^9 X$ p4 t. b* x
  10. // 创建根实例+ G: [  T) ^9 n+ C4 f
  11. new Vue({  N  D$ H6 M2 X9 P" ~( ~1 ]2 e: ^
  12.   el: '#app',
    + l) ~, R! q* C4 d8 j' y  j
  13.   components: {# d1 l- v9 M/ }/ L$ B
  14.     // <runoob> 将只在父模板可用
    . T, O) Y# M5 Y4 _3 u* o
  15.     'runoob': Child1 P! S0 b( u0 r/ U- u
  16.   }$ O! Q6 i2 @) r# v* o3 u
  17. })
    4 K* S/ ^. x6 g/ y, k, N
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
4 F7 L% R4 R6 Y0 c+ l. u
  1. <div id="app">+ Q2 y' f# v1 w/ @/ A
  2.     <child message="hello!"></child># M) L" c4 u; u: D4 }* K
  3. </div>
    % C5 W0 }3 f  X4 Z

  4. & P" f6 b% X# i' i  Y
  5. <script>
    % g+ X* ~* V3 e" F) B" |
  6. // 注册+ j  R  d2 J! {$ X3 v9 Q
  7. Vue.component('child', {
    # {; E& b5 i4 N; S5 c; X, C
  8.   // 声明 props2 `+ o5 m1 I0 Z
  9.   props: ['message'],3 j' P5 N+ Y9 ~% m. E: d
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ! g. d5 `; A7 Z  j& B* \
  11.   template: '<span>{{ message }}</span>': E7 k5 r, q: O* ]7 @1 l- i% j) |
  12. })
    % X* r; P( e5 {, N7 w
  13. // 创建根实例
    8 f9 e; `2 h; F- H: }" y
  14. new Vue({- v8 j. ?% R# g/ A6 X
  15.   el: '#app'9 Z# D  Z. a0 {( p
  16. })
    * ]9 w8 l5 ?& x0 |: W. }
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
) e$ H" ]# v4 L* {* ^8 j2 t9 e: S
  1. <div id="app">
    0 T) l5 |6 ^5 x& ]/ ~# K
  2.     <div>6 O$ M/ G8 o6 W1 _% P2 \$ d
  3.       <input v-model="parentMsg">; s: H+ V$ u, L/ c2 r
  4.       <br>
    + r" X9 O  D7 E
  5.       <child v-bind:message="parentMsg"></child>
    9 L# R- t. }' y( g5 t+ q* n9 ]+ q% x# \
  6.     </div>
    6 r- S; r) @, [; Z/ {+ P
  7. </div># K% \; J* `2 `* H& V# v% p

  8. * q- e9 p$ h( n. c: G6 x
  9. <script>
    * _$ N9 K# W5 j/ K# `
  10. // 注册
    8 n+ m; ?' j: q. c* B
  11. Vue.component('child', {8 L  b! C* q: G. @. `0 U
  12.   // 声明 props+ p4 I0 g+ J  S2 x
  13.   props: ['message'],/ r& t1 ~+ R6 `; L  b  ]9 `) ]' M& T
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用5 u" b, h# {1 u; z# l; t  B
  15.   template: '<span>{{ message }}</span>'
    ! }( T/ S8 m2 H" R8 `
  16. })/ K, |9 |1 X- y# b! S
  17. // 创建根实例! n  L9 f. S( l1 n
  18. new Vue({
    7 |; ^8 J% A5 o. K4 u! B* S' k
  19.   el: '#app',
    4 m% J3 w0 \& i! @* R# w  t
  20.   data: {
    6 {' m3 _3 {: Y+ E
  21.     parentMsg: '父组件内容'5 g, W3 X. D+ L- ]  T
  22.   }8 q8 _" p, I( J# `7 m/ _) D
  23. })
    ' X& A4 o) b3 z4 t9 x
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
7 x: H* V0 T' M, W) {; {/ A
  1. <div id="app">! P% O! y1 l9 H% [) Z$ ~
  2.     <ol>! [! l* a# h3 {1 T; P' |
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    7 C% H7 X4 O% _
  4.       </ol>8 p( N% \1 w( `( E! a; j
  5. </div>$ c/ h3 y/ f5 a- x& p* W
  6. + s" P' U" [$ [  j' q: a
  7. <script>! P# K% I# S6 u) G" {( a
  8. Vue.component('todo-item', {
    / p" U% i7 O; |; ^
  9.   props: ['todo'],( i# ^/ j8 t7 x( I7 D/ m
  10.   template: '<li>{{ todo.text }}</li>'
    1 p$ B5 k+ B: F3 j5 K( E
  11. })
    # r8 `! c* z/ G
  12. new Vue({
    4 Y# w" \! Q2 z& Z6 u0 T7 ]
  13.   el: '#app',$ A" t, m5 C% u# }% r
  14.   data: {; _4 t- Z& k/ e4 F" U
  15.     sites: [
    8 f/ T/ E- r. o6 M9 s
  16.       { text: 'Runoob' },
      L* |0 a; F" W" C
  17.       { text: 'Google' },( h) K0 q( C/ S
  18.       { text: 'Taobao' }
    & c1 A* N7 i- `+ b0 \2 _
  19.     ]3 L2 l, ~8 N( l, d+ r$ h: o, l+ u5 e
  20.   }: g; n$ w/ q: p. _( C' G
  21. })- Q3 [7 d5 O: v1 [6 \* [( k3 R
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {2 w8 h% h. D, x. |  M
  2.   props: {
    : n$ E) R# W; ]9 Z
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)0 Y$ S! ~/ o" o1 W( Q5 g* I
  4.     propA: Number,
    2 c* o; K' [5 v/ K# D
  5.     // 多种类型7 W2 Z, n( o6 w2 V
  6.     propB: [String, Number],: M" I( K* v$ _, k
  7.     // 必传且是字符串0 D* L' f' N0 g( W" s
  8.     propC: {9 ^3 E! E' u' H/ U' e; u
  9.       type: String,( a4 l* _* J9 y
  10.       required: true
    , Y( C8 B, T' W/ K9 V
  11.     },) z9 }7 F9 v1 O4 X2 y
  12.     // 数字,有默认值
    # _! s8 |) J- G; {' `* v
  13.     propD: {
    0 m5 `: {, J$ g) j4 q
  14.       type: Number,
      O8 J( [8 S+ h" e8 E
  15.       default: 100
      ~5 R# ?% K) \( v9 \
  16.     },. i" o2 l7 ^- H- |7 r
  17.     // 数组/对象的默认值应当由一个工厂函数返回/ Q  [0 x3 }' q/ Q- p# I
  18.     propE: {
    2 P  d$ r2 N$ S- p/ x; j2 e
  19.       type: Object,
    : H' }7 \* q5 X3 J! s# n
  20.       default: function () {
    $ d4 ~, W- c/ X% g; t" N" l6 x
  21.         return { message: 'hello' }- T! ^4 {3 s; I' C9 }* ^7 R2 H
  22.       }. E- M- G1 P& j5 r% B2 a  C5 _  k
  23.     },
      U3 w7 T) `+ f. K' e: L+ s- _
  24.     // 自定义验证函数
    4 S/ M# T9 }& U5 s) u9 D/ _
  25.     propF: {/ p7 G6 M& j$ L5 D3 ~4 W  d
  26.       validator: function (value) {2 k. K, X- H) {3 w6 G2 m1 u2 v2 M3 V
  27.         return value > 10
    7 k( O8 x: b) E" p
  28.       }. i, q1 N6 t8 M9 Q/ l
  29.     }
    ' U+ U* I, B8 d) G6 d
  30.   }
    - C# |7 A) U" N' ?
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array( l7 h$ k6 u( C) a1 ?
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    3 g4 L) [. M; T6 s# O, A
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例% _4 o  \" i  F# @! G* `; Z. u
  1. <div id="app">
    9 G1 ]2 {9 j9 H
  2.     <div id="counter-event-example">
    . Y  _! W4 E1 p- |! f2 ?2 }! b
  3.       <p>{{ total }}</p>' u% o0 ^/ e# M  u
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>, Z# }  H$ q! e' I( Z+ z
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>& m, C* e! w- k7 o
  6.     </div>
    5 t/ k: J- G% K. F
  7. </div>
    5 T1 u6 r6 n) [1 t
  8. , X% L" L" W2 M% h, S/ p
  9. <script>
    7 a) W: }3 \" e0 X! W. a
  10. Vue.component('button-counter', {* b9 V' Z: _  x4 e: w* ]
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',/ K$ W0 o% T5 s2 Q* w4 P' X" _
  12.   data: function () {
    ) ^% u8 d: F: N/ s7 E- n0 a
  13.     return {/ N7 \) M! Y8 g6 ^# ~+ U
  14.       counter: 01 ?: i2 ~' a$ f; J' C; t
  15.     }
    1 O$ S, I: I, q9 Q; P7 |
  16.   },
    $ H% N) J8 N0 E7 h
  17.   methods: {
    : R, \+ d, k# Q4 [
  18.     incrementHandler: function () {
    3 _, p' e8 j/ }/ n* `  Q
  19.       this.counter += 1* l8 t& c) L; l* U
  20.       this.$emit('increment')
    , O4 o- m* {$ v
  21.     }/ @# }! y* T$ w. K  C. {
  22.   },+ a& P5 }+ O1 [7 _8 R
  23. }), i6 G2 {% s; ^7 d1 m
  24. new Vue({
    - H3 {4 `& g6 q2 S' D
  25.   el: '#counter-event-example',
    / i6 x/ v6 o, ~) K- R6 G, C+ I
  26.   data: {5 k4 L; f& q# s# s/ a
  27.     total: 0
    1 [2 W$ i0 P% M9 u7 j" J6 c
  28.   },5 E& J5 }3 f6 V- M% ~
  29.   methods: {
    ' i- g5 \$ s! i
  30.     incrementTotal: function () {
    3 J  q) R, j) k/ w: U3 _' l; P
  31.       this.total += 1; U; C6 O- @% H# o2 H2 X
  32.     }. P! h% U6 L+ t; s7 J  H% w8 ]
  33.   }
    ! h& {( k3 g9 j
  34. })! Q3 o" O; R0 {) k
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册9 S) j$ C, v' x5 Y# U
  2. Vue.component('child', {
    ' Y5 l% r0 y) W5 [
  3.   // 声明 props0 g. b. r, K* i' ]
  4.   props: ['message'],
    7 G, z. h, O- R3 p6 E
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    # t/ z% ?# q. g- {$ j+ b
  6.   template: '<span>{{ message }}</span>'1 g, j& [! Y+ m
  7. })
    $ [2 p. _9 T3 a8 x$ l/ N% g
  8. // 创建根实例
    + r' b% Q& r* Q) l$ r
  9. new Vue({
    + n+ g& p3 M8 }6 }7 W0 W& ~# x/ M  @
  10.   el: '#app',
    6 G- J" N: e  c0 E
  11.   data:{; v- d% E) b- _# F1 X6 |% ^
  12.     message:"hello",
    8 u- J0 q2 g1 @1 Q1 V4 L# P: }
  13.   }
    7 y, c7 L& E! K) c; x
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    $ \* E7 q7 a  B  f7 [
  2.     incrementHandler: function (v) {, S5 {) Y, a. v( s6 F* t. Z" c. b
  3.         if(v==1){
    ( Q' J7 Q+ _: t! p
  4.             this.counter -= 16 S+ D& k* S1 ]: l$ m- I( B! R
  5.             this.$emit('increment',[1])
    % \4 ?9 i8 t+ b, Z* Z6 o! o
  6.         }else{/ ?  d9 I1 P3 I$ M3 a1 r
  7.             this.counter += 1
    ' U( L7 j5 T+ f2 d" n, x
  8.             this.$emit('increment',[2])  @# m5 l* C- S; N4 ^
  9.         }( H2 C& q1 C$ R# n
  10.     }" \1 \; R, s. v0 J+ q' h6 x
  11. }
复制代码

) e; L; E) j8 n; ?8 A3 W" T6 E
+ [% s$ {5 m; K0 I8 ]
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 16:06 , Processed in 0.067222 second(s), 22 queries .

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