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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

# l) |- s$ R  @, e" z! W
  1. <div id="app">- P& Z0 E! j- e, |1 t! w4 \7 A7 {
  2.     <runoob></runoob>8 U* i0 t% o6 {; h0 P6 I4 s+ Y# Z
  3. </div>
      }1 A+ K4 g3 ?3 b9 H7 _! b

  4. 8 X2 U) v2 Z# `$ {4 e
  5. <script># p% p5 L1 u1 B
  6. // 注册
    ' [) M' w7 g) R7 P) `; ~* s
  7. Vue.component('runoob', {
    3 U! e) G- f  I# f; s" a
  8.   template: '<h1>自定义组件!</h1>'
    & b. i0 T* e3 W, B9 W* J- o  }
  9. })
    5 Q0 U' [# Z) Q+ G7 _
  10. // 创建根实例: [7 {- f0 o/ j# H' H" U
  11. new Vue({
    + \% w; c7 r# Q- \, {
  12.   el: '#app'
    1 S. y6 \1 ]7 B( N6 u; w
  13. })7 ]) S+ q$ ~' W- D/ m* ^
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

8 [* U5 s- t7 l( Y
  1. <div id="app">
    % m; I0 h& h+ m$ I, ?
  2.     <runoob></runoob>7 E2 r- f: G. A4 y
  3. </div>
    6 _6 e8 n1 S7 a6 a+ ?+ L5 W

  4. ) Y4 K, n- j4 d4 a. C, `. z
  5. <script>2 P9 q3 n5 j& B5 X  ^
  6. var Child = {- J$ c$ T9 B( X$ |; ^/ q
  7.   template: '<h1>自定义组件!</h1>'
    : u: y" ?1 v+ u! h6 h
  8. }
    ! A. l: }. E4 u: S# M6 H

  9. + d9 y; L$ Z+ C# `
  10. // 创建根实例
    7 ^. h) c- z( c+ }, I# A3 M
  11. new Vue({
    . C9 a( k0 w+ Q0 w& m
  12.   el: '#app',
    # T* t) S9 ?0 i* ~$ z& t
  13.   components: {
    ! U3 X; R! p# k5 d9 P- j
  14.     // <runoob> 将只在父模板可用
      m! F7 @3 s! o0 o
  15.     'runoob': Child
    $ H8 W* @) [: A: }4 g$ a% y& t. i1 D- L
  16.   }
    2 i- |& ~- s7 \; g) r
  17. })
    / m; ^# d3 b; k% y3 _- S% |) n  G
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例- |# \8 i! x! p) w
  1. <div id="app">
    % y+ H& L5 O6 l# B$ z+ G
  2.     <child message="hello!"></child>
    + R2 K4 o. _5 }
  3. </div>7 w+ R, P( L% [  l
  4. ' ]; u! M; @6 _, Y" }; ^* H
  5. <script>
    ( o$ v2 \  `: t  M2 ]- C) V
  6. // 注册% ?: M; J: z  \. m( L
  7. Vue.component('child', {6 C& ^! [8 `: B7 M5 P+ x" S
  8.   // 声明 props# x8 n% L  r: j( C5 [
  9.   props: ['message'],: l3 \4 z; M$ h& `3 E4 z
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用7 F' D9 X2 O& J5 `
  11.   template: '<span>{{ message }}</span>'  s7 P! \: A+ \7 R! V
  12. })9 `; W( n0 f1 H$ w" N& }: n
  13. // 创建根实例
    * C1 p$ X' w" O* l% P, M
  14. new Vue({
    0 a5 o+ s9 k3 k* E& o0 D- R
  15.   el: '#app'
    , F* d* }7 e% ?0 d  y
  16. })  Q$ N# E2 A1 O( b% J' W3 H- l
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
2 }  N- i. h2 P+ J' ?8 u# k( S0 p0 ?
  1. <div id="app">- H# x9 _; h' K" o' Y+ x. {
  2.     <div>% P' N! ^/ v' ]! C+ H" B
  3.       <input v-model="parentMsg">( V9 z4 L! R' `0 |; d+ ]. U
  4.       <br>
    + @/ p6 t( ^+ Z% C' ^8 e7 q/ Q
  5.       <child v-bind:message="parentMsg"></child>
    & r+ y- O0 P) ?* P
  6.     </div>2 s, A* D8 f4 b3 `2 m8 m
  7. </div>& x9 i. a. w* ]4 P0 O% O* p

  8. 8 _% U7 V( r) p4 g% k' u
  9. <script>
    . ?2 ~* E+ J( ?/ _: @  g7 o
  10. // 注册
    6 i3 h; @& U# `: j8 c* _
  11. Vue.component('child', {  w; R0 T' c( B7 A
  12.   // 声明 props
    1 ^2 _% j' u$ u" V: S
  13.   props: ['message'],
    , J0 J5 {: x" s
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ! r# Y$ G  ^7 @) z9 e6 n
  15.   template: '<span>{{ message }}</span>'4 Y4 b4 ~8 F$ g
  16. })0 @+ _, O$ I, V) E. U: v+ ~: L
  17. // 创建根实例
    6 T" h; t1 [7 B& u7 u; y
  18. new Vue({& e' g% q3 W! l% N. ^
  19.   el: '#app',( @3 b1 d5 M0 f) v; b% d
  20.   data: {
    9 m8 P! V: w1 @+ M+ z, z" [" H
  21.     parentMsg: '父组件内容'+ A: m2 F2 m9 |8 W# T
  22.   }5 L* v# x; @' i- _; J
  23. })/ n4 j, H5 F3 O2 A% O5 S/ u
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例) O1 p4 ^# v8 ]! k$ q" e: x. T
  1. <div id="app">
    ! {! `+ v: q2 L6 j* j& [
  2.     <ol>
    ) _( f* K* W  t$ n
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    8 b2 R" ]3 Y0 z$ Y
  4.       </ol>
    ! t# F: B/ V% ~$ h
  5. </div># z9 X2 A; _9 x+ N

  6. & j" o( h+ ^+ r* u
  7. <script>; z1 D2 h- m$ j6 J6 U7 Z) k
  8. Vue.component('todo-item', {7 S8 {" ~$ t6 j% t% W/ O' V
  9.   props: ['todo'],$ T/ w5 p- Y# X# M" w
  10.   template: '<li>{{ todo.text }}</li>'6 O; a. }. l$ B9 B! J
  11. })6 u$ \! g5 G. k; u
  12. new Vue({3 G. H$ g& x0 A
  13.   el: '#app',
    / B+ v" E  p4 {! Q$ j3 x! J. L5 H
  14.   data: {! E) a0 N, j. V# D: e
  15.     sites: [
    0 H& N& S( @  a
  16.       { text: 'Runoob' },+ h& d2 a3 T( y
  17.       { text: 'Google' },
    . @3 r' v( q- n5 u# q7 U$ w+ _
  18.       { text: 'Taobao' }
    2 K/ m( k' u) ?8 H! b* }
  19.     ]
    : i8 `, F, U4 E
  20.   }
    / W( d% W  b3 q8 A8 n" p
  21. })
    * t7 j  m, t& Q. E3 r% E3 T6 M* B1 P" v- b
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {8 Z, q3 c+ X! I, ~
  2.   props: {1 u$ |) h: {  C8 q/ ~3 {3 E# r
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)" q/ H- {  d: [- p+ K* N
  4.     propA: Number,
    : O+ W) r7 s# P
  5.     // 多种类型
    6 F; C( U0 i8 _$ L5 V$ W$ |- c' g
  6.     propB: [String, Number],
    , q) e# L5 r/ J4 Q
  7.     // 必传且是字符串( U. Y5 {  d- A9 K2 Z9 f+ g
  8.     propC: {
    ) u% ]1 ]3 q5 }9 T
  9.       type: String,* [7 j" u/ v& \- n0 `& i- y
  10.       required: true
    . P7 v1 K6 @% D/ ~1 R
  11.     },  Q8 N- E: O9 a9 U, N/ }4 Z9 l
  12.     // 数字,有默认值
    * f6 m3 g: m7 \
  13.     propD: {, V/ k1 V" {. g/ S9 Q" Z) r
  14.       type: Number,
    / {) c4 y: `* b) p
  15.       default: 100$ v, Y- |9 U2 i
  16.     },% \3 z( d9 R  y( |# i" |0 f% f
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    1 h( M/ U) B. v* o
  18.     propE: {
    * J2 T! P6 V0 |- o. Y
  19.       type: Object,5 s# f& Q& ?: I9 b: L7 `4 J, e
  20.       default: function () {: }; G7 l! ~% d4 g3 s/ P
  21.         return { message: 'hello' }
    4 }' U! K4 z) L
  22.       }
    % c* C2 K# F' b0 S: }
  23.     },9 V0 W( v! b( L
  24.     // 自定义验证函数+ J! S3 z1 R/ S
  25.     propF: {# R6 d3 F6 W, o. \( G# f
  26.       validator: function (value) {
    " b5 H: |( ?" M7 i; ]. Y
  27.         return value > 10
    4 B; w7 g! ?1 c: x& Y
  28.       }
    # G; W: L# B  [+ @+ o, U' s
  29.     }* s) k6 {& K# X; m
  30.   }6 F2 ]7 C1 i  Y* N
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array) J8 M0 `3 U! G! ~# ]) s$ N; b% p
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件$ O, ~" O* m9 z2 `' D7 |
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例) p( P6 y; ~/ @% s" q! z! c: }( J
  1. <div id="app">
    # c" h$ G% i/ |
  2.     <div id="counter-event-example">
    5 S  h% ]9 @( u- y4 @: [
  3.       <p>{{ total }}</p>- Z: G; l, e, r, P$ }
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>% h: J' r; d% J! @
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>1 i6 B) l; b0 _+ G8 [. x$ t
  6.     </div>
    1 N$ G3 a- r) l1 q
  7. </div>9 m( `# Z2 H4 L: I. G8 Q; l
  8. * l9 D& `4 Q4 d8 ?% @3 x
  9. <script>( C8 R. y3 N# D* v3 @& e
  10. Vue.component('button-counter', {' V7 f9 y% C% Z7 D# r
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    + V$ O8 C8 W) m$ I
  12.   data: function () {1 u: g7 M9 X# Z! F2 [, y3 z
  13.     return {
    3 H' q  j4 A6 I4 R* z
  14.       counter: 05 P5 ]8 `/ {+ `# q$ \
  15.     }
    4 f3 m6 @8 w6 X2 V+ z, [/ V; T
  16.   },' q0 a& G4 G' r. T' c
  17.   methods: {
    6 l2 W6 X/ O9 `5 M2 ?  v3 u
  18.     incrementHandler: function () {
      G6 {2 N. W  S3 {+ K! ]0 ?& X
  19.       this.counter += 1' \4 d& m$ n1 g9 I9 y' F
  20.       this.$emit('increment')
    8 m( Q% s, Q4 J: }( ?; Z2 X, a
  21.     }( p% ]+ A/ W7 o8 I) z
  22.   },
    ) {% g" c. K8 |, o
  23. }); O  o! ^) p+ q
  24. new Vue({
    5 s% l! R* d1 J7 V; h5 j9 ~+ o
  25.   el: '#counter-event-example',2 k& H. ?4 p5 S0 e) N* I4 B
  26.   data: {+ v% N* }1 i: A% a
  27.     total: 0% c' w' L$ `& X9 Q0 {, z4 v& E7 G! L
  28.   },) O; o/ t. Q" ]( E  v7 S$ U4 u
  29.   methods: {
    - H5 t# M$ D$ Y$ W4 N4 A
  30.     incrementTotal: function () {
    ' m, r# v# {' S+ o: V
  31.       this.total += 1/ ?- U5 Y# N' W6 l
  32.     }
    " U! |2 p% `( ]  m8 C& ~- a  u
  33.   }
    " f7 O0 O3 [6 P; \  d
  34. })
    8 z7 O  C" i" ^0 f# s
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    5 L; k) y' ?: ^# s4 p. n1 x
  2. Vue.component('child', {
    $ l% T: V- I7 q! u7 X* @; M+ H
  3.   // 声明 props+ T6 @5 X9 P6 c. f: N/ |% V
  4.   props: ['message'],
    ( {& G2 w; o& _  j, V0 g2 ]
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    $ C; g9 N5 U8 ]& F* M5 ~
  6.   template: '<span>{{ message }}</span>'
    4 _3 P' ~/ c* M; I9 z6 H& P8 f
  7. })
    5 w" T/ g' [, L
  8. // 创建根实例
    " ^& r0 H3 e. @6 Q+ N3 Q( J4 @9 {
  9. new Vue({
    / k' [: O4 D0 S+ J
  10.   el: '#app',
    ) C+ t2 v- Y* N$ e
  11.   data:{% b$ Z) m9 g. K
  12.     message:"hello",
    . E* }' V1 ~; T- ?  U- ?
  13.   }
    3 F# s  n: N% p# c& H. ~6 ?
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {- b% n) @& B- s/ b; B
  2.     incrementHandler: function (v) {
    ) Q7 ]" j) N' Q! ^
  3.         if(v==1){
    : _0 S. Y5 d; Y& F
  4.             this.counter -= 1
    4 l( w4 `7 F# M. m$ }% l
  5.             this.$emit('increment',[1])
    " l8 T* I4 e2 n; m4 G" O
  6.         }else{% f  }* [. T/ p0 p$ d+ u
  7.             this.counter += 1
    5 I1 F  S. B& ^7 l2 q7 w2 V
  8.             this.$emit('increment',[2])
    2 t3 r4 h: \& `: v" Q& i
  9.         }
    8 z0 U. z8 b# A7 S: w2 }! m0 ^
  10.     }
    7 X% K% ]' C! Y; k
  11. }
复制代码

/ `) S: I" @1 b$ C- h! N5 l: B8 n; ?' |6 U, B
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-11-1 11:31 , Processed in 0.137384 second(s), 24 queries .

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