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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

- h' ^. ^! E7 O9 ^% h1 L8 b
  1. <div id="app">
    ( g3 ~: {$ |2 ]& C
  2.     <runoob></runoob>% N9 W% ]1 O  m/ F8 X& Z2 x: k, l
  3. </div>. i& O3 q; X$ E2 E& b

  4. 2 C2 }; n& X% {7 B3 h" y# W
  5. <script>
    0 M0 u( c8 }: h8 y% C: ~4 u( q
  6. // 注册" W$ I$ {0 d/ h7 z- k
  7. Vue.component('runoob', {
    / C' _& D. Y: ~* y0 [
  8.   template: '<h1>自定义组件!</h1>'
    % S% z( C& u/ S( e5 z  P* F
  9. })/ d; c+ R! G  V' h; L* G# ?
  10. // 创建根实例
    ( B& u: E2 H# T% b+ {
  11. new Vue({
    ; |( K& Y! b7 G4 k# S/ l  Y" m
  12.   el: '#app'
      B/ X0 B0 q5 D+ x' f
  13. })% [) i) x' t5 p! q: D+ Y
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
/ C+ N3 C: o/ d& t
  1. <div id="app">8 @; A9 G  f$ f
  2.     <runoob></runoob>
    + d6 S: w; L- ~6 a) }/ U
  3. </div>
    / }$ s( Y% R* j2 J% U% r  I% ~
  4. * u4 H4 Y) d1 M! E3 e4 Z
  5. <script>
    . G9 i* [; B/ _
  6. var Child = {1 J& B- a* Z! Q: ~  C( m
  7.   template: '<h1>自定义组件!</h1>'
    / @# s: g( {. i1 L
  8. }
    - `1 q- k' d* w/ b

  9. & k9 C! r5 n4 D4 B3 v$ u
  10. // 创建根实例5 i  N. K, D3 H+ F- z, T
  11. new Vue({7 I) y$ u3 ^9 Z* C4 U
  12.   el: '#app',/ |$ C1 ]2 w6 w( a2 F
  13.   components: {
    0 S" ?" w! ?  \$ [  M
  14.     // <runoob> 将只在父模板可用
    4 _4 L8 _3 E- A
  15.     'runoob': Child  S$ a& h6 Y8 v  x, o+ g  p
  16.   }
    2 {, S  v5 C2 l$ ?( @# Y3 y
  17. })
    / G9 W  W' q, ]$ x: |
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例& D$ G/ i9 x4 M7 `6 ]8 p
  1. <div id="app">. n; |+ i  A$ A
  2.     <child message="hello!"></child>
    2 G0 }% p0 V8 r2 ~+ V2 a
  3. </div>
      U9 B& Q: _% o& G  O/ \; v
  4. ' O3 ~+ ?4 {: h, M- d2 @
  5. <script>
    / O! W8 A# n2 I
  6. // 注册3 H7 q  [  x- U( R, f" N5 o4 U
  7. Vue.component('child', {& w2 K. F& ~( U! J
  8.   // 声明 props4 x# j7 A' a9 p, S
  9.   props: ['message'],: Z, l1 r% ]. i( m
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    5 }, Z* w. q! e+ x. A$ t" s8 M
  11.   template: '<span>{{ message }}</span>'' k4 S" E# `1 L$ `& ?
  12. })
    5 M+ _# i6 [& L' F" f0 I5 r! H
  13. // 创建根实例
    # h! \9 D1 N- z
  14. new Vue({1 ~# b  ?( F( S1 B5 F; B
  15.   el: '#app'# p, l  x3 H7 I' T) m. K  W
  16. })
    + c& U3 u1 H" e7 I4 N
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例6 Z: j7 q8 w) ]. q! M/ y5 x
  1. <div id="app">& g+ w: g- [( [' M* e5 _* s1 ~  m
  2.     <div>% {7 S; P3 C1 Q8 {. L- `8 t
  3.       <input v-model="parentMsg">
    $ k3 [4 C. I7 ~8 u) I
  4.       <br>( ~( M( d9 t6 H
  5.       <child v-bind:message="parentMsg"></child>/ w* V" y' W6 O
  6.     </div>! l" |) j, o' k0 N
  7. </div>1 ^  F; t2 b3 A0 H) r9 h$ B  x2 p
  8. ; n* b8 U* [, M
  9. <script>
    2 r4 _! j" _. L
  10. // 注册4 J5 }" }9 K" R
  11. Vue.component('child', {
    2 F+ {. [" {8 T# X
  12.   // 声明 props
    $ L1 ]2 Y3 Q1 z& u/ F# [; u
  13.   props: ['message'],
    : @- ~( p$ N6 N! w# ?
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    % S1 ^- I/ x, B* K5 |" S
  15.   template: '<span>{{ message }}</span>'
    # R6 i% X: m# o/ e. R
  16. })& k  r2 m0 q. p# z. K* X
  17. // 创建根实例
    5 I$ v, F; a! \2 \8 w. O
  18. new Vue({" n1 M/ c+ c) l# w8 k
  19.   el: '#app',5 o' }5 U1 j1 \% `2 O
  20.   data: {; H) W' e( S0 ?2 h; n
  21.     parentMsg: '父组件内容'
    + s9 n0 i: g9 ^+ y
  22.   }
    - ?. B2 c4 N  k
  23. })3 K+ W$ C- f& K$ `: }
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例) A. c6 Y1 V4 G2 \3 g3 j. n  }6 e
  1. <div id="app">
    9 R9 z. A) \" j/ X" @6 x6 h
  2.     <ol># g6 ?, l4 E$ g- y( D* {0 q
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    7 g; Z- {/ A  u
  4.       </ol>) M& i5 z9 w& n8 B- P
  5. </div>
    # e9 C0 w; {4 \& [0 T( V

  6. ( u( s# i' ?: U/ W6 x
  7. <script>0 x% y5 P4 ^& P+ Y9 Y2 U7 x5 \2 Z! u
  8. Vue.component('todo-item', {
    ) F$ F5 S4 T" h- Q- I; J+ O) ]
  9.   props: ['todo'],8 A* _5 r# O! N1 i0 _: Z% g
  10.   template: '<li>{{ todo.text }}</li>'+ h3 Z8 K, m" k; z6 w0 S0 H
  11. })
    $ Z# |+ K0 o/ P0 H: k( V) z
  12. new Vue({
      Z; O& X% _* }2 s. h' N2 Y1 g
  13.   el: '#app',( `. z# L' V- e6 C' L
  14.   data: {9 [, G! f6 q9 U6 v
  15.     sites: [
    . O1 B$ K2 H' g) r
  16.       { text: 'Runoob' },
    ! Z7 f  e& e  Q4 s9 U: P1 g- Z
  17.       { text: 'Google' },% W1 G( H& V) \2 Y8 U9 {
  18.       { text: 'Taobao' }: b6 I: t. [$ A- m" i
  19.     ]
    " `- M* f  C" r# ^0 m9 b
  20.   }) _( E/ q1 \% d# b
  21. }), c7 T& \' ]0 b8 s$ ^$ o. b. I
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    * ^7 e. f0 I5 M" z
  2.   props: {" e# @( W+ f+ k* n5 B9 f
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)- D2 P4 `# c# k
  4.     propA: Number,
    1 D' I( y. A# V) x
  5.     // 多种类型
    ' p6 I1 V* @" M! m
  6.     propB: [String, Number],
    0 n7 K8 ?* B8 y& R9 J
  7.     // 必传且是字符串8 R* j: ?! [4 v5 w" ?1 x  ^  [# F
  8.     propC: {6 g! l7 H4 j, c- z3 e( B' O
  9.       type: String,
    ( J& G- a6 J2 i8 B! |+ P+ l
  10.       required: true. r" O$ N) w8 N0 H! e/ t- u( }) C
  11.     },
    7 [5 [2 H( A4 Z9 A# Q& W& Y
  12.     // 数字,有默认值
    8 ~9 J) [3 i0 V2 n
  13.     propD: {3 B' ?1 @( l- O% c% Z) X$ G5 C
  14.       type: Number,8 |4 p  F9 T9 P- T! @% g
  15.       default: 100% d  [% h# ]. T! p$ T; m/ u
  16.     },
    # L) S; }, W" |
  17.     // 数组/对象的默认值应当由一个工厂函数返回5 h" Q- R- }8 J8 Z8 q$ y9 e3 D
  18.     propE: {5 O  ]. s/ z, s4 B3 B1 T
  19.       type: Object,1 ]8 Y: q9 T5 d* x# S" K2 `2 A( p
  20.       default: function () {6 v7 y  J7 o" r" m
  21.         return { message: 'hello' }+ I- N+ \1 \/ Q2 H
  22.       }  W. d2 b* v& ^
  23.     },! K; i' r5 W* X% |
  24.     // 自定义验证函数6 u8 }5 {8 y4 ]8 e6 F) H
  25.     propF: {7 Y7 z, H$ \( e
  26.       validator: function (value) {5 Q9 J6 W/ x" j
  27.         return value > 107 _; o" K  ]( o, u, o
  28.       }
    ) ^- W" b! k3 `- k+ z9 p
  29.     }
    ) S5 A* |4 Y# f. C) Z% R
  30.   }
    : E& F- G1 _$ I' K2 _6 H
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    % L$ f% F' j+ C$ F) P( _
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件; T+ g$ T8 g$ O& _4 H: W2 a
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
3 I$ q" f6 Q" c# p4 E1 V
  1. <div id="app">& W) I3 T- a, k7 O! `
  2.     <div id="counter-event-example">
    ' c- z' R% ^$ p9 k
  3.       <p>{{ total }}</p>+ {" k2 j9 Y2 P- I/ p% U8 z. r
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    8 T, g! @# l% p/ F
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    ! I) W! y6 |( {% ]8 M) m
  6.     </div>
    9 P8 c- y) ]; N$ r8 e: C
  7. </div>
    ( o" _, Q3 }) A3 G- y
  8. - T% A  P3 X+ c) ]- l" G
  9. <script>3 g% b8 [- {; A2 `0 m$ ^  X
  10. Vue.component('button-counter', {- t7 c! g0 I2 w* I  A
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    : x# m# ^/ w" x7 O
  12.   data: function () {
    8 ~7 A# l( D$ a* U1 K3 \$ q
  13.     return {( m2 ~. P5 T# M
  14.       counter: 0
      O# d, d6 r  k5 q
  15.     }
    . c! a4 o' }( Y' g
  16.   },7 S- p: E# ~; H# ^% t9 _. |$ l4 \
  17.   methods: {1 e7 n9 v6 ?  N3 J8 W
  18.     incrementHandler: function () {
    : H% o* X. p  s1 X: P# N% E6 J
  19.       this.counter += 1
      x. t. x& r0 H7 G/ p% l/ v
  20.       this.$emit('increment')) S2 d% Z3 G7 w$ U) \' Q' O6 ]
  21.     }
    7 y( p/ V! i2 I, c% H2 ^
  22.   },
    3 X9 ^( v" @( M3 u# k$ C; w
  23. })9 T+ s6 c# y+ Y4 Y  g
  24. new Vue({# ?. w; N& L% H
  25.   el: '#counter-event-example',
    1 S' N; t* c" E; |7 T+ J+ E3 X
  26.   data: {7 ?' J! ~- w$ \
  27.     total: 0: f! d( S2 P' F/ l
  28.   },
    - x, G! k3 t" `, a/ ?
  29.   methods: {
    # U9 {, E! Z6 s) c3 c
  30.     incrementTotal: function () {
      _9 w6 g( o% n2 T
  31.       this.total += 10 @; n7 D/ O$ n2 j
  32.     }
    * Z1 c( w. y: G
  33.   }& E! L( T4 J- a* R3 z( o
  34. })- `+ b6 K' p* f& d  K* `  i
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    % d# {4 S0 K% F. O) G! _1 A6 Y
  2. Vue.component('child', {
    . i, a! i+ N5 e7 H3 O8 z
  3.   // 声明 props5 J) Y/ v6 f; ]. L
  4.   props: ['message'],
    ; E5 m1 O# ~) ]2 U  ]. _
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用6 R8 q5 b& J: E0 _/ p. C/ b7 L
  6.   template: '<span>{{ message }}</span>'9 B) p; y) s) q( Y' c( O% p
  7. })6 {+ u9 E, F; u- {
  8. // 创建根实例
    8 F  E% U, t1 M" F' X# C7 v
  9. new Vue({4 X0 v- r3 v% o% N
  10.   el: '#app',$ K/ r* R* g3 b4 h4 d# P. t, i
  11.   data:{; N  B4 g: Y- [  k$ C6 G2 X6 ^1 _6 d
  12.     message:"hello",* |5 F2 Q; e" Z# \4 A1 z4 [
  13.   }
    7 ?4 h( h( x% M, K4 f
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {0 k" Z/ v3 B7 o; J7 s: q7 Z& B
  2.     incrementHandler: function (v) {8 X% P6 V) O' k8 A2 C
  3.         if(v==1){! p3 j. G5 t: k: E
  4.             this.counter -= 10 [6 |- h( q0 `, W6 @. J5 Z
  5.             this.$emit('increment',[1])0 `) h7 l3 F1 j3 d5 |) e7 b
  6.         }else{
    ( r1 \/ }8 |  S) t2 }
  7.             this.counter += 10 w2 f$ Q) K: g
  8.             this.$emit('increment',[2])
    & y* }8 L# S( F& Y4 s
  9.         }! J5 s* |' h" |
  10.     }
    2 d* ]$ T% r3 y4 B  p
  11. }
复制代码

6 Z! @2 P2 J7 j4 V- Y
( [  a  }9 h' [: C& ?7 K
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-8-4 15:14 , Processed in 0.064794 second(s), 22 queries .

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