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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

) M! |2 [8 v0 ?2 p7 T, r, t$ X
  1. <div id="app">" k% R1 J" z3 n
  2.     <runoob></runoob>/ l$ i! D* a" E( g
  3. </div>& O( \9 P  w% h, K2 N, b2 N
  4. 1 M% r9 V' L' r: N5 U6 {0 X
  5. <script>7 T% s6 I5 Y; y
  6. // 注册2 Y+ ?* A' _7 M* D
  7. Vue.component('runoob', {9 V9 y+ K( t& q4 O9 Q! C  q3 P
  8.   template: '<h1>自定义组件!</h1>'
    - |7 e8 l4 u( y3 N  s' j
  9. })7 q$ r& T; q9 ~; N
  10. // 创建根实例  g8 }0 }) D& ^0 f" C
  11. new Vue({5 M! {# T. b' {
  12.   el: '#app'
    " l6 k9 z0 o- o& o1 e, O
  13. })5 X- u9 q7 I1 t1 Z6 \6 O' W
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

' d; S. d1 x, ?+ A* {
  1. <div id="app">
    8 n0 j4 J% p! V
  2.     <runoob></runoob>$ q7 t0 Q  W( M9 }9 E( b
  3. </div>  j! `1 v+ n/ j5 h2 S' G

  4. 8 C) @* g( ?8 D; n: h' B
  5. <script>6 w! }1 N3 q2 N* y' o
  6. var Child = {$ N7 C3 ^. g) |
  7.   template: '<h1>自定义组件!</h1>'
    0 s1 r. Y. \  \. I2 K
  8. }, h' \/ }. ?* T
  9. + t$ A  B. I, a
  10. // 创建根实例
    ! ^* f$ L$ K" S- g% k
  11. new Vue({
    8 V/ K( S0 B0 c2 l, B& V
  12.   el: '#app',
    0 T- @4 o0 e5 Z* Y9 y- H0 z
  13.   components: {4 W4 V2 t& C2 V! T* a" s/ ~4 _
  14.     // <runoob> 将只在父模板可用7 D. |2 l! }2 U" K, B
  15.     'runoob': Child
    , U" K5 {' [7 ^) _! G$ ?) h7 U
  16.   }
    6 x( M/ L( N  V5 N) e
  17. })- D( U( n' Q% u" @3 Q* y
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例9 h  P6 [7 \3 g8 [6 a/ j. Q; o
  1. <div id="app">+ U2 B, A$ V( A$ C" l9 ]
  2.     <child message="hello!"></child>0 z2 ^1 N; f2 s1 g3 e. ?3 O
  3. </div>/ x$ t1 [7 G' w3 q. a

  4. 4 ~8 l$ m/ Z# F$ c; s, ~
  5. <script>
    ; c, {* w. @; Y! @: N7 M* x) g- g
  6. // 注册4 z- n$ V3 U7 L% w, t
  7. Vue.component('child', {9 N  Q& W8 N- X. U
  8.   // 声明 props  i4 r5 w0 H  p
  9.   props: ['message'],8 M1 j$ i- ?/ _
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    4 X. [7 o2 j2 v2 ?5 N1 A" a
  11.   template: '<span>{{ message }}</span>'
    * k9 t& f4 P& e+ E. M
  12. }), `3 E( V; ?0 p* w
  13. // 创建根实例
    5 x# z1 ?; V& _; _+ U$ f& r- I  T
  14. new Vue({; A5 d4 v" d7 y  |3 c, H+ J3 z
  15.   el: '#app'2 w$ z9 L& I9 Q
  16. })8 s$ p$ l; ?8 b4 T# N, y& `0 {
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例' P$ _& `9 e2 h# U0 a
  1. <div id="app">
    " ~: m" ^: a( |9 q7 f3 |3 A
  2.     <div>: y* \' {% g" |, h7 f! m1 S) `0 T
  3.       <input v-model="parentMsg">
    9 P$ @6 s" ]4 K* I) p0 t
  4.       <br>3 F/ R& l: }% h" ^8 Z# X* v" d
  5.       <child v-bind:message="parentMsg"></child>
    $ S" f& I$ ?1 i- ]$ K
  6.     </div>; N2 y/ O1 f8 G6 z8 @& J
  7. </div>
    - R- Y  Z4 V# a* Y3 _0 `, E
  8. 1 g9 O6 c4 t/ E5 N& \7 U3 r
  9. <script>
    / R! H  L# e% v4 I3 [! l. n2 P
  10. // 注册
    - e, \, a; v7 `7 ~9 k
  11. Vue.component('child', {
    ! h) j4 Q. e! S% m# Y/ O$ b6 x
  12.   // 声明 props
    9 I: V' [) U* u/ g# j
  13.   props: ['message'],' j# ^" J* @  S; E
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    + l* L8 l. h; O  z
  15.   template: '<span>{{ message }}</span>'
    0 g' c0 n! n0 b
  16. })9 J" m8 }! G3 S: }
  17. // 创建根实例& K" G" M' Y; g- l9 R
  18. new Vue({# P- n2 }7 n5 G' ?' ?6 p3 \7 A
  19.   el: '#app',- D% E6 ~8 I) b. m
  20.   data: {
    , |- A1 K! D$ [8 X3 e
  21.     parentMsg: '父组件内容'
    # ]0 w9 X- [$ g& \
  22.   }6 R8 n/ K* d* E5 m, D4 l( E
  23. })
    6 q; b7 {9 b4 W6 O
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例+ @: J, A) V$ m9 R# a: _
  1. <div id="app">
    ' d/ e9 s3 U' D! _) H# _
  2.     <ol>
    % ?. u, a  }8 G& d4 G9 P- U  C" |
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>5 y. S5 Y' G8 N2 E% L# `! Q5 u
  4.       </ol>
    7 S$ {: R: o2 c' A. T4 R5 r" G
  5. </div>/ ^6 R, P! s# u

  6. ; D$ q. ]- R1 H$ e3 N  z0 L
  7. <script>. C  @( y( e  Z% T* W
  8. Vue.component('todo-item', {9 K' N4 E1 t* P2 C8 h- Q/ j
  9.   props: ['todo'],
    - e! A2 D2 l& {7 t8 }
  10.   template: '<li>{{ todo.text }}</li>'
    ; A! y4 D  w+ o8 g
  11. })7 b% M+ l5 ]' z  g) \
  12. new Vue({
    ' a; x$ r* S$ F( B/ D4 D
  13.   el: '#app',
    , k# p# b$ K! C- V3 s8 T/ c+ G& m
  14.   data: {
    ) A6 J) F0 d4 g* L, U' N0 e
  15.     sites: [6 n0 _/ Y6 q6 t% f+ ^$ f
  16.       { text: 'Runoob' },
    # M; Y3 O9 S) z2 ?( H# g
  17.       { text: 'Google' },4 n: d5 _; Q; f; O
  18.       { text: 'Taobao' }
    ; I% Z+ i' \, G
  19.     ]; U! b9 g. A6 ]/ X% I" ~
  20.   }: y6 }! o! |! K* V9 H- l0 Q
  21. })& F3 L" p" C" x+ H
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {" Q/ l5 c3 h$ Z
  2.   props: {  W7 g+ {. O0 T" H! E# b( ~
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    " \1 O9 a3 }3 G, V/ t
  4.     propA: Number,
    3 q. p3 l& G3 f+ b+ s3 n
  5.     // 多种类型
    $ A8 d" H- z9 y+ p5 x
  6.     propB: [String, Number],% J# H$ E7 l3 ^9 [' T/ y
  7.     // 必传且是字符串
    # J  S* P+ a5 I) {8 k8 `9 n5 A# P% u) b
  8.     propC: {  K- V; L* O% N0 T7 Y6 \
  9.       type: String,
    9 Q' N& g( l- ~3 P! E
  10.       required: true$ X: `$ |' s! A& \- s, s6 M
  11.     },# w, b7 q% A( _+ z& ]
  12.     // 数字,有默认值
    6 n2 Q) D, i9 e6 F' g+ N
  13.     propD: {
    / k: ^' P# T/ ]! l8 c4 R
  14.       type: Number,
    , F" i- g( X1 k1 p
  15.       default: 100- y6 s+ S7 p# Q& }
  16.     },; \9 O3 k# b! {2 W+ W% _* _
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    6 r: ~' z' O' P; F# n
  18.     propE: {2 r& Y6 E- b) {+ ?' [  x
  19.       type: Object,
    6 A5 t2 m" y4 \
  20.       default: function () {
    ' m. s5 R6 `$ c3 m
  21.         return { message: 'hello' }
    & I: |  W' D9 w* D4 d% ]+ Y
  22.       }
    ( v( s5 u# R+ k  y( O
  23.     },+ h9 r: h' F. f9 k: T8 O; E
  24.     // 自定义验证函数
    # n" _* ?! @5 }# w, v1 [* Z% p$ R
  25.     propF: {
    ; G8 `4 P8 g" y4 U
  26.       validator: function (value) {* _; Z2 K, c" N3 x& d
  27.         return value > 10
    8 J. X0 X5 E2 k6 X8 Y  R& S4 t
  28.       }5 [) f+ I. _6 X( L9 k
  29.     }$ `2 e/ ?# y* P/ V
  30.   }  `. E! D3 B# Z' ]" h8 M) u
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array2 U) A% D# N/ ^: b% |4 `
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    $ [' B1 p$ t: }" z7 O/ y9 Z
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
7 o4 q5 o( `% P, P
  1. <div id="app">! t+ e6 w0 p# D9 S$ O( n
  2.     <div id="counter-event-example">
    # O+ E! \- o; j) W# H5 P
  3.       <p>{{ total }}</p>
    ! A. X' }9 a) E+ h- p8 A' ~# k7 y
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>1 O. d# {2 a- R" P% F8 I8 E  q
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>, {* j: g  ^$ I& [7 z, R/ g* q6 [
  6.     </div>
    ' a. n" O8 H8 o" r2 c
  7. </div>
    & v4 o2 m$ E% @" T

  8. - E. f4 H4 j- U) f8 L; ]0 E
  9. <script>2 D) J4 g% a" v" V8 S4 F
  10. Vue.component('button-counter', {6 G% ?' r2 r& ^' [
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',6 G2 b' Y/ ~/ K5 w3 O: U- z% T
  12.   data: function () {$ d( Y  ?" C* E# L2 P0 l8 ~0 T
  13.     return {
    ) c1 J- X: @8 X  W6 @: i  x
  14.       counter: 0# X% j* b3 n( s& Q
  15.     }# v! f3 t: S$ A1 g- Q
  16.   },
    $ X( I: ], ?3 G7 a" {' T, |
  17.   methods: {% w! N1 y! X8 W( G8 ^
  18.     incrementHandler: function () {
    7 G6 h( x+ U! i* s* {! s
  19.       this.counter += 1
    8 o' K7 g1 h# C
  20.       this.$emit('increment')7 ?- ]! h7 [4 }; N! |5 E  K
  21.     }  N. |! b7 ~( g- k& F7 t: y
  22.   },! B& z) y+ O6 _4 Y$ m
  23. })) V2 x& ]  E! r) t
  24. new Vue({; y7 i; U) a8 E8 [2 D; Q
  25.   el: '#counter-event-example',2 l" y  b, t$ D! N8 Y$ G
  26.   data: {
    ( R! r6 e  R3 P# z" N: D/ y0 |
  27.     total: 0
    8 r) a7 X9 i3 `. I
  28.   },
    . O8 U  F4 p) c1 p( J5 E( k
  29.   methods: {  V3 c' `+ U5 {) \5 R- ~
  30.     incrementTotal: function () {) _8 C! L" q, @/ m. d3 v
  31.       this.total += 1
    & N& y+ k  y1 Q3 O4 q* D
  32.     }
    , j! \6 F' A' a: d
  33.   }" h; `" E$ R5 p5 L7 M
  34. })
    * h( }1 ^9 x) ^$ }- y
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    $ e: x% \6 m/ [/ H- Q; h! O/ D" n
  2. Vue.component('child', {. {/ X3 y, q$ {
  3.   // 声明 props
    - _2 }6 u& k5 B4 D) W' Q# ~
  4.   props: ['message'],/ X3 F6 P6 `; r( x# m0 s" \% d
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用; }) |$ q  a0 a2 J. w% L  V2 R
  6.   template: '<span>{{ message }}</span>'3 {8 z4 s4 B- g- Q7 C. z
  7. })
    5 i6 n. Q' q+ U! K) T- [
  8. // 创建根实例
    " _) m. U- T( l; l& m" C& ^2 Y
  9. new Vue({
    ' _5 h9 ^9 e$ n/ e2 V
  10.   el: '#app',
    ( g5 `. p" k3 ]
  11.   data:{
    ) u7 E: q. C& y3 u& G6 q; Q# P, F
  12.     message:"hello",
    ! V# ^2 X2 Y- g! S
  13.   }6 t8 t2 @+ ?* x
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    / Q& o5 s, \9 N3 _0 g2 |
  2.     incrementHandler: function (v) {9 _2 [$ Q- |: G* w: v% w- ^& @" F
  3.         if(v==1){
    ( ^( r, Z" i8 y! K0 R  _
  4.             this.counter -= 1
    ! @5 D4 _( ]' B+ N4 Z  U& f
  5.             this.$emit('increment',[1])
    8 p5 H5 T% e3 F* e) D
  6.         }else{
    6 ^5 [: U: o! b% d: K. Z
  7.             this.counter += 1
    9 d  D2 @$ W& x
  8.             this.$emit('increment',[2])
    % ?* o) U$ p# ]4 S& I& r6 f
  9.         }
    # O: D4 Z9 d2 T
  10.     }
    7 m' {0 ~/ T% Y
  11. }
复制代码

0 }( C4 @( O7 Y: i' s5 h& e+ t8 _1 o1 A* o& J
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-15 11:19 , Processed in 0.159339 second(s), 22 queries .

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