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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 16296|回复: 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% ~* {6 z' l# {5 g" N
  1. <div id="app">/ c1 H7 A3 Y8 P+ Z) O1 Q
  2.     <runoob></runoob>
    - A9 V7 X, G4 Y% {
  3. </div>& J! E0 P# D$ a0 N% G/ \) @, p8 C

  4. : Q( D4 i2 v$ e% b
  5. <script>
    8 C5 g$ x# Q; j# S5 c0 z
  6. // 注册
    ( d- W. h& g& |& d, @% r7 r* D
  7. Vue.component('runoob', {: I" E2 ^; X9 P6 i; x0 F  u2 q
  8.   template: '<h1>自定义组件!</h1>'
    ; C, C% D- A5 C8 G
  9. })' X$ y5 H& v/ |/ L! {- K7 O
  10. // 创建根实例2 t# s$ ?7 E" n
  11. new Vue({
    : n$ S! i  G' c! S
  12.   el: '#app'' z, r7 Y- ^' c/ l3 ~0 K# Y8 K
  13. })
    & v: h# }. Y% s* H* R! a% P8 O/ v
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

1 c8 Q- R1 w* c6 H+ m
  1. <div id="app">) B" B" ^* @- ^1 h$ R5 t/ a& f
  2.     <runoob></runoob>
    - k) B# N0 u, `7 h) w3 k# y
  3. </div>
    - [1 z* q1 f; }  b
  4. ' F$ j. B9 w/ H% h& A+ e) W( q
  5. <script>
    * Z- j2 [9 r* x
  6. var Child = {
    8 [+ o% y4 _) q4 d& r& c# X% F
  7.   template: '<h1>自定义组件!</h1>'
    * C$ `4 X3 `+ C  U
  8. }
    * u$ N5 B5 r/ a# D5 G1 j

  9. 4 J# d) K0 W0 }/ a
  10. // 创建根实例. p* c4 c4 |" A1 t
  11. new Vue({
    & R, Y; R, h1 ?* V+ l7 k+ r
  12.   el: '#app',( |" c% @, ?4 y  q
  13.   components: {
    ( q! e. [  F3 w! s
  14.     // <runoob> 将只在父模板可用; @* a/ ]9 p# C8 u/ c
  15.     'runoob': Child
    $ x/ d/ w. x& ~6 `
  16.   }
    2 \& p: p/ y; J) V: ?, o
  17. })
    & u; }. W6 p6 h+ ~% L
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
4 b$ N% g' m4 T! X- G7 L6 L
  1. <div id="app">
    ) g9 w) b5 E6 [, N4 e2 Z
  2.     <child message="hello!"></child>
    & j! @( H7 k3 |. @3 g+ \, A$ b$ g
  3. </div>- v  _/ ?( O; I: m" d
  4. 5 X8 N0 `. V+ w8 n- U- R+ q  h( S2 o& m' ?0 _
  5. <script>
    5 N4 b; r! W$ n' V, v
  6. // 注册
    ! t$ K9 |/ o, Z3 q
  7. Vue.component('child', {
    : X% Y% j" [0 [5 G8 j  f
  8.   // 声明 props* m% `, o+ Y$ i) K/ \" t/ b
  9.   props: ['message'],
    6 e- u+ Z1 D% S% E
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    7 |) n' ^9 s9 X
  11.   template: '<span>{{ message }}</span>'& R/ ?! f2 m# Q0 h9 l# k
  12. })! J9 r( Y* L" ^5 X
  13. // 创建根实例
    ! b3 d# m; |2 O6 u  O: r. o
  14. new Vue({% i. i7 S/ U( V  o& Q
  15.   el: '#app'
    . G1 g6 a8 U$ S8 C* ]% P* L! F
  16. })
    : E! m( p# d! v" x) h
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例) G: A# H4 `5 f4 X$ z3 |
  1. <div id="app">! S$ ?) o8 q* a1 c
  2.     <div>
    " G( ~! X. C; A, p; q5 E
  3.       <input v-model="parentMsg">
    4 \% g' D- C7 N+ r1 n1 n& d; U! }1 U" Z
  4.       <br>
    - W+ f0 u4 N6 n! f4 ^; y  U. ?6 k
  5.       <child v-bind:message="parentMsg"></child>9 x' `6 v' ^7 |$ d
  6.     </div>$ D) R+ Z( ~( H4 A
  7. </div>! `( J' m# }$ x0 }& K+ o0 L7 q

  8. 4 S" ^# w' h3 G5 P0 h: k
  9. <script>
    . G6 O/ }4 E" U& t  C. U7 m
  10. // 注册
    ( B" J4 Y6 E- A2 f: E! t
  11. Vue.component('child', {
    # [3 z& r/ t8 X, \- E. R# ]
  12.   // 声明 props7 X0 _6 H) y9 x: n
  13.   props: ['message']," v7 }$ z3 E# p3 y
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    - r5 e4 W, }) G: d. {, R1 d
  15.   template: '<span>{{ message }}</span>'
    9 J/ L% B5 q( f4 t
  16. })7 `& a( Y! m: E$ z) T
  17. // 创建根实例
    $ }. i7 {2 o' j2 b& d
  18. new Vue({
    6 q! k. n( B, O! {3 ~
  19.   el: '#app',& p9 @& g; j0 V
  20.   data: {" k6 j) j4 k& p" m( r) v1 _4 x
  21.     parentMsg: '父组件内容'
    8 r+ r. M2 w8 O$ a) G. k( o1 ]
  22.   }
    9 ]( }1 [8 q- u/ j$ x) W& |  _
  23. })
    5 m; Q( ]- l+ N) L* N5 K
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
6 x2 T9 k( S  b0 X3 u: W' K
  1. <div id="app">
    9 R5 m7 e; W$ ^- I
  2.     <ol>
    & X3 a' F) g2 Y7 r1 T, P
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    % z% ?( n6 h3 U; P  h. T" W
  4.       </ol>
    ' U0 U& K: }5 q) U1 Q& M! _1 ~1 f
  5. </div>
    : w0 k1 S2 F3 ^

  6. # i& x! V6 J- u1 j1 [
  7. <script>
    ( }( b8 D4 D6 D
  8. Vue.component('todo-item', {1 w( V% [3 ^. ]# q- E# f, O7 _% g
  9.   props: ['todo'],
    * R3 \4 _- K* y! U
  10.   template: '<li>{{ todo.text }}</li>'9 u! r* ~" R7 ]+ w6 }
  11. }). j3 `7 W8 K0 ^2 o" f
  12. new Vue({) q3 U8 ^+ i: Z& W& l# {
  13.   el: '#app',
    # Z( |& {+ M! P& `3 \3 Z
  14.   data: {# X0 e; }& K9 d$ c
  15.     sites: [
    3 e3 O5 I+ P/ l& r  Z  d) B
  16.       { text: 'Runoob' },
    4 E& f0 f! F1 K& _% d/ s
  17.       { text: 'Google' },  b, H* |; S" l3 f, y
  18.       { text: 'Taobao' }
    0 a4 m" K( R3 W4 R
  19.     ]
    ; W- j  a! z4 N( e
  20.   }
    7 I. U) `4 w" x9 d: i  C% k
  21. })) O1 a6 |% M  j$ a- k* d
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {7 O: j1 `/ x/ `! g3 q  d
  2.   props: {" j& @" ~8 u! w; v
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    # w# B6 P8 L3 D1 J
  4.     propA: Number,
    ; W* r  F. T* H- Y  \( |* z
  5.     // 多种类型( W0 [/ G; |. I: Z' O
  6.     propB: [String, Number],
    % _3 Y+ l! L9 T$ _+ d/ O* ]
  7.     // 必传且是字符串# l# v) |1 w2 \
  8.     propC: {
    . Q" A- d- h8 Q; O! x8 \; g
  9.       type: String,9 h* @2 u6 w6 P5 [1 C7 f( w) |
  10.       required: true; j# ^6 _  l% X. n4 g( T7 q6 K
  11.     },
    6 B. e) l- E* K* X: K
  12.     // 数字,有默认值
    " }, m( @3 ?. e
  13.     propD: {& z) E0 I. J: f+ @2 Z, X
  14.       type: Number,* S0 ~/ x( I/ Z% H$ ]: W$ c9 y
  15.       default: 100
    # Q' H1 X7 r( G% k' l
  16.     },$ Q% I1 U/ @$ M
  17.     // 数组/对象的默认值应当由一个工厂函数返回7 s6 j+ C# `4 u
  18.     propE: {1 K! ]) @, Q' l4 v8 Y  s
  19.       type: Object,
    3 D; J5 F5 E$ D) j/ c+ o+ ^' w- }
  20.       default: function () {
    : Y) A' T' s: T7 y& U# v
  21.         return { message: 'hello' }9 c* `* S5 D4 U) s  b$ D2 I
  22.       }4 w! U. M6 h6 V2 J. s
  23.     },/ V: a( ]4 I* x3 H5 n, r
  24.     // 自定义验证函数! M; V* h+ i! k! T# }
  25.     propF: {
    6 w; Z  ^! U, N* [; }$ w1 L! z; ~
  26.       validator: function (value) {6 n; w' V, F- a' Q  v" p  N  V- K9 N
  27.         return value > 10
    & C; G9 E# G2 P
  28.       }/ o3 J; d( ]3 ]1 f2 q
  29.     }
    : T0 {* i: s2 b& ]; B
  30.   }- p9 R5 y8 c' N3 b4 q- G
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array- K) q. [% Y1 q* m' z
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件; W# \( x8 D0 i* S. b- B+ N
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例  t9 r! x' }8 I
  1. <div id="app">
    ! B6 [8 H& T3 l/ N& k
  2.     <div id="counter-event-example">( Z3 ?  p% ~( ?* Y
  3.       <p>{{ total }}</p>5 O( R' `* e* r. z
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>1 h; o' O, b" E( U' g7 q3 D
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    ( d1 B1 ?0 }) d! L/ j# ]  c" k9 Z9 x
  6.     </div>& L" _& h3 H/ ]2 ]% C% `: V- T
  7. </div>
    + X* {2 i- D+ ^  S, A

  8. ( b1 O, }& A2 a- ?& f
  9. <script>% Z& t8 ~3 i8 V" T( U& S
  10. Vue.component('button-counter', {
    - m; t" M8 D& Y1 W
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',+ o: {0 @+ g. K: T
  12.   data: function () {
    ( I8 z' c# d5 G$ N* o* _2 ?
  13.     return {
    - V2 C7 K8 c  Y& C/ W( [0 a  f# U* D( r2 l
  14.       counter: 0. |) _" X7 T, ^6 E, j
  15.     }/ E& d0 T0 [0 W
  16.   },
    3 b5 K& p4 e* d
  17.   methods: {+ W, V$ t" r* t: b
  18.     incrementHandler: function () {. {2 L% p2 I8 l5 L) i* U* {0 J
  19.       this.counter += 1
    ' V& }0 W6 T2 W$ T4 T$ U
  20.       this.$emit('increment')
    : P/ d- i$ \3 w+ Q
  21.     }
    7 A' C7 ~4 W4 u# Q: r5 Z
  22.   },
    6 J& Q8 z1 T- U% r* \! q- C
  23. })
    ! d  z# @! B1 _3 o2 L* G) U
  24. new Vue({( Q. H$ H- C7 f+ H0 \
  25.   el: '#counter-event-example',
    ) A% T0 ]: {; W* W/ D6 f: K
  26.   data: {. p' x+ p- s* i8 L
  27.     total: 0
    - T. A7 R1 T+ s; G5 A+ P7 o
  28.   },
    ( K5 v* B) w: E. P( v
  29.   methods: {, H7 x% h5 w  x" r% U$ O! T
  30.     incrementTotal: function () {, K3 X5 a6 v( _. x% f, X3 m
  31.       this.total += 1: ~: c* p4 y3 [
  32.     }& x, l' _4 v7 Y8 K) S
  33.   }
    % c: w! z; S" C$ }9 p/ C
  34. })
    * C) P8 V* c2 ?3 d7 C
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    6 f$ ?. u, e3 }$ C. q
  2. Vue.component('child', {
    8 c& ^, \: V# Y' z
  3.   // 声明 props( C/ f! N) Y4 `1 C( N
  4.   props: ['message'],
    * ^) s: W& H& z; D" \+ R
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    , N8 S2 s8 M7 t! o
  6.   template: '<span>{{ message }}</span>'+ L" ^( g1 t( s. v, E/ N
  7. })
    2 R0 B, N) l$ R. t% J* _2 s" N
  8. // 创建根实例
    4 s1 S' d, k( q9 _' _, Y; T) f: ~* y
  9. new Vue({
    # P7 o3 Q5 x& G2 M$ m
  10.   el: '#app',
    ! @+ O5 o. |. D( [1 O
  11.   data:{0 |: z! k1 @0 a) x
  12.     message:"hello",! ~6 u. E, }; r0 l
  13.   }' G8 t) V7 n, C) p" Z5 d1 z. b
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {9 \$ w- @* d" g- H; |
  2.     incrementHandler: function (v) {
    7 D( Q7 k$ ?. e9 C! _4 I9 r
  3.         if(v==1){9 ^- C' W" T* Z3 [7 f% d( a
  4.             this.counter -= 1
    0 b/ D8 @" U# y
  5.             this.$emit('increment',[1])8 A/ E  z( _0 J
  6.         }else{
    3 l9 P8 r1 ~  E9 Y( s. i$ z9 `% ]! q
  7.             this.counter += 1
    ; a/ x3 Z# R; ?; \' i+ v% I4 [% d
  8.             this.$emit('increment',[2])
    / q. h. a/ A- X# R' o
  9.         }
    , g0 Q- o: u# N5 I2 ?% K
  10.     }
      y' Q; I8 q- R" B. k; i. l- j* ~
  11. }
复制代码

4 ?1 n, J- D- j/ E% }. s) c* c+ Z. Z' }3 t8 a; R6 _
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-8-4 10:54 , Processed in 0.054297 second(s), 22 queries .

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