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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

$ u+ v9 p* M! T8 B& G
  1. <div id="app">
    + y# `" G: }+ y. P3 p8 J9 j7 M
  2.     <runoob></runoob>
    " a* Q8 a; z: ]1 n
  3. </div>
    4 y0 u" e% o5 P" w& p8 D, u

  4. . \! S  I1 f( V: c5 Z; I7 k" ]
  5. <script>% ]* v/ H. a, Z0 ~0 [2 ]
  6. // 注册
    8 o3 M2 K" H( f
  7. Vue.component('runoob', {
    ( M" f$ ^, N/ s$ C2 L( [! M2 J
  8.   template: '<h1>自定义组件!</h1>'  k7 ?7 ]8 k2 d* G& ]" M
  9. })( {) I9 X1 A0 A1 d+ w& c
  10. // 创建根实例7 w  f& U6 a3 c. C1 F( C; F9 b
  11. new Vue({6 l* W$ G- D) T" t, r. q" ]
  12.   el: '#app'
    2 T% x  _: H2 n: t- l* t0 s8 c
  13. })
    6 _8 Z/ j+ m3 q8 g
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

6 l7 Y. t1 M) O
  1. <div id="app">2 t  {+ n8 @) S% t( V( ^' V9 v
  2.     <runoob></runoob>
    7 p# W6 n9 {0 d" `; v6 z' o$ ]  p
  3. </div>
    3 j( A" S# Y+ G1 P; M, z" i- d
  4. 9 S% h  Q' R7 m' t& m) h0 ?
  5. <script>. |7 Q* G/ i: h2 G6 J
  6. var Child = {
    + Z! `) v: x0 _9 e' c# w
  7.   template: '<h1>自定义组件!</h1>'
    % p4 v* A! O8 b( S  K8 M
  8. }5 d0 p+ W9 g' ?" B5 _
  9. + w( i  h" |6 W$ `2 N# c
  10. // 创建根实例
    8 ^% v( X# H  `& \$ b
  11. new Vue({
    % q/ O5 b3 g+ o6 _) |: P
  12.   el: '#app',  r5 ]" d# d# ?1 O! E, Y9 v
  13.   components: {" y" |6 h% Z* L, p
  14.     // <runoob> 将只在父模板可用5 F3 W) T2 P0 d$ P
  15.     'runoob': Child
    8 k7 r" d1 G. d
  16.   }
    0 ]8 q5 j) V6 P8 R% W$ D" E' W
  17. })$ [3 ~4 n1 \7 Z) S$ @/ U3 r6 p0 |: E
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
* X/ t  H) m0 B( U
  1. <div id="app">; j7 b4 D' \( a  p5 J5 k8 g
  2.     <child message="hello!"></child>
    * ?# z1 L8 @* |9 k2 i/ U3 J
  3. </div>
    $ ]' g8 \. u; I

  4. 0 X, L2 i7 W) h  I) [( U$ }
  5. <script>
    7 W  |( E; I5 Z
  6. // 注册
    7 Y) V5 k4 O% l; O9 G/ d
  7. Vue.component('child', {
    2 F7 ?1 q. H3 o" \+ f+ D
  8.   // 声明 props) x7 K" h1 T: E9 _" @3 s" ~/ _) L
  9.   props: ['message'],
    : ^* T3 ?8 I0 L; G* G7 f; d
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    : W2 a' b7 G' a0 |7 y
  11.   template: '<span>{{ message }}</span>'' ^/ G0 Y$ ?- H: G! p" h' R
  12. })/ O# P: d" O! n1 p3 J7 \( `  Z' |$ o
  13. // 创建根实例
    % h; k' \6 A3 T& J- ?7 u4 c
  14. new Vue({/ ]( h. O5 _( `3 J  `
  15.   el: '#app'. f3 T8 X3 [0 P. R  B
  16. })
    - X, `. @& R3 k, ]
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
% y8 M5 i* x1 B+ V9 i" A; L
  1. <div id="app">; g9 I1 t. g& T8 F# Y
  2.     <div>
    5 m$ O6 D3 y* B* {
  3.       <input v-model="parentMsg">
      i) f" n8 @( k& O9 i  }
  4.       <br>  Z2 g: Q& E2 Y
  5.       <child v-bind:message="parentMsg"></child>
    " o8 i, D' c- `* M" j
  6.     </div>! b. S. N6 E8 B0 z' W: o8 v1 D
  7. </div>
    ' ^1 h1 ^: E1 n& Y# B
  8. 0 h" ?+ ]6 N  R& p
  9. <script>
    ! S+ P% p/ `1 h5 E3 H! ^  H' e
  10. // 注册
    . q6 i% ]- c0 G& L
  11. Vue.component('child', {4 ~+ I# K" e* x, Y) Z3 B9 g# v
  12.   // 声明 props3 f2 \1 ]. ]& u+ j9 Q$ K  @
  13.   props: ['message'],' d, ~* a/ C, t1 ?9 V5 _- ]0 H
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    6 _8 n; l: O" S
  15.   template: '<span>{{ message }}</span>'
    6 x& n, E) M" j1 D
  16. })
    7 `- P, A, \% d& M* Z+ b5 f
  17. // 创建根实例: S2 K6 r8 r" ^
  18. new Vue({7 |0 r. L2 N$ r4 _" ~8 s: ?* P- a
  19.   el: '#app',
    4 U' R/ D; x0 }8 }
  20.   data: {
    : b7 n! x# O1 S( ^% X
  21.     parentMsg: '父组件内容'7 d4 E3 P+ {5 s3 T- V+ [' D: I" @4 Z
  22.   }* T  R! P$ ^9 [; I1 m9 D
  23. })2 v& \; C$ a4 W+ y; a% M: i7 z
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
0 W' K. u9 C# F4 {
  1. <div id="app">
    2 M0 D; L- t/ @
  2.     <ol>
    % _4 g  z  ~' K
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    # R& F" n$ y# k3 k0 |6 a
  4.       </ol>
    7 V! f; U6 _7 k2 c
  5. </div>
    - o5 S. R* r# F& r/ d* N

  6. & M1 p2 U- Z; Q4 R9 W
  7. <script>
      c; b, g% ]1 Y; C. @$ w6 W
  8. Vue.component('todo-item', {0 T$ G1 F  @. x; i& ]0 H; c
  9.   props: ['todo'],
    # j4 s, {. b0 U1 @4 G3 X
  10.   template: '<li>{{ todo.text }}</li>'4 }7 l# X3 u- n3 ~  [( ]
  11. })
    - G! u3 @' o4 b
  12. new Vue({
    & |  X/ |* C: A" U) Q
  13.   el: '#app',- v- f9 C( U' r7 x5 g
  14.   data: {$ j0 T) O+ K" M" k+ Q
  15.     sites: [
    9 k2 M- D+ d2 ^, A2 Q9 @  c
  16.       { text: 'Runoob' },: D+ k" `' v& t
  17.       { text: 'Google' },2 r# M3 ^7 ~0 f6 D
  18.       { text: 'Taobao' }
    ; f( |% r" q! e! A) t. r; y
  19.     ]
    # E6 `9 m$ h* E0 T  ]2 ~& ?; Z3 P
  20.   }
    ' M- ?, v, k# W4 Q- K8 y/ p
  21. })2 A' Z* [# R( u" M9 G* H2 W
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    8 q- s: W, b2 P7 H$ R
  2.   props: {
    5 |4 f9 X6 e) L- f6 \2 l: e
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    3 K+ j1 v" @* `* M' [6 a
  4.     propA: Number,
    4 F9 @% V- z- E+ Q  W
  5.     // 多种类型
    5 Y1 @6 t/ `& l9 d# n0 E
  6.     propB: [String, Number],7 a$ A; n' o/ }4 K0 J  m
  7.     // 必传且是字符串6 e, Y* I3 F0 t6 Y8 [
  8.     propC: {
    2 p- N' a( D# s  B4 y. F
  9.       type: String,. Y" b! Z& t4 b3 a
  10.       required: true
    5 j* n2 W6 G6 V
  11.     },8 ^. v& K0 D+ d
  12.     // 数字,有默认值! B# ~# S8 m( Y) Q: i/ P$ e
  13.     propD: {
    9 s" M# P$ D* k
  14.       type: Number,3 y3 r. ^1 R4 k
  15.       default: 1002 j6 z. B( D+ `
  16.     },8 s. b9 ^# _. T# \3 j
  17.     // 数组/对象的默认值应当由一个工厂函数返回/ ^% W' B: [: g1 q! c% \3 n
  18.     propE: {
    : G# \* ]0 Z6 k2 i
  19.       type: Object,& T5 t0 O, ~/ ^# G# T
  20.       default: function () {
    & H5 ?6 {. j( s; K) _
  21.         return { message: 'hello' }2 R. M& l, |5 V3 F7 T
  22.       }# c$ H& `7 v5 {1 S5 y# j
  23.     },
    5 \  c* p! i) x3 R2 I+ g
  24.     // 自定义验证函数
      N0 I+ e! y# f4 c
  25.     propF: {
    8 x7 X/ N0 h# ^7 Q1 H; ~# `4 l
  26.       validator: function (value) {5 {. a- a) h! Q6 O
  27.         return value > 10, S4 w" D" r* C! o$ a3 B8 H) x9 ]
  28.       }& r, J9 D0 u9 s4 C: }; D4 c- O1 `) l, B8 @
  29.     }
    : ?. j, d5 j; {3 {6 A/ @9 ~& ~
  30.   }+ d1 x; ]5 e/ a( Q( u! i5 I( b- Z
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    ; V6 g8 z' N" H! C) g% t  U+ s8 v1 w
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件- o6 x9 i# X! {% O9 S
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例4 E7 X; v! U: [2 ?6 K
  1. <div id="app">( r- `3 F1 s0 R. a3 I- V0 T% y
  2.     <div id="counter-event-example">
    + }4 L( O# ~. c$ P! C
  3.       <p>{{ total }}</p>
    - q7 ?  L) f9 ?
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    + o: b% v* d3 j  b$ j, G5 `
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    $ _- }0 S  b" l' Z0 S
  6.     </div>
    8 m# c$ W4 k% C+ d
  7. </div>) p8 [# [* ~  q. D& ]6 b
  8. * T" D& S$ n5 B$ j( J- H
  9. <script>+ \- T; S' _$ J6 W8 y+ N
  10. Vue.component('button-counter', {. h& q, D7 g0 S" t1 r# v' C" i
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    - q4 g2 Z' {, Q: o
  12.   data: function () {
    / ^; p7 `, @0 |2 q6 A' n+ L/ {
  13.     return {# c* ~: k9 c8 a% i. ~% O; O
  14.       counter: 0  w8 f0 U. Q* W) ^& {
  15.     }5 \0 T) m- i: F$ {
  16.   },
    ! A. a+ t5 O* M' |
  17.   methods: {9 {1 y2 Q% ]( F
  18.     incrementHandler: function () {
    + B$ a# W2 L" A
  19.       this.counter += 1& T, v2 Y, j# b
  20.       this.$emit('increment')- {1 ~2 A+ Q3 f4 w/ r# O3 l3 c
  21.     }
    + y  `$ P7 P6 X" @& x% ?/ U
  22.   },! H3 `$ k% R6 j, c: P" T) j
  23. })$ r3 `% C; A8 z$ G
  24. new Vue({( ~- v+ z5 P9 e5 l# N- _* g2 F
  25.   el: '#counter-event-example',/ h3 Y: j3 }; C6 l' x
  26.   data: {4 L  ~$ Z- `1 v7 ~" D
  27.     total: 0
    % t4 Q; k' b. u; h. n
  28.   },
    2 k" p+ J( X4 Z' r, b, \' B
  29.   methods: {- l0 L- {: X; }8 A$ k- r$ ^) A* U
  30.     incrementTotal: function () {& ^- V1 L. [4 k, c0 C
  31.       this.total += 1* L& f# {0 ?# E" Y2 g
  32.     }, H  }& [' X4 O0 s
  33.   }
    4 o$ c' A3 u* k5 @7 r0 E' R, |- G
  34. })7 Z, z1 w( Y3 d1 j7 k- u  q, W
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册5 @7 Q3 C/ e. y0 a
  2. Vue.component('child', {( h$ J" Y; Q7 R0 Q. q6 l# L$ j0 k
  3.   // 声明 props/ c0 O/ [0 \* P# q, V9 b5 X! o/ Z
  4.   props: ['message'],4 I, s' {  G2 A( Y% M9 x! k
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用! N. Q% u6 j( e7 |+ n
  6.   template: '<span>{{ message }}</span>'
    ) X* u6 @4 w' L2 d
  7. }); a# y: N, F' W+ P. z
  8. // 创建根实例. a9 `4 V: z9 _1 c+ ^
  9. new Vue({4 f1 N- K$ n7 a1 j& T* B* }' [
  10.   el: '#app',
    , Y& M: M1 O0 t$ x$ z/ o: z
  11.   data:{
    4 y2 ~2 C4 Q2 Y' B0 J3 {: |. M/ r
  12.     message:"hello",
    / X/ n' w% e/ e9 h  t1 Z
  13.   }
    8 H& u* O- V0 a% V( P4 X" N# K% Y
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {% T! z* V. J! M: Y5 }
  2.     incrementHandler: function (v) {
    2 e, J3 f2 I' x
  3.         if(v==1){/ T% q/ ]: T' }# _3 ]
  4.             this.counter -= 1% H6 n! U8 N/ a4 B9 @
  5.             this.$emit('increment',[1])
    ; B, ~; j3 l4 F( a$ d% o
  6.         }else{
    ) M" ]7 S& z# @8 @  Q( s* q: i
  7.             this.counter += 1
    ' J) ?$ j. n2 l# v! V
  8.             this.$emit('increment',[2])5 Z# G4 x4 t6 B
  9.         }$ E$ ~- k. K0 `. p$ i( I
  10.     }
    8 }6 V& ~* `4 }' M* [
  11. }
复制代码
) J0 H5 A9 d% {$ @4 S

/ t% M, H1 [4 S0 n3 e2 f/ J5 W
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 11:37 , Processed in 0.058136 second(s), 22 queries .

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