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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

0 r, x8 m3 h5 o& R4 t, Z
  1. <div id="app">
    ' @3 t* M3 O% k( T1 ?
  2.     <runoob></runoob>
    % H: @# d) V  B7 L
  3. </div>
    0 o, \) i) [( y% B+ L0 C
  4. 8 E2 U7 U5 O9 D
  5. <script>! u1 e5 g3 ]2 R9 }6 \" E, w- v3 {
  6. // 注册7 b( g0 S7 h3 ?
  7. Vue.component('runoob', {
    - G5 t7 z5 ~: U) `1 J$ h, [
  8.   template: '<h1>自定义组件!</h1>': N& [9 h$ }. C; ^; h" z
  9. })
    6 Y, Q  ~9 }; }# h+ o! N0 w
  10. // 创建根实例& B, z* s/ b' @% z5 S2 J
  11. new Vue({
    ) U$ f7 `  \/ l1 g" T) ]1 Y
  12.   el: '#app'
    8 ?1 k- O9 l: N
  13. })6 ~; p( K1 K# \$ T; }% r, E
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
" q# Z! g" t0 I" p
  1. <div id="app">
    8 C; U3 S% X- ?" Y# V, r- O
  2.     <runoob></runoob>3 S: `- E" x* p. \
  3. </div>
    . r% D( i5 J8 S* m" V6 A7 X, A8 L
  4. - r# u6 M0 l6 i* p* I- H# T
  5. <script>
    / S! S1 N1 d$ U* M5 {: i
  6. var Child = {
    ! X4 N* A: M8 }" t6 k2 J
  7.   template: '<h1>自定义组件!</h1>'9 F" {! h) g0 N& v- B
  8. }
    $ r$ \& v, s" u$ e8 P$ J+ W: \

  9. 5 z+ b+ L& o0 P0 t& B4 w( c
  10. // 创建根实例
    ! O. e, b$ u, j* c+ t
  11. new Vue({
    ; A& r& S  s4 f6 q0 j
  12.   el: '#app',. _* ?4 o, C& V- o. Q
  13.   components: {
    & e" y$ t* c6 }) a1 p6 o. o) N
  14.     // <runoob> 将只在父模板可用. y! K6 U( }* `' i( p
  15.     'runoob': Child/ y0 {  b) m5 j7 w5 i7 W% W
  16.   }
    0 ^) O& N$ I8 j
  17. }); T5 F* I+ U* ~; \1 z9 Z# E
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
0 v" B" }  k* O* x  \3 p' K
  1. <div id="app">$ `3 j6 s2 O! h1 c" z
  2.     <child message="hello!"></child>
    7 e9 J8 r% {, G2 }
  3. </div>
    ) j$ [" ]/ I. ~% R! g# M) e" _
  4. ' ^, c) q. K4 @+ b
  5. <script>7 G! t7 T( ]: f' ^, C
  6. // 注册6 e; b, L! x; e* E' H& U+ k0 W5 n
  7. Vue.component('child', {6 Y" F2 S$ p2 |8 G
  8.   // 声明 props
    * @# M; Q6 K9 i* B6 Y% T1 G
  9.   props: ['message'],6 a% b' u3 p5 C
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用3 {" t- s0 N* e; z, r" ~
  11.   template: '<span>{{ message }}</span>'5 H; C8 W4 m& y, {4 u
  12. })
    4 [# h& S1 l- P( L1 k* }$ w
  13. // 创建根实例9 F8 b4 G1 @7 J, ~! W
  14. new Vue({% [) t; d1 w( S/ \6 k8 Z: m$ @0 M
  15.   el: '#app'
    ' n0 n5 x% L) T9 w( f
  16. })5 _! K: N& y) [! Y$ H+ Z/ Y
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例- N1 r, S( L; W* B1 K# d
  1. <div id="app">4 i+ i' |" ~6 I
  2.     <div>
    / l% F- L2 Y' ]( l/ d
  3.       <input v-model="parentMsg">
    - t8 ?: ~# X; V; r; t
  4.       <br>
    + l7 Y. {' ]2 V8 V' @
  5.       <child v-bind:message="parentMsg"></child>3 X, ~9 `( r! Q3 V
  6.     </div>
    8 l0 Y4 a( K$ F7 ~- F8 D
  7. </div>
    ) a- @3 I" o" r
  8. * Z& E4 X* J9 Q6 Q# G, Y
  9. <script>
    7 c* a' N' @' A. H. J
  10. // 注册
    ' N* X+ h. e/ N( {( u4 ]- N: E
  11. Vue.component('child', {
    + ]0 M" F6 {' n$ T5 q0 c- g
  12.   // 声明 props
    4 h% w# R$ e3 I; n  ]
  13.   props: ['message'],
    9 ~9 u* f$ b, z
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    & D# a3 E) a& l5 |# `9 Y$ E
  15.   template: '<span>{{ message }}</span>'
    . @1 O6 A9 C& ~/ k2 j' ?* x
  16. })
    * N, E' y8 t1 F$ k3 a2 \2 E
  17. // 创建根实例' H, @  c! z# {% x
  18. new Vue({1 {3 `7 f2 T, C2 g1 w+ l! w8 q2 M
  19.   el: '#app',
    0 W2 J9 c: D6 N* T& e1 d: U  w
  20.   data: {
    % z! E: ]/ }$ O5 h, N3 R
  21.     parentMsg: '父组件内容'$ u. |+ B! v$ T& j9 \
  22.   }
    7 d" I2 u5 b4 J  ~* Y
  23. })
    " R+ |6 H" L% u/ R* [
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
& I# a' Y4 Q" V4 a7 H
  1. <div id="app">
      L$ o" @) C: K6 H8 \+ r
  2.     <ol>
    & z- T& y) W# T5 B7 o2 C( S
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    4 a0 j6 H4 S* S- c$ k. f2 K
  4.       </ol>& L% d% r6 X4 I; ^
  5. </div>0 [+ s( O" _# O+ F- k

  6. 4 L6 d5 O: f, c2 q9 D
  7. <script>
    7 ]% b. B( H  H+ W
  8. Vue.component('todo-item', {6 E. \) v9 U- b3 j1 H' v
  9.   props: ['todo'],
    - n, |3 [3 M/ [. s  L
  10.   template: '<li>{{ todo.text }}</li>'% |% ]( S2 q, |
  11. })5 |- _2 B! f5 ?4 ^. R
  12. new Vue({
    ( o8 H3 p. w% I. L+ s- L
  13.   el: '#app',) m1 r/ b9 N) q) s4 j" z
  14.   data: {
    # y3 x' ]0 I) b4 F/ v5 }: x
  15.     sites: [; x( s2 {# X/ r( D5 T4 K
  16.       { text: 'Runoob' },5 w5 S: l$ G3 }
  17.       { text: 'Google' }," Q) S* v# k! Q0 s$ T7 x0 o8 U
  18.       { text: 'Taobao' }
    9 C' [  Y- D3 Q8 r9 J* [) d
  19.     ]
    8 X0 G& h. f: H4 z& ]/ z3 s
  20.   }, F7 B4 }/ b7 u) i' k- o
  21. })
    5 Z3 }, ?& q2 a# E/ E
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {$ {. `% `% _8 |$ g: ]+ X; c9 z; W
  2.   props: {2 `: {  h; C! a& M5 n
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)) `' c5 V& j, U9 Y! y
  4.     propA: Number,/ J4 y* `" W$ _5 l
  5.     // 多种类型5 T* Q# H$ h+ k
  6.     propB: [String, Number],
    9 \* _! w8 h2 w8 w. [" i" a
  7.     // 必传且是字符串" `: d" w. r% }: \0 t* |
  8.     propC: {. k% F( X  U: l
  9.       type: String,
    1 ^0 g( X3 W0 \. T& t( y  d
  10.       required: true6 }# W4 b1 J' _) _6 B! n+ W! K
  11.     },
    ( X4 s7 N  |' C% K' W2 J- A0 ?/ z
  12.     // 数字,有默认值
    ! w9 m$ d* a& U1 U& i- |( s) B7 k# v
  13.     propD: {: U6 W4 f" c9 \- h  Y9 p: L
  14.       type: Number,  f" v7 z+ ~* u. O" N: \$ p
  15.       default: 100
    , C1 x9 p8 w: L. e
  16.     },
    , `: r" \2 }' k
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    4 ?" Q  S! w) {9 {$ O6 g
  18.     propE: {7 x& @* q$ k. W9 ^% F
  19.       type: Object,8 N/ d: e# r+ n6 B% _
  20.       default: function () {- o  z& |4 Z+ p! `" u
  21.         return { message: 'hello' }
    ( K* \1 |3 S- }& A) ]" f
  22.       }% |+ `- s5 B# D; f% o7 X
  23.     },4 w( f1 O, r( X: ~( Q2 N' D
  24.     // 自定义验证函数
    + q6 A  y9 c: J% l3 [$ d
  25.     propF: {
    4 H" ~6 R, H! ~1 G
  26.       validator: function (value) {
    : i% g! r% V9 d+ M/ M: t: ~+ m
  27.         return value > 10
    & s1 P$ ^$ Q/ V" F; d/ ?
  28.       }3 @$ ]& j* T/ S) a' W( A, H2 n/ ^
  29.     }' K' W/ x: ~1 W1 V% S. V( k- `: y
  30.   }
    ' ]7 _5 \$ v7 ?, i& u! ?$ J3 H
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array: Z, W9 W7 l, ^0 j+ j
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    4 g- R& q7 |& h) T. u( p
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
2 `/ b0 s! B1 ^9 Z7 z! I6 c) _
  1. <div id="app">
    ; x' B$ ?, d2 T) ]% l: Y
  2.     <div id="counter-event-example">
    ' v7 m" k5 l% g2 X4 t5 ^+ I
  3.       <p>{{ total }}</p>- ~* u0 @' c4 p6 h/ Y( ^+ G
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>2 F$ s( O& H4 i# s& y( x
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    - R3 E4 L& N4 Y' W5 x/ f
  6.     </div>. ^( ]7 o" G1 w2 [
  7. </div>
    6 x" w3 o" j  p5 ^
  8. $ J  W* `9 @5 N5 u+ n5 u& m
  9. <script>% ^( P, K' m9 S2 S' c
  10. Vue.component('button-counter', {+ {& l5 P: [/ G" Y# V$ J! V0 e/ B
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    & R2 e1 B# x" ?
  12.   data: function () {* I, z2 t7 ?0 c1 ^
  13.     return {+ _$ U# P4 h1 e3 f- S7 K- C+ k- T/ `
  14.       counter: 0
    # }+ {, l. E" D4 p
  15.     }; U2 t8 Z  m. n7 v; [! l, Y1 n7 X
  16.   },
    & r, H& g1 |) j4 {8 p
  17.   methods: {9 R5 g4 Y& i3 A8 m, v1 `3 X3 o5 [8 y7 f
  18.     incrementHandler: function () {
    ; Q+ l! _2 o# ?0 R' u. f- S
  19.       this.counter += 1
    ( g9 m7 J8 u6 h5 r1 j2 {! R
  20.       this.$emit('increment')
    5 q4 H+ v! [. z; E+ H
  21.     }- C, p% {9 l/ W- t" c, _, J- }
  22.   },
    ( @2 N/ |+ {* T2 w$ \( n
  23. })# A: x9 b) B  X% u5 M" ~
  24. new Vue({
    - j1 |; h5 C/ j
  25.   el: '#counter-event-example',7 b/ U7 h# j9 t; [
  26.   data: {- g7 ]. \8 `- E! L& {
  27.     total: 04 o2 L/ n1 @1 B$ o
  28.   },6 V5 b, C: w+ I5 m1 \% {( H
  29.   methods: {
    7 |; S5 K: e1 G, p
  30.     incrementTotal: function () {
    % u  @5 h8 U& S" u
  31.       this.total += 13 s* Y1 a7 P# `* v6 K
  32.     }5 D2 C! M$ z5 f- O
  33.   }
    3 B% Z0 N* ~5 E" x$ O
  34. })
    9 `/ G* S3 h/ D) d. Z
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册9 T; J0 G. K; m7 l
  2. Vue.component('child', {8 Y  x9 j/ X/ n2 i7 b
  3.   // 声明 props# o: F4 w9 Z( \" C3 J8 A7 q8 L( j$ Z
  4.   props: ['message'],
    8 ~; Q* R( u! |6 U' x5 ]
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    4 w! w' M, x) g$ R- Y& m
  6.   template: '<span>{{ message }}</span>'
    6 Q# [/ q% T8 G+ M' z( U; {* r
  7. })# ^8 _) p1 G+ t7 X+ v) x3 u; q
  8. // 创建根实例1 I3 a5 S' z! y0 L6 w) m8 E- D
  9. new Vue({7 f2 D/ \, r( P# D3 N- r- C
  10.   el: '#app',2 y2 K- I, a+ q3 E
  11.   data:{
    5 F, L5 d1 X3 [
  12.     message:"hello",* H, S# N& |# e# N
  13.   }  |5 v$ y! ^% Q/ v% {. a
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {% O9 [8 f% V8 b, K+ W
  2.     incrementHandler: function (v) {
    7 s3 V8 G& _3 X# V) r& f" W
  3.         if(v==1){- u0 c$ ~5 x: f1 |8 Q4 P
  4.             this.counter -= 1
    4 g4 ?: G# Q6 a- h, A  O
  5.             this.$emit('increment',[1])
    2 Z* e7 `* y; g5 @3 V% ~  M( A
  6.         }else{+ q* Q8 e( W# B5 _( |
  7.             this.counter += 1
    8 o$ c+ D  Q7 q9 C/ S; C& S9 G: N
  8.             this.$emit('increment',[2])( C$ S, i, L) m6 i' T3 Q8 [
  9.         }* q: j0 D6 i# T) z2 h
  10.     }
    ; p( I" M' B9 r4 F
  11. }
复制代码

5 ^- l& w9 D' q8 \( {
" G- F' a3 g8 \  R- V6 K
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-8-5 01:12 , Processed in 0.055613 second(s), 22 queries .

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