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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 11099|回复: 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,并使用它:
; r& u9 @* [" k+ f$ J4 T
  1. <div id="app">/ N# M7 F1 b4 Y/ u# f& g
  2.     <runoob></runoob>; H) V8 I, \( M' E; q; S
  3. </div>
    # I6 D0 `5 j, B1 A1 t* {1 l

  4. 9 j5 S% R2 k5 T  ?) h$ ^
  5. <script>
    " A8 o* E" h- b# g: e3 Y
  6. // 注册
    4 t& L" }: L$ r  [7 u" h
  7. Vue.component('runoob', {  X, ~1 n2 _- s, u
  8.   template: '<h1>自定义组件!</h1>'% s& Y; J% T  C/ a
  9. })
      y* U/ W4 f2 V3 Z" q/ U' p
  10. // 创建根实例, q& a" i: g7 K$ N- r3 C% Z5 ~
  11. new Vue({1 s  G+ K; M, N; @0 u' P
  12.   el: '#app'. n6 N2 X4 o2 s1 U, K
  13. })
    6 W4 ^$ m( y/ I( V# I! I2 x
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
8 `7 }, q+ I2 |; ]
  1. <div id="app">6 T8 b' Q5 h  G. g; o  m4 V* L3 ?7 H" T
  2.     <runoob></runoob>
    ! h5 w# g( Y& z* T; B  M0 X0 Q
  3. </div>8 Z9 v6 g, m- |7 S- J

  4. * W: y, d" _- K! J, t
  5. <script>" X) ]) P( Z' C5 h
  6. var Child = {
    " {+ X3 q4 p8 e
  7.   template: '<h1>自定义组件!</h1>'
    8 i  }! p" k% c7 {) W7 Q$ Q6 h
  8. }* Z" c' v* E( z9 `3 Y

  9. ! V: e: i  Z4 A* k# N
  10. // 创建根实例/ T5 v" P& `- z6 W' W
  11. new Vue({
    & U" F3 K( r- i5 \" s' F- V
  12.   el: '#app',+ R+ h% \5 \! X. f6 g6 ?3 h2 T2 K
  13.   components: {
    : D1 u% s( O# J1 G6 N6 {% j
  14.     // <runoob> 将只在父模板可用+ r6 z. h) x) h, ~- G: w
  15.     'runoob': Child* C% U( D! N% X+ E/ _# g
  16.   }' W6 q* ]" Z& e
  17. })! P* |3 B- V0 k4 n
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例1 b4 z' x5 {/ d- o3 B' W( `
  1. <div id="app">6 R8 ~- ]0 {5 M# i- U( B$ D
  2.     <child message="hello!"></child>
    1 q- T* [( q; D
  3. </div>+ f* ~, z; g( i9 z+ b" p

  4. 3 c9 q$ h. H/ H5 J: ~
  5. <script>1 T8 {" ~5 J% b! N9 s
  6. // 注册+ x* `5 E' L, X2 [" T
  7. Vue.component('child', {
    * G- W; D! d4 J/ |8 j5 p2 h
  8.   // 声明 props" {: q0 q( E8 [" v# r- Q! v
  9.   props: ['message'],
    8 M6 i9 W4 t9 d9 Y( Y
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    4 J5 O' }( ~% T3 G' p1 R7 y
  11.   template: '<span>{{ message }}</span>'8 a5 {  J0 {" B: d$ E1 G
  12. })9 H& n6 ^* v& v1 y
  13. // 创建根实例
    5 j$ R' \, O8 c5 b( n+ n
  14. new Vue({# `2 q/ I! t& C0 ~8 s
  15.   el: '#app'
    * k7 a! \/ }  b1 W
  16. })* k3 ^: ^, a. T" @$ L% y
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
' {. H; ?1 |1 A- Y+ F% y2 x$ e
  1. <div id="app">5 g) {+ O( |4 f! \
  2.     <div>
    . ^9 w, S; E: O; u4 f
  3.       <input v-model="parentMsg">
    & Y1 ]$ Q+ E/ {1 D8 @: w
  4.       <br>
    9 w( K% e- q: E/ D! _
  5.       <child v-bind:message="parentMsg"></child>
    % y0 c. c, K" a' S& V8 h9 I
  6.     </div>; O5 ~' w$ P. o4 z3 C) \0 s
  7. </div>
      f6 H+ C$ @& G/ i2 N

  8. ) K" C& o# O1 }- n
  9. <script>" h/ p+ R" C+ j" D. w0 W9 x$ H( o2 u
  10. // 注册
    ( ~% g4 f2 S8 ?) s- W+ w
  11. Vue.component('child', {; C8 y/ ^' ?' U/ h
  12.   // 声明 props
    . z" c8 q! `# o9 f! ]- ~
  13.   props: ['message'],  f1 T6 c4 P# v; K2 `  h( |% P
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    + _6 W  b# D- h
  15.   template: '<span>{{ message }}</span>'
    ; r/ ?- {+ R3 e4 d' X
  16. })
    8 F" p. ~# x- q# p* F, y( p
  17. // 创建根实例
    + T9 x: x" ], @4 k
  18. new Vue({
      i* D" N8 n1 B
  19.   el: '#app',0 |* }, i  _( d# V
  20.   data: {
      J& V) ]% B5 T$ m; {. H
  21.     parentMsg: '父组件内容'2 ?3 \( D9 g4 b2 q9 I. w: f4 Y
  22.   }
    ; ]4 i, i7 H3 u& m; D( t
  23. })
    , W, J+ c- A- \3 K
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例' q* D( M) ]" O+ l' q. a
  1. <div id="app">4 C. F' ^2 I0 [/ j
  2.     <ol>
    & x* C  @0 }% b8 k. |
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>6 T3 E7 B5 h% ^2 s) `
  4.       </ol>
    5 Q& h3 D1 E# F+ T
  5. </div>0 R6 g! z/ u5 i3 n  X

  6. / q: G# {1 v. H& w3 s+ J
  7. <script>7 G) o1 \  P5 T5 u
  8. Vue.component('todo-item', {
    # ?8 g8 {: r) e3 |2 u, w0 p6 S# A
  9.   props: ['todo'],
    9 h1 f. x" {1 ?$ G; S& U
  10.   template: '<li>{{ todo.text }}</li>'8 k1 c  V* C/ v8 M: q
  11. })
    & H+ m7 n+ ]' N; [6 i& N0 S7 h
  12. new Vue({
    5 j. \+ h% v. t
  13.   el: '#app',( k8 {) V2 x5 \/ ~! H
  14.   data: {/ H" y( F$ ~8 K4 N: G
  15.     sites: [
    - \4 p: Y+ M. n" m1 \* c
  16.       { text: 'Runoob' },: y! I5 W! C! |: L2 A+ a1 g5 }
  17.       { text: 'Google' },7 ]4 Q, F9 z9 ~) Y0 ~0 v# w% w3 b6 O
  18.       { text: 'Taobao' }8 P- F9 r* m/ f) Q. w7 `) V
  19.     ]
    - w3 @1 C2 L0 ]9 ]
  20.   }
    2 X  k) {3 p- w0 p5 @9 p
  21. })
    # V: D1 j# g7 J! `
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    0 c% }& v% w5 E! o4 E; B
  2.   props: {
    ; ]8 z- Q) u2 O  h. U! r
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)' y# e( g, s1 c% z4 T
  4.     propA: Number,& T. Q. X; M( l& F/ |6 q3 |
  5.     // 多种类型4 H- K5 N+ d, Z+ b* L
  6.     propB: [String, Number],- H: y2 j& o  N# c
  7.     // 必传且是字符串
    % O: z- B, L0 v
  8.     propC: {" k0 \' A- U, R7 X' |
  9.       type: String,% P. k, D3 d# b; O
  10.       required: true$ Q8 x# ?1 Q7 Y3 T8 O% x; W  x
  11.     },
    - a1 m& a, v. d4 v& A, c- c
  12.     // 数字,有默认值+ N3 h1 _$ ^! S- E% J
  13.     propD: {
    9 H# j5 @. D( G/ F' ~, h
  14.       type: Number,* U9 [6 a4 F# O& Z5 Z4 J
  15.       default: 100& K, a1 m3 z1 c5 }* g7 \' x3 {
  16.     },
    8 B* _; @, S4 Y" r6 i
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    1 u' i( j0 r" c' ?! W
  18.     propE: {
    1 ^8 D0 o5 }4 s
  19.       type: Object,  N+ u6 S! \, H, x$ V5 P! x7 t
  20.       default: function () {
    ) {8 _0 N/ u% a" x4 l; U2 E# R
  21.         return { message: 'hello' }5 ?" p7 e' a6 R% [- q1 M
  22.       }
    8 e. |7 h) X6 K, h! B
  23.     },
    , G+ T) ^9 ?9 K4 S- ^
  24.     // 自定义验证函数/ r& {  {6 `) O
  25.     propF: {
    8 y' i+ `; a+ c6 k5 b# _
  26.       validator: function (value) {
    1 \) d0 Z  ^- Z" A9 D7 I3 D) [
  27.         return value > 10# k$ G+ ^/ h* d& U
  28.       }
    , r) N. n' h# [3 O% P2 n
  29.     }1 C7 b, n4 s3 ^$ v& _( C" R
  30.   }  E! j2 {% c) N' f# \
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    * }( k+ F$ k9 W$ v/ u9 H( n, @0 h! T
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    ' ?2 h) S4 \$ k5 P# _
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例7 P) I5 O+ I2 m6 X5 a" x
  1. <div id="app">: K, ]* P" L- _& X# o
  2.     <div id="counter-event-example">
    + U; {$ s, m! P4 Q) f
  3.       <p>{{ total }}</p>
    % f" h# n4 l, C& b. l, Y2 G: z' [
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    ( ?  w3 Y+ M& r/ |) P- E
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    * b  F5 ~% T- j4 }, j) A
  6.     </div>7 z1 b; e( I2 B0 \( E7 ~
  7. </div>
    0 }, c7 i$ j" U/ B5 k# \# D- _
  8. 7 ?* n' e9 I! B' d
  9. <script>5 c3 k. f# P* u( P& Z
  10. Vue.component('button-counter', {
    ! j( h7 ^( z3 @% V6 n4 k9 d3 ~; h
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    9 w1 a  Q$ P  K4 V7 J6 ^! Y9 W# {  j
  12.   data: function () {! i9 G6 b4 \, z
  13.     return {
    + N. |4 e4 n8 G. a) m
  14.       counter: 0
    + f4 ^; N( _/ `% O  Q6 j+ B
  15.     }
    # U, {! v$ p& C& S- |/ i
  16.   },
    & i# h& {$ h0 z* J) p% G
  17.   methods: {
    / F3 g- S0 T5 Y& T  C# K
  18.     incrementHandler: function () {! m8 U- G1 m" x  x
  19.       this.counter += 1
    1 n6 ~/ ?3 u+ R% v( `
  20.       this.$emit('increment')5 [+ }( M: ]( p! q  s) M
  21.     }4 D3 k7 k7 s  r9 q9 [7 {3 s9 z
  22.   },9 t  O* F+ ~  d$ U( F& l
  23. })& k' Z1 h. k( }7 }5 j: u, C
  24. new Vue({
      C; ?8 e/ I5 b
  25.   el: '#counter-event-example',  N8 X. D7 I2 L! ?: D
  26.   data: {* D2 {7 ~& i5 b- P9 v! U
  27.     total: 0
    6 v. N3 O1 h% i/ W8 g/ A3 b% d3 J
  28.   },
    ! M7 k; p# z4 r7 s. m. Q
  29.   methods: {  m. J# {( b& a6 @# q
  30.     incrementTotal: function () {5 u" ^4 H7 ^+ _/ ^
  31.       this.total += 1  m4 e8 w2 ^9 |! c
  32.     }
    ( c$ g: U1 h9 S) a2 `7 C0 h7 B
  33.   }8 i% F1 [# g0 }$ K8 j$ y
  34. })
    # Y0 {/ z; W2 X# W# U) G5 y
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    0 R( q/ W/ {  i1 A* E
  2. Vue.component('child', {) w8 x( G, k6 R- A! v& j
  3.   // 声明 props
    - F  l0 K# S$ K/ `! p
  4.   props: ['message'],
    $ [! F6 M5 R5 M1 v
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    + M7 [6 Z# h0 `) [3 c# n+ k
  6.   template: '<span>{{ message }}</span>'
    , v1 \8 M% v* V6 C* x
  7. })
    ! m% B( w; b1 A7 |& c
  8. // 创建根实例8 a: R  [3 R& C9 W. w2 n" W
  9. new Vue({
    7 R; W7 K; r# V0 n; o
  10.   el: '#app',0 w% p# r1 C, B8 H; h0 x
  11.   data:{
    % y+ E$ Q# b8 r2 r
  12.     message:"hello",
    3 t, r5 B, V% L  O4 |. ]
  13.   }) y' ]- J" m5 z& d' f: G+ a# H
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {, m* u. q; P2 w6 D) w  _7 m' ?
  2.     incrementHandler: function (v) {
    : e9 l6 ^9 j% S" x. r9 y0 R
  3.         if(v==1){' D( r/ ]" H" Z! ^& x' `- b' X' e  W
  4.             this.counter -= 1% ^5 C) J9 i+ X- l
  5.             this.$emit('increment',[1])2 Y7 R, b1 q0 [: C( V* H1 P
  6.         }else{
    : G1 j& ~2 s$ _( s/ ~
  7.             this.counter += 14 g" {6 }2 B' z) Q# W/ d6 H, Q; V- |
  8.             this.$emit('increment',[2])1 L( o! z9 x/ b
  9.         }3 [  a: V+ J* I; i/ u" R
  10.     }" F) F6 o6 j+ y% X9 u' l1 o
  11. }
复制代码

$ c  H2 Y) H& y+ _. d0 J8 F  b* n  }6 L+ A* Z/ S1 [
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-19 20:16 , Processed in 0.120791 second(s), 23 queries .

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