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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

5 R* \' ^7 b- ~2 z
  1. <div id="app">
    5 n4 l; _& o5 g% j
  2.     <runoob></runoob>
    - q  g1 q& h# t3 T- U9 b& R
  3. </div>; l& ~; o8 X' e, N4 r; C

  4. 0 W: e8 K' v$ U% V) Y: _
  5. <script>/ A/ f* W; D( t" v6 j. n
  6. // 注册
    ' T9 w' `: T; W* z* L
  7. Vue.component('runoob', {
      e+ ]4 _6 c" p  T+ t( }* S
  8.   template: '<h1>自定义组件!</h1>'8 n; o% D6 {# X# u& D
  9. })
    6 J( S6 K- _4 t7 a
  10. // 创建根实例
    1 W0 M0 w4 p9 p
  11. new Vue({
    + k$ f$ ?: R& `; E
  12.   el: '#app'
    . `( g( v3 w4 U5 ^9 J
  13. })4 [% i3 k( T: U8 u* a
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

6 Q' C0 S. t( [& n* g: U1 c
  1. <div id="app">9 F# t$ _3 n  \% p9 w$ ?
  2.     <runoob></runoob>. A) w; E3 _: S- y! V
  3. </div>. r! }7 w* ]: B3 F5 w3 ~0 {

  4. 3 j5 ?, H+ J: H( G
  5. <script>
    7 v. e* K# X- {) |
  6. var Child = {
    " b+ }  u/ Y3 T  a& I; r
  7.   template: '<h1>自定义组件!</h1>'
    9 I/ `  }4 }5 i/ v3 Q3 U; o1 e7 Y+ h
  8. }6 u" ^8 _. R" W1 H& y) ?
  9. , @' {. G8 v! I$ J7 s9 t, v* n
  10. // 创建根实例$ k/ v2 W& q9 p" k& b. E0 z
  11. new Vue({' W2 G2 M1 R  e) n+ F4 A2 K
  12.   el: '#app'," a2 p, ~% M! b' [8 O
  13.   components: {
    / T0 p" u" o5 S) f, s& U. _
  14.     // <runoob> 将只在父模板可用, Z" y5 ]' b6 Q3 h4 W* k5 X  e$ e
  15.     'runoob': Child
    5 T" [0 G+ X0 m6 T
  16.   }
    , E- X, o( E* g: a5 R0 {- w
  17. })& v* U9 s. m2 T: \. P3 b+ z* W
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例' X6 `# a/ o. S" v8 f8 Z
  1. <div id="app">
    5 \: U! J# s1 p+ w$ F: r
  2.     <child message="hello!"></child>
    ! o4 l& ^* V# s1 ]' U
  3. </div>
    ' c/ }- u5 \3 C! p! l7 |$ n
  4. : F2 a- t/ m1 b/ P
  5. <script>
    , n- z+ m$ n8 x4 M& _: X2 B/ y
  6. // 注册
      j, Y; _9 p2 o8 p
  7. Vue.component('child', {( ^, ]/ k1 N# @4 O. b) p9 }
  8.   // 声明 props0 J5 \/ h! u6 X
  9.   props: ['message'],
    9 G- d8 q3 S- n, G) b/ K
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用* V6 i1 K% J2 f
  11.   template: '<span>{{ message }}</span>'
    9 Z( R" s) g2 V8 \8 ?3 V; J( c
  12. })7 r  u( Z. s5 s6 ?
  13. // 创建根实例
    ' C1 k6 w5 L& ^- z6 G. e+ ^+ a
  14. new Vue({! t2 Y8 |# L: r) v1 v
  15.   el: '#app'
    " V& Q  s# f' t3 @! r! X0 e+ M. U
  16. })
    5 c6 M1 `* V8 H4 u, j  Q" U
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例( m2 ]* Q$ L  k+ @% |! D/ A
  1. <div id="app">
    8 E" A& V8 U- i
  2.     <div>( B4 J( r. ~0 R7 E) R& H
  3.       <input v-model="parentMsg">! ]$ g1 X  A: ?: }" H8 Y2 ?5 k
  4.       <br>
    / d0 n, B4 ]* p& ?
  5.       <child v-bind:message="parentMsg"></child>
    7 w2 s& a9 d" `  v$ k6 D3 x" ~
  6.     </div>
    ( Z+ t3 Y0 w( x- R" q2 R7 D
  7. </div>
    - L0 j( G5 E9 C, h) k
  8. , B% I9 H' D* v/ o: M' J# t
  9. <script>
    1 x# z7 J$ B3 N, H5 K
  10. // 注册
    6 C# n  D$ z! }, @+ Z" f% O
  11. Vue.component('child', {
    8 l$ `& N4 B+ O
  12.   // 声明 props
    ' j; i: b( `( J3 [! J0 g
  13.   props: ['message'],
    3 h+ d- l6 `) C& l$ Q  h5 X  ]
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ! O: Y8 v: M1 P
  15.   template: '<span>{{ message }}</span>'
    " h" `8 ?# B) L
  16. }). A+ p7 G" q  z# n
  17. // 创建根实例) m7 {; R, K- l: _
  18. new Vue({7 e1 q% }5 N7 g0 F; a; a
  19.   el: '#app',
    ' x/ O) b- `5 |) m1 v1 q: v) C
  20.   data: {
    2 {% ~, m" q4 ]6 u
  21.     parentMsg: '父组件内容'8 x/ A1 p- `* T+ i$ t
  22.   }
    3 i7 D. q6 o, V& V: r  g
  23. })
    + K- v1 x1 b5 B# Y1 d  Z
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例& `* F: r* F5 r, k1 T/ R
  1. <div id="app">9 Y2 f+ E6 c: [
  2.     <ol>$ s- Z" M: d6 g/ U
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    5 N5 o' t$ z7 C9 f4 s
  4.       </ol>
    3 W/ Q# r$ g/ X. z8 {+ ^' _
  5. </div>! r6 g6 ?5 R/ z) ]! P, j' X

  6. 0 {1 j4 _/ G" n+ b! E+ i
  7. <script># }2 G: [" A4 m( X; M( J; a) }
  8. Vue.component('todo-item', {
    ) i, D$ T( I/ l4 b: v
  9.   props: ['todo'],0 d" K7 y! N1 I) `' y
  10.   template: '<li>{{ todo.text }}</li>'! R9 T6 @( K5 a! u
  11. })
    , t- ?- Q5 E8 N0 I0 b8 Q
  12. new Vue({' w) L8 w8 K+ j3 I( ?/ @2 z
  13.   el: '#app',; U) t3 ^" Q& I1 o# P
  14.   data: {
    + @2 u& h7 B5 J0 N& D% S
  15.     sites: [
    4 c. k, |/ ]0 G( A- W
  16.       { text: 'Runoob' },3 u" x7 Q. v* N
  17.       { text: 'Google' },
    8 O- F+ {7 m( I+ P/ g  U. ]
  18.       { text: 'Taobao' }+ v. H4 @" g6 U8 f
  19.     ]
    . p% b5 Q4 @( r- V9 ^% U! [4 _
  20.   }9 i+ e8 r7 E0 T; l4 x+ h" `0 ?
  21. })+ _  l0 u! s( i. N, V/ W) F! G
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {7 t* ], u) x6 Y4 A2 `& `
  2.   props: {4 V. v4 q- t! w. W# y) L2 r5 I
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)2 V5 ^. C' |/ d4 X
  4.     propA: Number,, }9 f5 e1 r* q8 \7 m+ r. G9 X4 F" Y
  5.     // 多种类型( x) a4 }! S% l  g
  6.     propB: [String, Number],
    3 v% O8 A% ?$ d1 [
  7.     // 必传且是字符串
    $ M( n- D9 ^& C6 E! |+ q, R5 r
  8.     propC: {
    9 M6 r$ x" j+ P3 g$ ?
  9.       type: String,& }2 A0 i9 C. G( r/ x0 a3 h
  10.       required: true; t& d& e' [+ V* a% |
  11.     },
    ' c" U" P  E, w: I( h
  12.     // 数字,有默认值
    / ~1 o$ }( [5 s- w) k& m
  13.     propD: {
    % E5 y* B0 q  s4 p# O0 ?. Q& u/ \5 l
  14.       type: Number,- Z$ z, u8 [! q) Z
  15.       default: 100
    / z& s. A( h" s6 e, v* B% ~. F
  16.     },: P- v0 J6 |; d* ^( J
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    0 A. p+ o2 c$ a6 ?
  18.     propE: {
    9 l% h' f+ F& k9 l
  19.       type: Object,
    1 e, a) K  I3 ~% \; x3 e
  20.       default: function () {
    , V) v4 }7 S' y3 f- H: q7 M5 z
  21.         return { message: 'hello' }
    9 e, P+ F3 b; i9 s" \$ x
  22.       }
    ! X! W  q3 \3 N5 p7 a) e0 }
  23.     },
    & w4 U/ k0 O' f& L, S$ O& f- T; M
  24.     // 自定义验证函数0 P3 V5 z6 d5 E
  25.     propF: {9 d& O  E. z  G0 \
  26.       validator: function (value) {. N( n; b& \6 P
  27.         return value > 101 g( X! H9 H! K0 I6 Y9 u# p9 \
  28.       }
    7 p% M, i! Z  R/ K' q, n0 @4 H
  29.     }
    $ m  A3 ^9 ]+ B+ J6 h
  30.   }
    & x. F9 Q# l8 J1 S  s1 F& z
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array! ^! ]- M6 U+ |$ [; ~
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件. ^2 I* z7 v# ~' L. P/ G7 {  D  ~
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
* q  S, n8 M) ~8 ]8 n! g
  1. <div id="app">; O( N4 y/ ~7 ^' _$ [( T
  2.     <div id="counter-event-example">$ ?  \& r. v4 E% _
  3.       <p>{{ total }}</p>
    * |% m  w1 r  t9 G( c# X, \% S
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>$ o+ O) `9 |% M+ e7 r# f
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>% M' J$ n$ C8 s* G+ h; D
  6.     </div>
    - M# s! X! q  b" P
  7. </div>) J, N3 Z, F4 s: }8 \5 ]
  8. ( m* Z" X6 f$ r/ `
  9. <script>" ?0 y' m% }* t. o; K
  10. Vue.component('button-counter', {
    3 L$ h% C9 w: A4 a3 C
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    ) ?7 M* t2 ]7 {, J3 y- |* P  k# d+ q
  12.   data: function () {
    ; @5 k' `/ x% }- N- q  R. I
  13.     return {
    3 a; F& ]" m! K8 {- L  g' x
  14.       counter: 0% ]7 G- [1 x& o
  15.     }
    6 u: P( t4 ?6 J: B0 {. S
  16.   },
    & x7 Z7 y& ~6 {: y. P% q
  17.   methods: {
    0 c* |% ~; h3 X
  18.     incrementHandler: function () {
    - b, F$ X8 q, `6 N' p- E9 i; i
  19.       this.counter += 1
    ; P) U5 F% N* I2 N
  20.       this.$emit('increment')! i4 c. D% J/ K7 _$ b
  21.     }
    . T: S& n, R4 z' y
  22.   },
    , Z/ v* h$ ]6 b, I3 L) v1 I3 W; {
  23. })  J  W+ i! R) m% B$ p, s
  24. new Vue({( H* i% d3 C. z/ a' Z$ Y
  25.   el: '#counter-event-example',, Y+ d0 t4 T% G8 W  @% P& c1 |
  26.   data: {
    3 \1 ]1 |, ?) q! M7 H
  27.     total: 0
    0 |" X: S( ^9 B& }7 w9 j
  28.   },. g2 @; _+ y9 `& H9 S, M  O
  29.   methods: {
    6 i8 e5 g; r, x
  30.     incrementTotal: function () {/ H, {5 e$ u2 B; F
  31.       this.total += 1
    6 ^1 ^3 x7 p# x- F  X
  32.     }  v$ L% @% P- A; U' L9 ]
  33.   }
    8 ]/ G* o% y% q4 x8 {
  34. })/ @: H0 U1 w2 q* d' f
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册% K' _6 |9 Q" N4 p3 U  K/ y/ j
  2. Vue.component('child', {& C2 g' R9 L3 H1 u$ ~$ B
  3.   // 声明 props
    ; m" D; ~! ~: T- Z
  4.   props: ['message'],
    ) Z( i& y$ M& L! N2 ]
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用6 A- X1 Y8 I# N5 Z' X4 s$ n
  6.   template: '<span>{{ message }}</span>'
    ! [' L0 q1 B. b* C; g* z2 G+ A2 d
  7. })
    ( D5 S& `2 @8 X/ L( r% ~
  8. // 创建根实例7 n, S; i! W: s# X1 C+ O9 x) O& X$ _
  9. new Vue({
    & g$ A9 G* W+ T7 H  v/ }0 T  z2 o
  10.   el: '#app',
    ! N" K  Y! F8 b" D1 X4 [
  11.   data:{( b' Q1 T# B, M. K" K9 [9 z
  12.     message:"hello",
    , w8 q6 L8 c. m+ X/ ]* Q1 A
  13.   }
    ! }3 s: l: g* W: X
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {( J7 |$ [2 E* |# e3 D2 w  Y
  2.     incrementHandler: function (v) {
    ) C4 N6 g6 ]8 v& s6 g
  3.         if(v==1){
    8 n% ?3 R! n4 s# n& Y5 D$ B
  4.             this.counter -= 1
    9 t7 K7 s$ n, p  O- e- e
  5.             this.$emit('increment',[1])
    , m+ a6 y% ^, r  k- v( f  ]
  6.         }else{
    ; D( n  m4 t7 ~
  7.             this.counter += 1
    ) p$ \6 W* X- [* O5 \
  8.             this.$emit('increment',[2])# e0 |7 C: x6 b* [- ^. `  v! X1 U  ~
  9.         }; z( D- ]- C8 z  {2 Z& F
  10.     }0 f8 \- p. {9 l) l; W8 A$ m
  11. }
复制代码
) X/ x( w. ?$ U% x
7 F3 V6 U- I! o% q, v' h
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 16:44 , Processed in 0.060973 second(s), 25 queries .

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