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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15839|回复: 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,并使用它:
  L2 \0 g* ?/ i# Q1 \5 M5 A
  1. <div id="app">
    $ g3 {6 M9 {' f0 X$ r7 c9 o
  2.     <runoob></runoob>: l8 q& B4 g. I& g8 y6 |
  3. </div>
    ( v% T2 t6 d1 t0 e

  4. , ?; J/ E! P5 S
  5. <script>
    , S- K' W4 T9 Z) D3 R
  6. // 注册
    $ ^% z7 Y4 z; t1 T  c
  7. Vue.component('runoob', {' A  N8 N& R. J; i: `; S/ q$ \* c
  8.   template: '<h1>自定义组件!</h1>'4 Z. [1 ^* e+ c$ S
  9. })
    & n) h7 P& W2 x- C  {. u& v. S
  10. // 创建根实例1 ]# w4 ?8 F6 _1 F9 i5 h
  11. new Vue({# V# j5 v, U- X0 U  }& N) u
  12.   el: '#app'7 j/ B7 R9 i% u: w/ l. K9 I* y
  13. }). @8 k# f/ n1 S# B' l. F0 q
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
' m% w2 c# R( S' {) z+ V
  1. <div id="app">
    9 h9 K3 Z# X' O( q5 t
  2.     <runoob></runoob>
    6 ]- g7 d- x9 h& J8 N8 G
  3. </div>* @9 J) _. b/ H6 b+ L

  4. ( {  w0 P$ h; h- P! @8 X7 f
  5. <script>; P2 a+ s. _7 a( l* E  N
  6. var Child = {6 V0 m# I# i0 q- A2 O+ w5 x
  7.   template: '<h1>自定义组件!</h1>'
    7 `/ V+ l( d1 _$ C! E0 t
  8. }2 P1 q7 @1 r* N5 R
  9. 2 N+ G1 c4 C* O; J  e
  10. // 创建根实例0 y4 I7 U0 w9 g: S
  11. new Vue({0 \2 v) g2 W) H, l6 @( I! ^( ^
  12.   el: '#app',1 H/ ~0 V: R  ?7 I$ o1 D
  13.   components: {& J; s! h6 f# N; L6 D0 E) L' O
  14.     // <runoob> 将只在父模板可用
    - w/ k9 Y$ `& o9 T
  15.     'runoob': Child
    # ]* b+ z# P: v( s/ v, ]
  16.   }
    0 h4 w/ J! D' f- u1 U( Y
  17. })
    ! h3 x5 a4 J  a: P6 K4 E2 @4 [
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
1 i; H2 t' @% }  l6 {% l
  1. <div id="app">* x$ x. s2 S( t
  2.     <child message="hello!"></child>
    ) D. o- Q* X! d5 I" {4 Y- k5 C
  3. </div>! c& c  X7 g' N6 a/ C' Z4 y: e) a
  4. ; \) {: E2 A( u; n! Z5 v" e
  5. <script>: Q7 @9 I. ~3 Q; z( |% A6 L6 c0 E
  6. // 注册
    2 m+ ~& ]0 D% t  Q( a
  7. Vue.component('child', {
    * Z& J, U3 i9 `' Z
  8.   // 声明 props
    5 ^& N  m/ o& D3 _1 u: E
  9.   props: ['message'],# u. Q4 E+ J# k1 w
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ( }0 Z; h8 K& k% a4 z( }$ ?3 a# E
  11.   template: '<span>{{ message }}</span>'2 I0 A( ^% p  G, [% G" G2 x7 v
  12. })
    , F$ G6 b6 Q& Y  a3 c, N4 F& L  p
  13. // 创建根实例; i; w/ K4 ]/ @. W' V! l! h9 N
  14. new Vue({
    : f& }. d5 `' R# B" ^: i$ K
  15.   el: '#app'+ Z4 Q& X6 A9 m( F  c& M2 \
  16. })
      P1 u& M5 j4 ~9 U7 _$ |( s
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
) }* v! K2 [) g, `0 |, R- m; f
  1. <div id="app">, J# P9 y8 d# _
  2.     <div>* H  @! x  w. N/ B1 F
  3.       <input v-model="parentMsg">8 x. {+ F4 k8 I( ~; ?# [) s( F
  4.       <br>; s, Q) @4 k9 @4 T3 g
  5.       <child v-bind:message="parentMsg"></child>& M2 i9 S/ a6 L! }
  6.     </div>4 ^% D) H8 }$ N# L
  7. </div>
    " b) ^% Y5 ]# {* B% [& W

  8. ) n( i) {8 ~+ }/ a
  9. <script>1 ?5 G( N2 }" h1 F& @
  10. // 注册
    " {& B/ }. v% n& m/ ]
  11. Vue.component('child', {& r2 k# {9 P2 A# V: T" P' h* z- ^
  12.   // 声明 props
    . f5 t, l* Q9 N$ j- z
  13.   props: ['message'],
    * a7 A) Y7 t1 ?
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    & g0 t5 y$ h  m9 W: Y+ v2 ]" f$ d
  15.   template: '<span>{{ message }}</span>'8 y$ O6 A& ?4 v
  16. })
    ! q" R8 A# D5 S% E
  17. // 创建根实例' C6 y8 J4 w+ d) d9 a! Q
  18. new Vue({
    " H, w( U; w$ {
  19.   el: '#app',; \; s1 L( ]3 u3 r8 w' B
  20.   data: {5 C4 [( T; S! G7 N. @2 i
  21.     parentMsg: '父组件内容'
    % s  x' q( }) b
  22.   }! p. d$ j) O' P6 h
  23. })" _5 v# y$ v2 f0 ]2 s
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
4 c, V+ ^) g; g0 t% N
  1. <div id="app">
    ) Q! g, P2 M2 ~8 d" x" c
  2.     <ol>
    3 P' N, _  D5 b7 G( l
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>% ?; D& A4 L* m" w- l
  4.       </ol>0 t, I5 W7 p" j1 f( [& X% o
  5. </div>! f5 m5 K: }+ D5 V7 ^+ F
  6. 9 ?% j/ v1 _( [5 Q) V- u! x
  7. <script>
    4 e( H. e: A+ [
  8. Vue.component('todo-item', {3 q/ \6 o5 g% }  Y, P
  9.   props: ['todo'],2 v  N' j1 u; ]( }7 f7 @) e8 H
  10.   template: '<li>{{ todo.text }}</li>'" [: X+ i: r2 U# [
  11. })
    4 s# n: y5 ^' k9 b
  12. new Vue({
    4 ~. @/ @: e. h. F* j! H
  13.   el: '#app',8 c5 }8 e& f3 d% I2 D# B
  14.   data: {& s6 J. b0 n6 g  r! N# L' I( E
  15.     sites: [8 e1 t# w, u/ X1 b! {( d
  16.       { text: 'Runoob' },
    # A0 Y4 R% u2 o* I
  17.       { text: 'Google' },! k; M0 y! k$ g% U& u! x  U
  18.       { text: 'Taobao' }
    / M6 T' z# n4 v2 O& ?
  19.     ]
    % }% |# [7 x# S
  20.   }* ^9 ~' y- ^5 {+ p) g" n; u
  21. })9 u8 ~7 }, A0 c8 C
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    4 p3 C) D8 r, W$ W: }0 o
  2.   props: {
    ; v* D8 a& u0 g- g% }' k4 x6 Y
  3.     // 基础类型检测 (`null` 意思是任何类型都可以); L* `) p  z* B- K; M2 x
  4.     propA: Number,
    3 V* {7 f' c) M2 V
  5.     // 多种类型% F& U+ n4 R1 A. m, @  @6 E
  6.     propB: [String, Number],
    5 {* L9 x6 O7 ~8 n3 }: `: N
  7.     // 必传且是字符串
    - D6 Z  f" S0 u$ V- z
  8.     propC: {# L& z  `  i! k! S- S( e/ X
  9.       type: String,+ {, B2 h, D; n, p# W7 p1 K; k2 r
  10.       required: true( c8 c% p4 |6 v8 x/ d( c' \  {
  11.     },% a5 T; ]% l; w. y3 C
  12.     // 数字,有默认值
    1 e! x8 Y9 g- p+ P! Q! n
  13.     propD: {
    1 M  A; S( q2 c# Z
  14.       type: Number,5 q8 F1 H; r2 {5 t* R
  15.       default: 100
    3 L% ^8 {( [- R1 P5 n  F
  16.     },
    % X! I9 W5 J" ]* C4 k, ?) p
  17.     // 数组/对象的默认值应当由一个工厂函数返回5 Y, x- X, S; O  S* ~& a
  18.     propE: {6 Y; O0 M# [7 d' p( u
  19.       type: Object,& j! K  t: n1 v4 a
  20.       default: function () {
    6 c4 C2 a. z! s3 w, g& S
  21.         return { message: 'hello' }  E3 n) C! y- p$ G/ Q" p
  22.       }
    # f2 Z# O% X- l, L
  23.     },3 W4 ~. u# s" T6 C, {" f
  24.     // 自定义验证函数0 O* O' b6 _# O0 L. \* G
  25.     propF: {
    % p1 B" Y' y+ q( q& C- Q
  26.       validator: function (value) {' |" h* O. Q5 ]# e! E8 p
  27.         return value > 10
    + r6 r2 r5 W- L4 m3 B
  28.       }
    7 E* M& M$ d6 h! H
  29.     }  P: r# ]: H- L; \
  30.   }; ~0 ]  G8 j( e  v# x/ Q3 q
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array' |5 m! O; b) n) k$ Z
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件, f9 z3 t- }  C* Y5 x+ S
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例1 ^+ Z2 h* l+ ?* \' J" q( E
  1. <div id="app">
    , Q) M# `% w5 x/ |* S
  2.     <div id="counter-event-example">, A: s  I: z3 l/ W) a+ z
  3.       <p>{{ total }}</p># C6 Q: \( f3 i* [2 o9 C6 J( G
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    . H# U( M7 W- X; m5 ?( S0 }
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
      g4 C: K/ {7 d* k/ w/ X
  6.     </div>- M7 J5 z: C: e- R) @0 ?5 `* J
  7. </div>
    & ~) D# T: C! R" m
  8. : M' r  ~) r' O, J# r  ~% n
  9. <script>
    $ L6 L* T9 b. s+ Z3 D! V: N! l& N: s: g
  10. Vue.component('button-counter', {  F, G% s! |6 l5 I0 k
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',! I$ l; O6 b& l& D- |0 G5 {  o
  12.   data: function () {6 ~" k* H/ N0 e% X! m  x
  13.     return {
      e8 R$ r2 K$ ^
  14.       counter: 0: ^" M4 N5 ]( p" ?% w2 g$ t
  15.     }5 u% v1 |4 d& E* @
  16.   },1 [) U/ _7 |- _( F) ]
  17.   methods: {
    - S# @* M# K) ~- n% }* l( L  H' D7 t! K
  18.     incrementHandler: function () {
    4 u$ t% T# n( X4 D/ ^
  19.       this.counter += 1( C# `0 H8 E; e; I. s
  20.       this.$emit('increment')6 @9 D# K5 t# @* ]5 T5 Z2 U: l1 T
  21.     }3 h  P: `$ t# v/ P" J
  22.   },) E3 ]4 a3 G8 D- K! x
  23. })
    ! n) C( S( ?% Z+ _
  24. new Vue({
    ( T3 n0 F  v& C. t
  25.   el: '#counter-event-example',. H- Y, d2 x2 ?1 L  c7 x
  26.   data: {: U+ f! Y7 T' x' L
  27.     total: 0
    / _' ]6 I8 F5 t# c8 m. H! w
  28.   },! \. |  E, o5 a) B8 {( J
  29.   methods: {
    ) _# t# Y+ B5 p. D+ F' `4 y
  30.     incrementTotal: function () {
    ( x% m  S0 h  Z' l2 z- s' ~" w
  31.       this.total += 1! u/ V- y# H- N9 L, [# B- R
  32.     }
    3 ~- u3 _: c( v  p# F% q
  33.   }, A( d( @) Q! z
  34. })& |9 |6 q$ N8 |
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    2 z. K7 H& h; H$ I9 Q/ O& u% c9 H. |+ t
  2. Vue.component('child', {- |; K: l/ w$ j; U; K5 z5 Z* m
  3.   // 声明 props& j- Y$ K( k& ~3 @' u4 V( a' r, g
  4.   props: ['message'],; N! N$ i6 T: e* f# Q# k, K7 b$ \
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
      Z8 \) E# M! g7 {8 L) u% a
  6.   template: '<span>{{ message }}</span>'
    * _8 [3 }5 e6 W" ^" F( @! G8 l
  7. })' Y, D- h) ~) @
  8. // 创建根实例
    / a( Y# z; C* m
  9. new Vue({
    0 [( X5 t0 I/ j- z  V1 @. m1 D& v
  10.   el: '#app',
    ( C, K7 c0 U% J& L/ E5 F0 A
  11.   data:{# a' e+ u, s1 i
  12.     message:"hello",
    : Y& m  d  m* r' l: j- ~3 ^  ]
  13.   }
    4 _: Q7 A8 W; Z! }4 Q( P
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {- R' X2 |' T) [7 ?& a" f
  2.     incrementHandler: function (v) {
    ; O7 k; y2 N8 i  I: `4 s$ T
  3.         if(v==1){3 P5 a6 ?' r/ k) \' v" v9 ^1 r' h
  4.             this.counter -= 1
    ! a' I: }* X# Y. L4 a
  5.             this.$emit('increment',[1])
    1 J1 w$ z9 Z- {4 {9 U
  6.         }else{
    " _# y! z5 a! `+ I- K
  7.             this.counter += 1
    3 b0 R3 k( z2 [# w- R0 U
  8.             this.$emit('increment',[2])/ X8 F6 f/ B0 @7 P* Z# q/ |9 {
  9.         }
    ! k* F" R3 V+ F% i2 F
  10.     }, R1 S, [8 Q( }! N
  11. }
复制代码

6 `7 S0 q/ L+ z8 P" T0 ?) Q9 J6 {# S" Y
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-20 05:39 , Processed in 0.070609 second(s), 25 queries .

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