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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

2 Y, m2 A6 F/ f$ O/ |1 h+ r$ k
  1. <div id="app">$ T# l8 e% Y6 \  T0 \& R
  2.     <runoob></runoob>$ d/ _- Q* }( H+ [' Z  [% t
  3. </div>- h9 z) M: I* b0 r
  4. ( Z8 d9 ?, i7 `5 U/ L5 X% C% x2 P
  5. <script>
    8 T; V3 e/ d- S% S- N
  6. // 注册
    % F; w8 K$ P' f1 [6 q  Q8 G/ H+ U
  7. Vue.component('runoob', {
    ( j4 L# E3 S; r' m9 y* I& z
  8.   template: '<h1>自定义组件!</h1>'% j; k' ]" `' L+ s7 U
  9. })
    6 {" d9 r" ]$ ?6 B" Z" W7 R+ ^
  10. // 创建根实例2 @$ z0 A" e9 C2 K! s
  11. new Vue({, x/ b# ]9 o+ Z( O/ ?6 f
  12.   el: '#app'
    # T2 \7 t" ~( M1 D) d9 s1 s: T
  13. })
    : d. y. W) u% ~6 B* b" P
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:

' z# N+ m6 S( Q6 q. a5 p$ t" V, @. ?
  1. <div id="app">
    6 |% x# l5 j7 q- H, z% T# N
  2.     <runoob></runoob>
    " ?. A* [4 `+ U& p
  3. </div>
    , ?( t& O, X6 N; V* U

  4. # S* b6 t" E, k8 k1 M
  5. <script>
    6 S5 e+ R5 Y0 L& m* m0 `
  6. var Child = {1 y' f7 h: @9 W) H( P3 u" \  U5 N  v
  7.   template: '<h1>自定义组件!</h1>'
    + i- g7 ], U( J7 {" b
  8. }
    ( v6 z: b; [0 ?

  9. ' |1 K+ x8 l$ Q& I9 E) ^
  10. // 创建根实例
    # j- X9 v) T. u9 F
  11. new Vue({
    8 d8 y' v. ^8 c2 B, Z
  12.   el: '#app',! V* R4 @' e, \8 E4 k# p( P
  13.   components: {
    7 e4 i1 f) C+ f" f) r& ~
  14.     // <runoob> 将只在父模板可用
    ( y& H% X2 \8 @/ O5 S9 l+ J
  15.     'runoob': Child
    8 e2 p4 l& u+ L; w
  16.   }' }: Z5 }1 y0 _8 x, }
  17. })+ k, B1 x  s- O+ D" h& T1 v
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
$ Y8 |! @6 w& S: n, \3 @: g* T
  1. <div id="app">" Q+ I- O/ y# N% I( J2 h$ y* N
  2.     <child message="hello!"></child>
    : v/ _# o3 z: N6 B  H5 V7 a" B( L
  3. </div>8 Z6 a& g  t  i4 L% l& e8 P
  4. 5 Y- L- L" k/ o# R( I0 f5 R
  5. <script>$ u0 X- e6 K3 I. r/ m, h4 x
  6. // 注册/ g) R1 v4 W( X/ \- R6 L7 t
  7. Vue.component('child', {
    $ D; p+ ?4 n: @  e% y+ ]. r' B
  8.   // 声明 props
    0 `3 H: J3 t" s/ B" y4 W. |
  9.   props: ['message'],
    0 X0 _5 e- F( F1 Z
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    8 o6 g+ H! [! [( M+ T  j. V' r
  11.   template: '<span>{{ message }}</span>'
    $ m* Z8 t9 T( u
  12. })  g( i) I( R% v' J7 e5 T  S
  13. // 创建根实例! W6 p6 O9 t1 z
  14. new Vue({) e2 G- N8 c  G" t
  15.   el: '#app'4 ]( D, \, c. K" z6 s% o
  16. })
    7 B$ ?7 q3 c& S: b, e% z
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
; @# s: g9 D1 Q0 {3 I+ A0 Y% b, Y
  1. <div id="app">' {/ @( g5 ?# W3 R) P! K
  2.     <div>
    * C0 ~# N6 k% n, {' L8 w0 ?! q
  3.       <input v-model="parentMsg">
    4 n5 ?5 }) d! k
  4.       <br>* N4 E, e7 r( p4 w$ A/ |2 ^
  5.       <child v-bind:message="parentMsg"></child>+ C# ?1 M4 o( u
  6.     </div>
    % z# i* g4 M, P, H  k; N
  7. </div>
    & }3 w0 v6 j' M2 n2 |

  8. ( \  c2 c  f# s
  9. <script>
    % e3 Q  J  e. Y. ~
  10. // 注册
    1 B1 r/ r7 d8 y' ~" j
  11. Vue.component('child', {
    7 u3 O; m% U  e
  12.   // 声明 props
    : Z0 H3 v- a; b! x5 G  H
  13.   props: ['message'],
    / T/ m( k) K; \7 j+ D8 ]' b
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ) q( w6 t0 L: V$ f9 T' \$ B6 R; Q
  15.   template: '<span>{{ message }}</span>'6 t, c7 _. ?9 c0 Z* ^5 V
  16. }). ~9 u" @! |  v- n/ w8 s& z
  17. // 创建根实例( ~# Q( V( c5 z- v& i3 ~& i0 `* l7 N
  18. new Vue({
    " y! o# H0 Y& f4 Z' X( T
  19.   el: '#app',
    ) G+ d+ ?! u6 N4 d$ R
  20.   data: {
    ; ~) k9 x" Z% g9 r; C
  21.     parentMsg: '父组件内容'8 @) c% J& D  p$ |! o! B
  22.   }6 d8 W, j- l0 C. R2 {
  23. }); D2 M) t0 ~6 F1 X2 g
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例4 h4 p. A% W; U) u; a7 a0 ^
  1. <div id="app">
    7 e6 Q7 {. F- s4 C3 |2 R
  2.     <ol>
    . U" y" j. n/ B9 B7 H
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>  `+ t8 G) O# q) N7 c, S! }) G0 L9 K. `6 n
  4.       </ol>
    - z* O" W9 R* j, c1 W5 w
  5. </div>: H: [" P" @/ E/ d/ W9 }

  6. ' e, o8 A- |. U+ ?# A% T
  7. <script>* K7 G$ V$ I( [' P
  8. Vue.component('todo-item', {
    0 |1 C$ Q5 `  D  h
  9.   props: ['todo'],
    # ^6 b' }# Z/ Z; e9 E  p1 M
  10.   template: '<li>{{ todo.text }}</li>'5 C2 t  V% H# g! k
  11. })% C; o: V/ d) O
  12. new Vue({
    : A" @8 d: u' s  x  ]$ J8 T, W
  13.   el: '#app',
    % R0 v8 l! J3 u
  14.   data: {
    ; n  @4 y/ C  y% y, M, c( B
  15.     sites: [
    7 u" L0 R9 H) _* j
  16.       { text: 'Runoob' },
    3 w7 _( N; o  V4 d* K% b' @0 }
  17.       { text: 'Google' },
    - ?5 M; r/ V2 j0 d. `4 R; b
  18.       { text: 'Taobao' }
    8 Z* J7 y: w2 l3 W
  19.     ]( h, w% h) U, F7 J8 o3 q
  20.   }2 T( d3 H) |# R* y9 p' M
  21. }); G, D9 B& y) T9 i2 \- [& L+ n
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    ( P: q$ I  {+ H5 V8 ^- m8 @) u
  2.   props: {7 t7 y+ j3 T( J. [3 c" j
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)7 G9 @$ C+ d/ @4 ?+ G- N8 r
  4.     propA: Number,
    ) @- H* q% O  i. S  s' B
  5.     // 多种类型
    9 }  I& u2 D6 B' F  F
  6.     propB: [String, Number],
    ' U; l* T( F4 a7 t
  7.     // 必传且是字符串$ ?# w$ M1 \% R7 _! W% a
  8.     propC: {$ o- I# T! h# x
  9.       type: String,3 C2 K2 m  F/ \* r7 X$ }* @4 x
  10.       required: true
    ( k) R  x1 Y4 a( ?* H% ?4 P% V+ s
  11.     },
    & \; {- e- w- ~& L' O  n
  12.     // 数字,有默认值
    2 }+ B# O5 B/ {' M
  13.     propD: {
    & h; s& J& G! X/ {6 b
  14.       type: Number,7 A! u) N" i7 e$ A& w" K( R( E# P
  15.       default: 100
    & U+ |7 Z. X7 m
  16.     },
    ) x. `- ]% @8 f% n: ^
  17.     // 数组/对象的默认值应当由一个工厂函数返回! ^0 W  u1 Y$ C9 d; N7 [
  18.     propE: {
    - C8 H+ a5 @/ R$ C; K  Z; n
  19.       type: Object,, t! M7 C- \% v: R  ?- H& f) K
  20.       default: function () {1 J$ Q, F: L2 {) K
  21.         return { message: 'hello' }
    : s$ w1 ^4 e, m$ J& b
  22.       }
    $ G) [+ ?: [5 c* p% V/ L
  23.     },
    4 M  c7 v) w8 Q9 ?9 u
  24.     // 自定义验证函数+ X  q* Z* X4 M' M0 p
  25.     propF: {
    ' p9 \7 @# f- j, J( L! k3 p
  26.       validator: function (value) {
    7 E5 ]5 c! W6 q0 w+ n! t1 O  M
  27.         return value > 10, c% b' h8 O  e3 E2 v$ P( K2 c
  28.       }
    ; q9 z  r4 K( N2 a) E
  29.     }: s, r8 S1 ~: F% x" z
  30.   }1 v% ~$ [  f* N$ w
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array6 B4 L- u  g" E( z5 x6 [
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    $ I; D& f6 w( V
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
. ^' m. F: c0 O
  1. <div id="app">  m8 c0 A/ ^/ j6 `3 [4 N' o; i
  2.     <div id="counter-event-example">* h7 U, S7 H5 q, e; }
  3.       <p>{{ total }}</p>; r+ D6 I; k) n8 [/ P" F
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    : O; L) E% ]+ u' A3 Q
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>
    . W) Q8 u" ~9 ?8 M+ h' G6 I: s
  6.     </div>' e  q: X1 ~1 f" h9 }3 \# F
  7. </div>+ C9 n" W5 b/ Q1 Z& i) _, ?5 R
  8. 1 i# [2 \9 o8 p
  9. <script>! _" D" Y! S$ H6 A+ [8 V# ?" I
  10. Vue.component('button-counter', {$ s0 ~" h0 T; s% K4 \
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    $ w$ {2 Q6 O  Y! ^( v8 r
  12.   data: function () {' d/ n1 U. e/ t" W3 k
  13.     return {
      C2 @* r2 H) ~  o# z
  14.       counter: 0
    , y6 W# F- c; }1 {, v
  15.     }* Q0 O$ a5 P; D! w: S3 I. M- w
  16.   },
    + u' J" {1 e0 h* j9 P& ]% j
  17.   methods: {
    " e, d$ v4 ~3 ]0 w% F6 ^; d
  18.     incrementHandler: function () {
    % l" J. @4 r* I% w9 M" {
  19.       this.counter += 1
    % U, i. n' c8 h1 D+ Z
  20.       this.$emit('increment')
    0 {- [, E2 e8 Z9 V) V
  21.     }! W$ ^- H6 S/ s6 Y) F( `  q  Y" H( O
  22.   },
    6 N: ?0 U$ j" i& n
  23. })
    * R  C# q7 C* P! I; r
  24. new Vue({
    - v# m, M* T# Z
  25.   el: '#counter-event-example',
    8 B- K4 T* s; N( A5 u0 [& W4 M
  26.   data: {
    - O- g/ B7 O4 ^
  27.     total: 0% J( B- c! K5 Q8 Y$ u' |
  28.   },& z- E) Y$ T  s3 m% o
  29.   methods: {
      W6 h8 |$ Z7 Z( p1 q& D9 |
  30.     incrementTotal: function () {
    3 c2 m6 D/ L3 T% r+ J6 p& M; P
  31.       this.total += 1
    9 {  o+ I& i2 D+ |: D; d
  32.     }
    4 w$ X* M, {9 K* g+ j: W3 {
  33.   }
    ' V: J, E7 O* f# u: [- E
  34. })
    + \. @1 O3 p8 L6 G( i
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    6 t- O0 c" I5 r; q' b
  2. Vue.component('child', {* _+ u* w5 R+ n' {! O7 R
  3.   // 声明 props
    & D1 {: ?* t) L
  4.   props: ['message'],$ w% F1 `9 d  t* ~# g1 q: b+ V/ g
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用0 P; g% Q% K7 t& h+ X! K
  6.   template: '<span>{{ message }}</span>'
    0 {  p+ f3 q. B( G* r8 _
  7. })
    $ E) W; _) d2 Z- z9 s4 t
  8. // 创建根实例& p; [7 j4 k2 i8 R  t
  9. new Vue({
    $ n6 g* _% g4 u3 E
  10.   el: '#app',: x8 ^0 F* i# e% J/ O
  11.   data:{
    1 @+ B; W8 F) z, t1 g
  12.     message:"hello",
    ( @. N. K1 j- A8 y
  13.   }
    % w1 M# d% Y+ p( ?% j! H9 }
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {9 m3 E0 `+ w* Z/ Q& ]) c
  2.     incrementHandler: function (v) {  Y% C; c$ x, W! E
  3.         if(v==1){
    2 L3 n1 J3 v4 a* S+ L9 |0 L2 B
  4.             this.counter -= 1
    5 M- A# X$ a8 V1 _: a% v
  5.             this.$emit('increment',[1])' _2 S3 P# j7 V9 b2 @% \6 f  _, q
  6.         }else{, e; i- [3 S6 D4 a# d% [1 ?
  7.             this.counter += 1
    / {8 c' o" T" R' x# B5 J
  8.             this.$emit('increment',[2])& h- @  W( }- L) G- `: ~1 M
  9.         }
    2 ~" I4 U4 x, d8 p
  10.     }1 n6 E* ]; R+ j) z
  11. }
复制代码

& s3 ?  K+ J' L) e+ u& e5 C- A5 U; x& n7 p+ P& K
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-20 04:14 , Processed in 0.073775 second(s), 22 queries .

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