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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

, ~9 @7 Z, ?& a8 n) N# j+ u
  1. <div id="app">2 w  |" s0 S  l( B4 m: f
  2.     <runoob></runoob>
    : J* Q4 b8 T) m* S* R3 S2 [; c1 f( f  A& T
  3. </div>% ~) T; ^0 b7 l5 f

  4. . c3 P6 f3 U' S7 \) J$ t
  5. <script>
    % L& _$ g) ~3 @& b2 F
  6. // 注册) W; u& p% a5 w# U
  7. Vue.component('runoob', {
    7 L" |  [0 F2 o
  8.   template: '<h1>自定义组件!</h1>'
    # S; u9 J8 c/ v8 h; n2 ~# o+ B8 R. r
  9. })
    2 p+ `* K- ?. e0 R: G# y; ^. s
  10. // 创建根实例) s5 q0 R9 L! ^" r! q5 k6 R
  11. new Vue({' V' y6 r8 z9 A
  12.   el: '#app'
    ( S" K- y: W/ s, F, b" f
  13. })6 K) i# n' |' k9 c0 L* v1 c) {
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

" h# V8 |$ `( P9 b- U
  1. <div id="app">
    9 l: `8 X7 x& z7 Q
  2.     <runoob></runoob>/ `. ^+ k- B5 `4 m6 m
  3. </div>- B, O" }( G# \, w  {3 E
  4. % o2 k3 u) o1 \! K- f: P7 k
  5. <script>
    $ W. D2 K3 f: z
  6. var Child = {
    2 c2 P$ L/ A2 U; c( i+ n
  7.   template: '<h1>自定义组件!</h1>'
    # [6 A) s; I1 N  L# J  [  y
  8. }
    ) I# z# [7 N% Z* @4 }
  9. , d% b& }# G5 H9 o6 K4 a# ]
  10. // 创建根实例! x* |; |1 O# z9 I* i. q  T
  11. new Vue({
    . w+ l& n' M9 Q
  12.   el: '#app',2 p# y2 d0 @( P/ M0 {, W/ |  n4 W
  13.   components: {- Q, D' J) z1 x' `+ v0 K( T
  14.     // <runoob> 将只在父模板可用. Y; D$ H& t7 v5 ]$ F
  15.     'runoob': Child& s# C7 M0 f1 R
  16.   }
    & E  r% V9 F  i$ [3 C  Z0 F7 Y
  17. })$ h4 k3 M' c* E& s: Z) @' g
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例8 a# G/ i. l1 \  f" |6 F: O, E
  1. <div id="app">
    + t! b+ G0 K* Y9 R
  2.     <child message="hello!"></child>! w4 F1 I0 K8 Z( E+ z( G" ?
  3. </div>: n6 W/ V+ b, ?9 [: V' [( Q/ m

  4. & D/ K( D. A+ I2 z  B4 R
  5. <script>
    6 L9 p& |+ |. ~* M
  6. // 注册# F5 q: ~  B8 E9 ?
  7. Vue.component('child', {0 x9 c6 I& h" j  T$ z
  8.   // 声明 props
    ; ?' m6 t2 m- ~" N' h
  9.   props: ['message'],# ~, N$ v% A! g
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用) j: l0 g) ]8 H# Q/ `, }; p
  11.   template: '<span>{{ message }}</span>'
    3 P+ F! X' V8 Q. Q: H/ U
  12. })) j% m) S7 C3 x+ v% {1 F
  13. // 创建根实例
    ) s5 L" c6 t; I# y5 v% l
  14. new Vue({
    8 h6 K8 b9 W1 ]# {
  15.   el: '#app'& L0 x& b; K9 `
  16. })0 D% Y& Q2 v& Y) \3 X
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
% K% z/ V; i9 i! C; Q9 K4 y
  1. <div id="app">
    & z9 m# A* Q8 W4 R3 n/ v, }
  2.     <div>
    ' W; P1 F$ O5 [- V: K. U* @  ?
  3.       <input v-model="parentMsg">+ J/ c  y; j6 p5 e, r
  4.       <br>
    1 }' e' ~4 P% t6 O6 M0 w! x
  5.       <child v-bind:message="parentMsg"></child>+ S. h$ Y( _" {- K) `, V
  6.     </div>/ _1 U: }8 l7 X$ ^5 q1 P# i
  7. </div>
    5 [5 n; L( J; R3 S$ w2 O4 O1 i6 R- j
  8. ( l$ V) x* O* ]7 j, x) G+ I
  9. <script>% u  o) e' e8 j( @, h
  10. // 注册# i/ P# F& |  C' Z! b
  11. Vue.component('child', {
    4 y  ~: A+ g/ A" Q% A: J- R* _
  12.   // 声明 props& J3 Q) g" l" M& R& `
  13.   props: ['message'],6 S9 i+ D6 s9 B0 V
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    $ x. O( |- _+ w/ W/ ?
  15.   template: '<span>{{ message }}</span>'
    9 ^+ K5 V7 s) @, H3 g6 L
  16. })
    * g- w8 Q: q& T- X
  17. // 创建根实例; H) s! T8 X+ `3 ]2 Z# B
  18. new Vue({
      P4 d: T1 R6 o/ ]+ x) ~6 m* V
  19.   el: '#app',
    + A: e2 J( t* y$ [/ M( n1 i/ Z  l
  20.   data: {5 }- M2 `8 ^, i
  21.     parentMsg: '父组件内容'0 [  Y" R% ~0 M
  22.   }1 s' g0 P' N8 R
  23. })) O0 x; M' [/ R  X5 S9 ?2 C9 b
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
6 D* `. ~% w( H( A
  1. <div id="app">" @! z9 x5 j) R) j" k1 t6 Y' x
  2.     <ol>
    / H" E$ g9 i% f" B* t
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    7 X" g" Q4 ^1 @1 C* @0 J  g0 {7 _
  4.       </ol>
    & `) m5 H8 ]5 y* [- `  M* P
  5. </div>
    & I- }9 \  }; u+ ?0 T2 I
  6. * ]( j& u6 v0 d0 w, E
  7. <script>
    1 Q" [  ^( M$ l: t8 t* d
  8. Vue.component('todo-item', {! ]2 h  s" ^- ]$ `4 f  h  C
  9.   props: ['todo'],
    * r+ [3 a6 ^; D! F& p
  10.   template: '<li>{{ todo.text }}</li>'0 V/ U! u7 A7 O: V6 U) v! `. K
  11. })/ C+ K# ?3 p2 ]  D- x: R3 e
  12. new Vue({' W3 h' F9 O: t
  13.   el: '#app',7 [$ t+ f7 o' Z; s. X) }9 w/ B7 _: X" M
  14.   data: {8 k5 {. J# |3 C1 D& {
  15.     sites: [
    9 l7 r6 w0 J+ b. }" u2 h
  16.       { text: 'Runoob' },
    1 l* [, S$ @; s* |; t" E
  17.       { text: 'Google' },
    . k6 Z# @& K3 h8 d& M
  18.       { text: 'Taobao' }
    3 H7 F, l9 A/ E0 n+ O- q
  19.     ]8 _7 O" n1 f) u; H+ [# N
  20.   }* w, }2 i7 w- ^3 x- z5 q
  21. })
    $ C" a5 f" P& `6 O
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    ) q/ @5 \$ K5 n* g
  2.   props: {
    2 g, A" f. b( F5 g
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)
    6 w/ J" {$ h. |1 `+ Q- j
  4.     propA: Number,
    3 {5 S. `9 V& d0 Z9 p6 o
  5.     // 多种类型
    $ g, b& Y" q) P* M+ ]9 \/ v7 }
  6.     propB: [String, Number],
    ' e2 W9 c6 P) f& x. Y1 Y
  7.     // 必传且是字符串6 R0 [, g' b5 N$ b& f2 T# Q& r6 p# T
  8.     propC: {
    $ `4 \6 @& f+ k& v0 P
  9.       type: String,
    9 O& A5 U" X/ {  }4 I9 e
  10.       required: true
    ) _/ u# t' A# K
  11.     },' Q( K3 N7 T; P, P' v
  12.     // 数字,有默认值5 y2 K& W, _& ^" h, t
  13.     propD: {5 u  N* n1 X( C1 f6 I2 q/ H8 C
  14.       type: Number,
    * f8 Y9 E0 M( N& k
  15.       default: 100
    8 l0 E3 s/ C+ ^$ O  m
  16.     },$ J: A; d9 m3 w( w2 \$ D
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    & H- ?- Z5 [- _. _' i# i
  18.     propE: {# ]' N8 h7 P* r1 Z5 J
  19.       type: Object,5 c; t  V: |7 _) y5 e! c
  20.       default: function () {) v- D& g9 Q3 y% H
  21.         return { message: 'hello' }. E; @% o! z* y
  22.       }7 u& W4 n8 n0 ^# k* T* O
  23.     },- |! s4 e7 q( D
  24.     // 自定义验证函数1 P! q2 J& w5 h$ t8 B  i
  25.     propF: {; N8 m, x7 M3 G5 x, z
  26.       validator: function (value) {2 B" Y0 B! L- J' F- h
  27.         return value > 10
    " ^  O! q8 r; V& Q" d- l8 N
  28.       }
    3 w; \% M% k$ y3 \0 A, ?9 B
  29.     }; _6 R% ^2 [+ B) `8 a8 }! r
  30.   }6 R" D4 ~; ?& {. `- R7 c
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    " ]  f0 Y* l; L: ~+ P) U4 r
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件* x; F7 i( l/ x% k& A0 s8 u
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
5 h$ m2 e# S( u* r8 c
  1. <div id="app">$ V6 j( g+ u4 W/ ?7 a( l' [. `. ^
  2.     <div id="counter-event-example">
    5 r0 Z7 }, E1 X0 ^
  3.       <p>{{ total }}</p>
      p) c$ V; u/ k) E8 o$ @9 s
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
      [; o4 L- J: l7 e
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>0 }# Y2 o# N" b- ?4 X& D7 a3 O0 l) A  `
  6.     </div>
    9 L0 |; ^( r: w5 @* k$ [3 [+ t/ ?
  7. </div>* L! w, `% y& |2 S+ O. H8 h

  8. ) N; o( E% a; }& a6 M1 _- k
  9. <script>4 L2 ~  B! R) f8 G
  10. Vue.component('button-counter', {: r" Q8 K8 _/ W6 f6 k. {0 H, T
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',2 V9 Z8 P3 R* x- v; k' p- ]% \5 D  d
  12.   data: function () {  I! E7 p1 t# f# z7 J! |
  13.     return {
    7 ?) {! }% D4 B% M. E
  14.       counter: 0& s" v! c7 v' b) b( B7 T+ G
  15.     }
    6 V4 L' v9 z8 F* a1 {5 F
  16.   },' n! ?! |, w2 E) ?" R
  17.   methods: {
    $ E6 l4 I+ ]" u4 V0 t
  18.     incrementHandler: function () {
    % Y4 o# E3 Z& s2 w) Y; ?) G
  19.       this.counter += 1
    2 m% d) l5 d; r7 t" k
  20.       this.$emit('increment')
    : j2 O* H0 ^' z0 B+ ^2 @" V
  21.     }
    " V2 i2 p5 C; n1 U, @& F' v3 ~( d
  22.   }," ]% U) p& C: H3 B  S9 U
  23. })
    - Y9 E+ r5 l, Y  x* C& E+ m2 T% G
  24. new Vue({6 o# y, J- ?" r+ w# o+ y* k( Z4 R
  25.   el: '#counter-event-example',
    ; ?: H6 ^: R% O8 j, q
  26.   data: {- \7 r- z, }( P' }  C1 R
  27.     total: 0' J0 X* _/ I- v5 ]5 H
  28.   },
    6 @* s0 C2 j/ M- E8 T
  29.   methods: {# f: X( v; j1 c/ F- {
  30.     incrementTotal: function () {
    % O2 j0 N8 o7 i
  31.       this.total += 1
    , m7 t2 _+ D7 |$ D- [# P; Z: |
  32.     }
    $ v: U" \% l% I9 N! q2 \; T9 w
  33.   }
    - A* G' Z) g; V3 U3 l
  34. })
    / O: ]5 F. q9 e! x0 N0 e! c
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册6 w& o3 v4 b& }  b3 n: P+ Y
  2. Vue.component('child', {
    / H8 F7 ~6 _1 X# r8 {) J; F5 B4 ~
  3.   // 声明 props
    ) }' R5 j" X# n9 y
  4.   props: ['message'],
    % s! b. C; ]( O/ J
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用$ E; \0 j# {' D) J/ x
  6.   template: '<span>{{ message }}</span>'' ^1 V) ~0 g; p) E
  7. })/ ?. V2 D/ @% ]) u  I7 T
  8. // 创建根实例
    4 ~1 ~7 B3 D& M' ?7 t& s; y# B
  9. new Vue({
    : H; L4 |% [2 m! z$ p/ E# L% D# V
  10.   el: '#app',& e5 E; }. l5 c" `: X
  11.   data:{
    , ]: k, z. W; ^1 T' ~
  12.     message:"hello",8 v& p: z4 _! p) J( s5 d( G
  13.   }6 f# R( y6 v/ [: G% O1 Y8 q
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    # L* L8 G$ S- X% L- N7 s1 n$ `
  2.     incrementHandler: function (v) {
    $ G' z. p' z( z; {% }
  3.         if(v==1){
    * L! h" x: b3 X3 s/ D( H* ~; a2 k
  4.             this.counter -= 1, O+ r9 G3 d& q$ L, W' f& f
  5.             this.$emit('increment',[1])
    " G  `9 Q. x& R- _, o8 _% o  ]" S
  6.         }else{6 Q* b& z5 r' R8 C: @: s
  7.             this.counter += 1
    ( g! ~4 g, b( }" Q8 j, q8 X7 ^
  8.             this.$emit('increment',[2])  d; E/ g8 K" k) `$ O
  9.         }! k* Z* t' S0 n/ N
  10.     }. O3 j# G4 M# P3 R& m" p
  11. }
复制代码

- p% f" `  F! H2 ~/ q' ~, Z) l4 l( T% ?- H9 M. r4 D- U2 ^0 Q6 ~8 s
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 11:55 , Processed in 0.136189 second(s), 22 queries .

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