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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15366|回复: 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,并使用它:
. E6 t6 R( R. l# K" \
  1. <div id="app">
    . R2 K2 _+ [( s, [6 G" W' x2 ^
  2.     <runoob></runoob>
    7 `/ I3 ~6 u0 W5 O
  3. </div>
    * L. F# |" t( q: t, j
  4. 6 [& B1 z/ o9 E; t6 b7 R
  5. <script>1 Y5 h8 T0 o6 r* H4 v  i; K: r
  6. // 注册% J$ L4 O- d0 v6 V( H- `
  7. Vue.component('runoob', {
    / v$ b- _& G: V+ I
  8.   template: '<h1>自定义组件!</h1>'
    0 R1 j* w7 w( r
  9. })
    . o9 |2 g3 @: p
  10. // 创建根实例
    9 S3 K- r' }2 @6 V: F% D4 X1 q( p
  11. new Vue({8 S* {0 Q7 N5 \* O
  12.   el: '#app'
    $ v# n* e/ X- |
  13. })
    " z5 m! i4 i7 h
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
, S" L9 e8 V6 T
  1. <div id="app">; ~; ~. Z7 I% k2 ]5 {2 Q
  2.     <runoob></runoob>
    % m$ b# J1 R  c! ?, I" C2 n
  3. </div>
    3 R8 [: l3 R- h! t* C

  4. % w: O# F# X8 ^* k* J/ }" `
  5. <script>- Z1 Z" E9 @" [. c2 O& F
  6. var Child = {: p" S2 x) q' F2 n# m- l! U
  7.   template: '<h1>自定义组件!</h1>'4 K1 J2 b( z6 F* D2 ?% C! F5 n+ ~
  8. }" o2 `8 w1 @: z  T

  9. 8 N. A1 t1 D" N- q. y4 \* y! K; e7 b
  10. // 创建根实例; L8 K, a  A; Y( L* Z+ _/ M4 U/ p
  11. new Vue({
    0 Y; G0 Q! O7 }9 v3 \' i+ H- e
  12.   el: '#app',4 ]$ u( z' a4 h) A  H
  13.   components: {
    3 X( ~9 g+ y( P: g3 h. q) i( _% ^
  14.     // <runoob> 将只在父模板可用9 C& a5 W( l$ @) [! [0 v$ {
  15.     'runoob': Child7 E& G8 Y9 V' V. R# F( X0 p  V
  16.   }
    ; Q' p; ]* E4 `6 s/ o
  17. })6 Z) T3 z6 ]) M6 o$ V% x
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例8 D5 b5 g  R2 @, c$ }9 g
  1. <div id="app">& z. C0 T; ]3 [' j! D$ ~9 c; T
  2.     <child message="hello!"></child>
    - X# s0 v3 F4 B9 B2 {
  3. </div>
    9 G9 I* d- G$ b- P

  4. ( l$ N" i$ G; _# F
  5. <script>
    + o0 f1 O2 K9 s
  6. // 注册' K+ G) a& |* X8 T1 a
  7. Vue.component('child', {
    9 F9 Z  i) F8 f  |2 g
  8.   // 声明 props1 Z  Z5 O. {) s, P. s6 ^0 T; y
  9.   props: ['message'],8 d8 _6 j' c1 z9 l
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    / ~! j: u+ G4 |6 ?
  11.   template: '<span>{{ message }}</span>'
    2 m4 ]2 q2 Y; c
  12. })8 ^4 Y8 P# N9 I4 S; ~
  13. // 创建根实例
    , W- x9 s4 e9 n: w( q& P
  14. new Vue({; {1 z9 d- Y6 r& E5 x8 m. j
  15.   el: '#app'2 ^0 J/ W" M+ f" [; Z8 U
  16. })
    5 b- ~) E- _$ P6 ^( m
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例( R! W1 C) K, R5 x& [( i, A
  1. <div id="app">
    ! Q# g0 ^5 N9 ?; G1 a- c
  2.     <div>
    2 A# @0 P. _" w
  3.       <input v-model="parentMsg">
    3 T% h' r; i' K
  4.       <br>3 J! S2 J$ A, i
  5.       <child v-bind:message="parentMsg"></child>
    : i. d+ j6 K( }) L
  6.     </div>
    + \/ E2 _7 k4 D: |0 ]) n% }
  7. </div>+ W. A& @( b0 r3 U- H' r

  8. 9 o5 w. t4 D( \5 N9 d* ]
  9. <script>
    5 {* u, N( }# O1 {% L  |
  10. // 注册9 v3 @. |# K0 f3 c
  11. Vue.component('child', {
    : [2 w( l+ y' a  j, H5 w1 r
  12.   // 声明 props5 M# A) u7 ^0 Z* `0 Y; R
  13.   props: ['message'],
    # C0 U3 o! P5 |: p$ h
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ' a4 s% L9 A" \
  15.   template: '<span>{{ message }}</span>'8 I! L) \3 K3 D  j' L2 y
  16. })* B* n/ O7 o6 N( y
  17. // 创建根实例
    - n2 V5 H) v3 ?+ ?' u
  18. new Vue({+ l2 D6 v) ]! x  R& B6 l- ^
  19.   el: '#app',
    ( o& s$ K! w. e, D. P
  20.   data: {: u5 h$ `8 x" y$ @
  21.     parentMsg: '父组件内容'; Q# d" X8 C( W; S2 E3 X9 J7 G
  22.   }
    7 t$ f( _4 ?) Z8 v% n
  23. })$ ~* h3 K6 b9 ~1 R* v' T
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例- J; L+ ^* ?8 S) p
  1. <div id="app">
      g% |2 z: m; I
  2.     <ol>3 H+ a# ?3 |! }5 Z  D5 m2 V9 W1 l/ A
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    ( b/ l' Y- V3 q1 I* J# k4 {( s
  4.       </ol>/ e9 j& j. A8 s4 T' r  Y
  5. </div>  j% f5 E- R" s8 I7 g+ j# m1 B' i# K
  6. + W4 I* L. q/ |& X/ O& \1 K& Z
  7. <script>
    ! l% |5 a; l3 N. f
  8. Vue.component('todo-item', {2 X, E" D2 p  V( |/ v9 g
  9.   props: ['todo'],) [, [  s& l9 n+ W
  10.   template: '<li>{{ todo.text }}</li>'* L! Q+ e' K$ ?) n; f; x
  11. })
    # c* N) u* X  h, F. s
  12. new Vue({
    9 e4 P7 j& B% P! P
  13.   el: '#app',
    4 \4 G0 Q. W8 R' f( }
  14.   data: {4 W5 |1 g! `' F
  15.     sites: [9 A8 o* s6 ]2 v& C
  16.       { text: 'Runoob' },# {+ O1 e* A+ ?7 }: {
  17.       { text: 'Google' },; _) n# T4 u" w
  18.       { text: 'Taobao' }
    5 |+ ~( L; d+ Z9 D+ G% s* _
  19.     ]4 t* X$ a; z9 p6 w. k1 X
  20.   }: v1 I  |; B* k1 b$ b6 E5 D
  21. })9 ?5 U, ^4 f( d5 i$ S  s1 z4 `
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {' H4 S  t# D/ n
  2.   props: {: i9 d- c' g# O
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)* E% S4 Y$ G! y- V6 T/ a3 m
  4.     propA: Number,
    $ q' H: ]: O* w
  5.     // 多种类型2 h* D1 F4 p+ E; I0 o
  6.     propB: [String, Number],
    2 [5 ^6 B" c( B0 _
  7.     // 必传且是字符串
      v9 N  G& n* l" k5 _8 }
  8.     propC: {3 u( ^+ J5 A* F4 [, ]' ]9 F" d+ u7 }
  9.       type: String,9 r9 ]& I. W$ h
  10.       required: true! q% ^5 M  {/ v8 n1 o! V" r2 W
  11.     },9 F7 J; g6 ?9 K! P" ^/ S) a8 y
  12.     // 数字,有默认值6 P5 |; A! A. H0 Q2 S6 Q) j
  13.     propD: {
    & y0 q* Q7 X' o0 F0 n
  14.       type: Number,# R4 E5 m! \* V: y6 S! P: Q$ u. V
  15.       default: 100
    ! g+ s# ]3 w4 a/ {8 b! L! ?
  16.     },
    , M+ X7 u, C( ^  d4 k7 Y
  17.     // 数组/对象的默认值应当由一个工厂函数返回. R4 g: a& @0 C) f
  18.     propE: {2 s! m& x2 O7 [' U# c8 G
  19.       type: Object,
    0 v% M4 }8 r% {( b
  20.       default: function () {; N, [' d& G% {9 O2 g6 i
  21.         return { message: 'hello' }
    0 v6 w1 }/ a0 k# @4 d
  22.       }7 w2 r* Z3 X3 C5 B& j4 z" h/ m. o9 v
  23.     },9 x* c0 v3 t: }! U$ G3 x  x* f
  24.     // 自定义验证函数! a) B* E' s7 W! i! y) n8 J
  25.     propF: {. i- ]7 y% l$ d7 [
  26.       validator: function (value) {
    . m& ]! A; i7 V# i
  27.         return value > 10
    + o& Q1 V, M# p3 u( }
  28.       }
    4 Y6 O# q; [4 i: F$ G& A/ m) }
  29.     }) j; ^' i1 L" P5 c/ z. P' e, K
  30.   }
    6 p$ k& t9 V/ Q6 y9 W( ]/ F
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    , p8 M% ?3 _7 S5 i- F" d
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    1 s9 X' X- X$ T, ~# H3 z
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
8 O& k3 m3 g/ i( F3 l' D/ x
  1. <div id="app">) V6 H- o6 n/ X0 W9 q$ q0 S
  2.     <div id="counter-event-example">
    ( c: N0 I5 K: J- g) O# @# P
  3.       <p>{{ total }}</p>- l! q* c: C5 K
  4.       <button-counter v-on:increment="incrementTotal"></button-counter># [2 q" X! z4 c$ i1 F0 H9 f7 E
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>" @2 d* e5 X0 [$ o& |- A0 {3 F/ x1 l
  6.     </div>
    * c8 R1 ]" W' a  [1 j( o
  7. </div>' A) D' N: @& z( A  V

  8. & ~5 d  r' ~1 s% E
  9. <script>! r) [* b' `4 _" V
  10. Vue.component('button-counter', {7 q, u9 I9 O& L! J/ X$ z! |3 F' m
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',. O1 x8 J, e" F, D! }) M
  12.   data: function () {: k1 U: H6 y$ x' m
  13.     return {. K/ J3 l  l/ z9 \. W
  14.       counter: 0
    ' G) r* A) Y1 `' e2 e
  15.     }2 ~3 C! m, ~; T, \: w" K
  16.   },
    " x  B, k5 `) V
  17.   methods: {3 @( E  m# L5 U7 m* S- }- f6 `
  18.     incrementHandler: function () {' S. A/ W) Z" P! x8 l* P! c
  19.       this.counter += 1- d5 E9 W' H7 \+ H! d, q, O! j
  20.       this.$emit('increment')
    . j! _; U& W8 E' Q. `6 R& H9 N5 e
  21.     }* y; ^6 m9 Z* M0 ?5 b, X$ X
  22.   },
    8 s3 C! L: ^* V) P+ C
  23. })
    / `" r' s2 F: e* Y0 G3 a1 b
  24. new Vue({
    0 u  M1 r$ ?! a5 _8 p
  25.   el: '#counter-event-example',
    * o# `' e! R: C% m) \; T
  26.   data: {
    6 a8 w! S& X! P, I
  27.     total: 0
    ) f2 n6 [; G: u6 ?( d* d: ^
  28.   },
    # k- ^7 a' a( g: d8 }1 b, a8 D5 O
  29.   methods: {) e5 Y3 v6 v& _1 o' Y8 e  W# l( p* I; l
  30.     incrementTotal: function () {% N7 c) W1 P* Z# N# E- l. n
  31.       this.total += 13 ?% l8 U0 q( s# K+ s
  32.     }
    5 q1 Y0 [. E% D
  33.   }
    8 W& \# {: k. t) q. Q
  34. })
    7 J+ `8 q. w; q* B
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    - Y2 _2 P; R* Q1 _* ?5 r1 M
  2. Vue.component('child', {7 R; V. d8 m" {+ l
  3.   // 声明 props
    6 O; A$ W. }; Q$ G( c' U
  4.   props: ['message'],
    5 G4 m, M. z& I2 _/ S
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    2 \( M1 y5 a: P7 c
  6.   template: '<span>{{ message }}</span>'
    4 {2 I' q/ E% }1 e& c
  7. })
    8 k" @% y. ~& E
  8. // 创建根实例
    ) ^+ s8 U+ B' g/ r
  9. new Vue({
    # l$ k9 t  e- Q9 k
  10.   el: '#app',, Q' F9 V0 ], ?3 |$ h, a2 o
  11.   data:{
    , h/ g( s4 _- F9 ?- H7 I
  12.     message:"hello",
    2 I; b# p7 \1 J! }0 _8 @
  13.   }# F, R- F+ f) B4 j1 G; [, ~$ `
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {- ~3 g: A" ?6 l- H3 U. w% B
  2.     incrementHandler: function (v) {
    . Q9 I( p) o3 A8 k
  3.         if(v==1){
    - f$ K! Y  h" C* @
  4.             this.counter -= 1
    * H! {, T0 }) ^! p' [- ^2 g4 }
  5.             this.$emit('increment',[1])& G* H' ~6 S* |0 H
  6.         }else{, B! X" |7 K- L; F
  7.             this.counter += 10 w2 N( r- m- j8 R% ^
  8.             this.$emit('increment',[2])# B0 c8 j7 u- V' }
  9.         }
    & I) \: n# E/ z$ N' {
  10.     }
    . l/ z! ^+ V# m6 P, I% `
  11. }
复制代码

/ L2 {$ B( m# o- ?
+ k# J8 |9 ?$ t4 E6 ]) v( Q1 O
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-17 18:22 , Processed in 0.061515 second(s), 22 queries .

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