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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 12296|回复: 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$ l% S9 L4 W3 B& ]7 r3 B" T
  1. <div id="app">
    7 m' h( a! a% p7 c
  2.     <runoob></runoob>
    0 w, a% z' ~- Y: ?6 n* m4 T
  3. </div>
    8 T! }  e8 ^& b/ n" n

  4. + F) z7 [- @: g% @) E" j, H: b$ u
  5. <script>- o9 K7 g0 y/ A; M" M; }. \! b
  6. // 注册
    4 e- k: W9 \# p( F1 k
  7. Vue.component('runoob', {
    ; T/ \; G2 K, w( O% r. v% k
  8.   template: '<h1>自定义组件!</h1>'+ Z2 V, e4 }9 {0 ^! h2 @' s: J
  9. })* f: ]0 ?; c% g, e4 _  X: F
  10. // 创建根实例) C' O8 R4 j, X, i
  11. new Vue({
    & E0 `4 e  J; }* D
  12.   el: '#app'6 |5 I/ }" T2 D: U; u
  13. })& Q* ~6 J+ P3 s0 Z
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
. I4 M: g7 F* K1 Q1 I
  1. <div id="app">( `' t3 J' y/ t2 O, @( x/ ], R4 g4 J& n, e
  2.     <runoob></runoob>( Q- A5 \/ ?3 x% L
  3. </div>7 M& S  p4 ~  L

  4. 2 k/ X9 N  j  D' i% M
  5. <script>
    0 J  `  A) ]/ \( s1 G: ^
  6. var Child = {& O4 x/ Q% y. s2 [% ?8 Y! P/ O  c
  7.   template: '<h1>自定义组件!</h1>'
    ; q6 c# }3 `, S- w* c8 U% J8 r+ k
  8. }
    2 D# x& r. `$ E0 K$ R0 f

  9. $ X2 N. q% Z( W! ^4 J8 H
  10. // 创建根实例! D! {3 x1 b1 Y, U, C$ E) N5 M7 [' \5 k
  11. new Vue({
    9 ?+ [4 q9 N! I  u$ E% O. F
  12.   el: '#app',' H2 r, I# B* p) h1 W- K" G% d
  13.   components: {1 g3 h# w1 _& h6 R0 H
  14.     // <runoob> 将只在父模板可用
    . b8 I4 j* n3 p$ k; S0 f$ Z
  15.     'runoob': Child6 G% r2 d; x+ v) Q
  16.   }3 p! H+ o9 J, o# C! j, D- W
  17. })6 u  R  m* o  n% H
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例* v, R# _2 m9 ~3 z
  1. <div id="app">
    1 q6 n1 ~! \$ ]
  2.     <child message="hello!"></child>
    - P# j" B$ ^1 g5 l* F! Y
  3. </div>( B7 V7 ^7 {. u2 @' x
  4. ; Z$ n' Y0 w, M; U) S) N- @
  5. <script>
    . G' m  }4 q( F, H7 a' v$ G, p* B9 w
  6. // 注册
    , E( V8 i2 q9 h$ M
  7. Vue.component('child', {
    3 b8 V' S' j- }& p+ C& H) A
  8.   // 声明 props
    9 h+ E, ~; l  G
  9.   props: ['message'],
    8 {( g, G7 X' S4 r
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用) p4 ^. K  o/ b3 K* j$ u
  11.   template: '<span>{{ message }}</span>'
    0 Q! o2 r% O' z0 A( |' V1 [+ K1 w8 d
  12. })8 ?; t7 L) D3 u$ Q  A
  13. // 创建根实例( g$ r* ^5 \, X% b
  14. new Vue({
    1 z" N4 e  O6 _
  15.   el: '#app'* ~" g) [/ y9 q
  16. })
    ! `% M. I4 S) j# E3 a; F( G
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
1 P6 H7 ~- R7 ?0 X' ]6 @
  1. <div id="app">
    3 X; {% Y" }6 k# [+ A  u* @
  2.     <div>
    ( j* W; j9 l) {9 F. Q0 ^
  3.       <input v-model="parentMsg">! c0 T' C4 z; m  \5 m8 s
  4.       <br>* P& N3 s1 t% }/ N+ z) Q
  5.       <child v-bind:message="parentMsg"></child>& Y$ p! j8 c. I% M$ g" L( v
  6.     </div>
    6 N: Z1 M0 c* m  a- b
  7. </div>
    . j6 J: @- j8 v, q9 }, @# Q2 g

  8. % ^* p5 n* ?3 h: d+ J- k  Z' Y) ]
  9. <script>1 y$ t+ h6 P9 ?9 Q
  10. // 注册
    , X, s0 P  }1 x. h0 V6 G" I
  11. Vue.component('child', {
    0 O3 Q: g/ X0 G' y
  12.   // 声明 props2 B$ S9 b$ d' i, y  B) c1 a$ [
  13.   props: ['message'],
    & k5 w3 i' W+ J8 B! t
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    0 {- f$ B- q1 F& T2 f0 m2 ]
  15.   template: '<span>{{ message }}</span>'" B4 l) v% y. V6 R6 B1 d: J# p
  16. })5 w. `# Y% B1 x- W/ c. c
  17. // 创建根实例5 }* f" ]1 l% x8 `- l6 B/ M# k
  18. new Vue({
    6 r6 Y* g, o  }- r8 d( b8 G, w6 D
  19.   el: '#app',
    / E) Q. {- r" Y  ]" i5 w. D
  20.   data: {
    : J  \/ Q# D& d( h
  21.     parentMsg: '父组件内容'# ]( y  v6 w0 ~
  22.   }0 Y+ a5 J* O* s  ?
  23. })2 Z" X9 [  ?4 }6 v! Q  a& y' l
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
! W& S$ h( l, I+ q& I3 `
  1. <div id="app">
    3 {5 R; S1 Q( h  N
  2.     <ol>
    + N+ r1 A2 V! G% \7 v
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>( b( q  @' K$ M, ^/ T8 _; }
  4.       </ol>; _  ~9 k: h  o+ C
  5. </div>
    8 L3 W, |1 ^" P

  6. * U) R9 U/ P( s; f3 y
  7. <script>
    1 S- H$ K+ a" u4 g. N% \
  8. Vue.component('todo-item', {
    / b8 |9 y' x6 |2 _, ~
  9.   props: ['todo'],( |4 b( R1 g: j' Z$ A
  10.   template: '<li>{{ todo.text }}</li>'  `% t3 b+ o" y. c8 P: c
  11. })5 S# k* ?# r9 @: q: o
  12. new Vue({! E; @# h1 w( {4 l7 F4 U
  13.   el: '#app',
    % t: D3 F# y' |% @
  14.   data: {& g! u( z' H+ k
  15.     sites: [
    ! ~8 t  b3 H) N, Y1 f
  16.       { text: 'Runoob' },$ Y3 v+ v5 T0 F& F, v$ p: z3 ^
  17.       { text: 'Google' },
    4 M2 U) _+ N: n  E
  18.       { text: 'Taobao' }- W9 \8 S$ `7 c! z
  19.     ]  n- v, R2 d' n$ V
  20.   }
    1 ^) S2 o$ g+ a0 E7 P+ t" h0 o
  21. })
    . M5 Q1 O! h; w5 f4 _
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {, e5 p* p" ?" x; L" T
  2.   props: {4 R$ A$ C, [- R6 D4 c# C
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    3 \: Q4 l$ ?9 ?1 L" O0 g0 _' k
  4.     propA: Number,5 h- }, m9 D0 P
  5.     // 多种类型: ^: }2 g5 ^, d" c
  6.     propB: [String, Number],8 E  K+ M+ x$ _3 Q# d) t  G2 V
  7.     // 必传且是字符串+ b4 k+ y& c2 ]( `9 Z9 _8 Z9 N
  8.     propC: {
    0 A3 b: |8 ]1 E8 a3 |
  9.       type: String,8 R- c! J) q& [3 Y9 k' O+ q3 ~& D
  10.       required: true: m6 \$ R4 m" A& B& A+ F  z& m
  11.     },
    1 v- Z$ d: U$ |' A) q1 n, H
  12.     // 数字,有默认值: }7 i" F+ _' T; D4 L8 o
  13.     propD: {  n( ]# K. Q' ]  w# E# E% H
  14.       type: Number,- E% R1 Q. h" q3 J
  15.       default: 100, i2 j4 j5 ^( o6 C0 X( m
  16.     },# k0 K0 d' d2 ]5 G6 \) a
  17.     // 数组/对象的默认值应当由一个工厂函数返回% q* d4 d3 q: y
  18.     propE: {
    9 J$ m$ e$ g9 r2 }2 {. S* u4 R- _# W
  19.       type: Object,
    5 o# }7 x9 D' `  `# p; W2 X
  20.       default: function () {9 A5 T' m3 M0 y; H& b  C9 ~7 Y$ k
  21.         return { message: 'hello' }
    0 p/ y) `' `/ o0 K  M1 m# _" |9 f. f
  22.       }
    . u8 L% ]0 V+ y: X! _) T6 K
  23.     },
    # h* q! E0 C4 l+ Q
  24.     // 自定义验证函数, h4 P4 s, y9 C# I. h
  25.     propF: {% C$ ~1 w" G: ]2 O6 L* |
  26.       validator: function (value) {
    # r' S6 l# s3 ?
  27.         return value > 10# R5 V; ?5 u) ~
  28.       }
    , t$ {* t- z" Z& d" L: ^
  29.     }
    4 x" w% ^- c. _; z5 G( ~, e
  30.   }& w: b' D- D3 L) [0 a
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    1 a/ C8 P' H5 Q# B
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件9 O* g; ~; O& M6 `
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
9 ?0 Q& N0 w9 U0 d6 {. a4 j* ~# m
  1. <div id="app">/ w! {& X& _; {) G
  2.     <div id="counter-event-example">
    . F! P2 W, B! S( a( Q$ M* c+ \- A
  3.       <p>{{ total }}</p>7 O+ I+ V1 H' z3 T. R
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>/ ]' S, k# t* f) Z% q" Q  _
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    0 w0 G! y" C7 [( Q5 }* t
  6.     </div>& k( x/ n9 H* i$ }9 z' L
  7. </div>
    / k5 A" E2 ^# e
  8. ' R: }0 e* \( ^
  9. <script>" t# U6 [, z: P9 A0 m
  10. Vue.component('button-counter', {
    4 S, K, z1 C) W2 _6 T! c4 Y
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',, o8 ]% X+ h0 T1 }7 d
  12.   data: function () {5 a+ `2 c9 z3 n- x
  13.     return {
    : J6 R9 E+ C' o; s0 e) K
  14.       counter: 0" F$ O4 P4 i) k) T
  15.     }2 Q3 D: t) l* }4 v; G. `
  16.   },
    7 h7 v9 W% e/ Q# h
  17.   methods: {' F% E0 d- X0 \7 [; }( \) s6 f
  18.     incrementHandler: function () {
    6 v5 l6 G* c; z! x
  19.       this.counter += 1& ?7 z* b6 V0 G( u+ K; p
  20.       this.$emit('increment')
    + W* r" l- U9 Z, v9 S8 h
  21.     }/ G, H  w5 \# W7 R( }" E
  22.   },1 @+ c5 E$ f+ M5 @* k) j
  23. })4 p1 t8 d9 @, O7 [) D5 A, W$ {
  24. new Vue({
      \4 C1 m4 `) q/ \. X; l6 O
  25.   el: '#counter-event-example',
    4 `: K: [% i% i. {
  26.   data: {
    " y7 A! F/ V2 O0 S1 u. @+ v
  27.     total: 05 q. U. j- D! @( E
  28.   },
    # V# a0 e3 ?: E
  29.   methods: {
    , o4 @% [3 v6 W
  30.     incrementTotal: function () {
    # o1 I2 K; i' R  F9 W; R& i
  31.       this.total += 1; i1 A# J/ e) B; B
  32.     }
    - w$ `" J/ U) E6 n
  33.   }
    6 Z  k7 K3 \+ N! l
  34. })
    # @. T1 ?! `0 G4 D, I
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    + N, e7 X2 m4 c2 x. I1 @! ]7 s+ _
  2. Vue.component('child', {
    2 U$ {9 {5 x7 V
  3.   // 声明 props: ~! h9 L" G. _8 |# W) G! T2 A
  4.   props: ['message'],% n0 z8 b. r! y: J
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用5 D  Y8 b, K+ f+ c
  6.   template: '<span>{{ message }}</span>'
    0 K$ i) m$ Z9 s+ P
  7. })7 I+ r! b7 ^/ K% z
  8. // 创建根实例
    2 ]) t8 b4 D0 Y+ J$ r
  9. new Vue({: F( B2 F& f  o( S) t) X- W
  10.   el: '#app',
    $ k/ k. ~* ~5 Q: @4 l
  11.   data:{
    0 @+ |1 r7 }" T) Z4 A9 A
  12.     message:"hello",( S2 y8 V4 ]% G! p' c  P
  13.   }; S- h" Z* u" \- t9 M, u+ W4 q
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {4 ^" S9 p/ n. s9 i1 K/ G. _7 ?0 g% ~
  2.     incrementHandler: function (v) {
    4 _' p( `, Y( j4 b/ L: j
  3.         if(v==1){
    8 K; k+ C' L) @  L7 ^5 {
  4.             this.counter -= 1& U0 T+ C/ B/ \2 t2 N
  5.             this.$emit('increment',[1])* l; F$ B  d4 s% m8 k! N
  6.         }else{' \2 a! p6 y6 u& V$ }
  7.             this.counter += 15 K% \: Q. @: X, @$ D, s. s0 t
  8.             this.$emit('increment',[2])
    & B4 {/ n- X, t
  9.         }3 l5 {! l8 [: z0 P: Q
  10.     }- A6 p* p: }; K, Z9 S- j
  11. }
复制代码

0 X' t0 s! `% E8 o# }& A: r' ^& E  n7 s/ X; U" O, `4 e
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-11-1 09:32 , Processed in 0.174812 second(s), 25 queries .

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