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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

  E* T0 M: R6 {9 }# I
  1. <div id="app">
    & p9 q' u* P% V' r5 w2 l9 O$ [
  2.     <runoob></runoob>- x+ F, ^$ H: J9 g9 P! x* ?
  3. </div>2 D- A  j/ t: {9 T" {1 O

  4. - u# k* q" G- s, X( e: A- O4 i, L
  5. <script>3 l. p+ |1 Y7 t: L% z( z/ g3 @
  6. // 注册, V4 B( N/ H, E- c! S# O- S2 \* }8 f5 k9 q
  7. Vue.component('runoob', {
    2 v5 j2 ^9 a; m' B! H
  8.   template: '<h1>自定义组件!</h1>'
    6 v7 |' I! Q: [! K' `/ }6 h
  9. })2 m- @3 ]8 y8 K$ `
  10. // 创建根实例; d1 P( A. }9 B4 }* ?, l" l$ X9 W' K
  11. new Vue({
    ! m0 o  r: ]: \
  12.   el: '#app'
    5 ^$ y' }- T# X: G( ?
  13. })3 |7 p, i8 `5 `
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
* }' c: h4 o+ ^) [# p6 _
  1. <div id="app">
    - o0 O3 j: h$ Q% o- @: D4 g
  2.     <runoob></runoob>
    ' f7 A! m! o/ q# k+ v- W! o
  3. </div>* H8 B* r2 v4 h1 @4 q* s
  4. / T; v' N3 I% U9 H
  5. <script>
    ! Q# C; Q* l' G. j
  6. var Child = {
    ' b) ^" y1 H; A: f
  7.   template: '<h1>自定义组件!</h1>'4 G7 Y4 E- W3 [7 @& J
  8. }7 G: m! h- P2 l0 s
  9. : e9 t3 ?5 Q1 v: F5 e% E. e* u
  10. // 创建根实例
    . n' l$ R: M. N7 U
  11. new Vue({
    4 k' W5 c' j. W! k8 m
  12.   el: '#app',/ f  L  r( ?8 m$ h
  13.   components: {
    0 _: ~9 @0 r5 W$ p. }" \
  14.     // <runoob> 将只在父模板可用; S) [2 u2 @2 j4 A! m! c! P
  15.     'runoob': Child9 X- A$ z( K; C- a$ z& i$ O8 A9 {
  16.   }
    . Y5 q+ w8 Z4 j
  17. })
    9 L6 \: @+ z: A# v& h4 X1 ~
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例  w3 w& H/ Q# U# w  ~: O$ Y% `5 e
  1. <div id="app">
    : T& w# Z  S2 o) w( \, o
  2.     <child message="hello!"></child>2 A, U' V# x& l9 L% P7 F2 k1 a
  3. </div>
    * ]0 _; w$ }7 c/ O4 ]2 N/ w8 F# W

  4. 3 E* e; I" Y9 N" l3 Q3 ~/ t4 Z0 B; E
  5. <script>
    7 |' G9 q; L' T% Y4 |& ?. a  o' [
  6. // 注册
    . F8 ~: \" T- A* |, U
  7. Vue.component('child', {% K+ P) t/ ]* ?' T4 p8 X
  8.   // 声明 props
    $ ~6 w. q" m2 P$ g2 h
  9.   props: ['message'],: E: z# u2 z7 @% h, j5 f( N7 n
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    + z. ^  v5 a  u
  11.   template: '<span>{{ message }}</span>'
    ; u3 M. @/ l& W( L
  12. })- x- L) ~" T; y4 \( J# d
  13. // 创建根实例
    , ~, b  l: ]# @" k5 W9 P
  14. new Vue({
    1 \1 t8 V' Q" q2 A+ {- E' b
  15.   el: '#app'
    ) }, U/ u& ]8 e
  16. })" S9 `8 N8 w, h; I& r
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例
- J+ X, {8 R, a3 m, A9 x
  1. <div id="app">
    9 u* e, Y2 y! ^
  2.     <div>
    # I4 ]% y4 j( i6 F
  3.       <input v-model="parentMsg">! \1 Z1 O6 C/ Y( k: {7 I( x9 L$ [
  4.       <br>4 w( m* j+ n# s( g3 O! _
  5.       <child v-bind:message="parentMsg"></child>
    9 L  e3 g. j9 b* f! b& J' u
  6.     </div># V4 j0 N2 j& P$ s- z- h6 k
  7. </div>1 z9 n, Y/ e) L0 B9 Z3 v( N
  8. 6 t+ H3 H3 E( S' q, O! s# u
  9. <script>) U/ X' C% \  F8 o) b6 E6 s
  10. // 注册
    & `7 Y5 s+ |' x- l" c* W( h
  11. Vue.component('child', {
    9 j; D( J9 u5 E8 p9 ~4 m
  12.   // 声明 props2 ~$ d6 g. Z1 ~' p
  13.   props: ['message'],- C5 V" q9 E+ Y5 M; n+ ~7 B* k4 y
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    $ A0 O, V# [# L2 d4 o
  15.   template: '<span>{{ message }}</span>'
    " b# N1 z. H( G3 l$ ?( R  s
  16. })7 j' I) m  F6 R% g5 g# j* B9 Z) U
  17. // 创建根实例
    6 l. m$ B3 f' j+ Q* Z
  18. new Vue({
    3 v% ]/ O- y* L6 v
  19.   el: '#app',. j+ S$ c1 ^+ C5 s  F
  20.   data: {
    ' g8 z  r1 P( b
  21.     parentMsg: '父组件内容'
    # X4 R0 U' I2 b' N7 \
  22.   }
    ; |# Q  @# X0 b# n0 V
  23. })
    ( n# |8 S9 T4 u
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例4 v0 }* L5 Z8 }1 m6 V% f  Z4 n
  1. <div id="app">
    1 s% |! A5 W- b5 s$ ]# p# s$ j
  2.     <ol>
    ! @, k6 U$ @6 `1 z
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    % I! B2 ^) h8 y# k% V- e
  4.       </ol>  J* \' \& i! J9 N) s: h
  5. </div>
    , S: a1 j, A" a0 M/ y1 Q7 \0 X
  6. % [; h4 d! {1 Q& g3 `5 j# n) ]* ^
  7. <script>0 z4 `2 X5 O. l# ~
  8. Vue.component('todo-item', {; @, r% K0 W4 r; P+ p; B3 F
  9.   props: ['todo'],% _/ c* e4 U9 b/ r7 B& J3 T
  10.   template: '<li>{{ todo.text }}</li>'; C% n9 F3 c5 _
  11. })
    % e1 E( _9 y8 P% Z) t
  12. new Vue({
    - e" U2 }# s6 ~# F/ b7 C
  13.   el: '#app',8 \% ^/ b5 v3 F1 H/ s
  14.   data: {
    & o9 V7 s0 t" y, D# u, O
  15.     sites: [
    9 O# m0 Z5 K8 Q3 D! ~$ }4 O/ {
  16.       { text: 'Runoob' },
    3 n& `7 M! B1 i
  17.       { text: 'Google' },) g! c" k$ s0 U. B  p
  18.       { text: 'Taobao' }( p6 v! ?2 X( M& N/ [
  19.     ]
    : `" O1 \: J' R4 M* }
  20.   }
    % G  F8 C1 ]. U, R/ h0 `5 i* E
  21. })" |  _% |8 Z' D$ r$ e
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    ' t( S9 `: ?, N" L2 A( e! `7 H9 U
  2.   props: {  _) v; @, e8 m5 |
  3.     // 基础类型检测 (`null` 意思是任何类型都可以)8 I0 T7 K( [+ Q' p9 S# |8 L5 ?
  4.     propA: Number,( ^& J/ m! x/ W$ ?
  5.     // 多种类型0 o' z! i* i- \) V2 P3 J3 t
  6.     propB: [String, Number],( Z8 X9 x- g0 q5 B% ~/ y: [
  7.     // 必传且是字符串) R! s* H0 D4 i  x" G8 u
  8.     propC: {
    9 P! }, P" k1 v* S4 [  D. P
  9.       type: String,
    1 b) P* q# ?( C
  10.       required: true
    3 _8 V7 `3 S* Y0 C) g
  11.     },/ L6 G1 ~2 L0 N9 w
  12.     // 数字,有默认值
    : C3 H- [5 O4 s  F$ G' n4 a6 `
  13.     propD: {
    * A+ d& N9 n  a0 l
  14.       type: Number,$ j6 d& Z) _/ L4 B$ f9 O
  15.       default: 100
    . y, w+ l& H- t5 e( z) X  @
  16.     },; }2 j; H, G$ O
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    : T" z  Y- u* z4 L2 @
  18.     propE: {, s& |0 W$ g$ y  s
  19.       type: Object,2 C2 O5 ^7 Y: K& ]9 Z  a6 n5 ]
  20.       default: function () {& H7 M0 E0 E0 Y! Y6 Z! T
  21.         return { message: 'hello' }
    5 n6 D- c+ e2 j) ~6 \5 H2 Y
  22.       }( V1 M6 \( ]0 M2 v
  23.     }," S, Q% ~3 l6 J9 [7 H. l4 t( ?
  24.     // 自定义验证函数) j: ]  E) e7 m& b
  25.     propF: {
    3 v* H/ Q. U7 m3 @( G7 z
  26.       validator: function (value) {& C3 ?0 Y: X1 N1 u1 S# F* `: P
  27.         return value > 10
    , i$ L  d7 S- E, ]- u! C
  28.       }. z$ y/ t/ g% @8 p1 S/ ^
  29.     }
    5 U: M- Z/ x! F
  30.   }
      q* G- q0 j2 [8 r( ^' P
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
    : ^! {$ f. |0 X6 G6 o$ v
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件' L. G- ?' j" ^3 l0 a: \) D( P
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例' [  H% ^9 Q: _' G! O
  1. <div id="app">
    1 f. R# V0 B6 y: E, v, k. m
  2.     <div id="counter-event-example">
    ; _% U" V! z* h) B; J
  3.       <p>{{ total }}</p>% F. e7 l# ^" `* i% Z' J
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>" A1 v9 \6 ]( m2 ?* c2 E# e4 |) ~
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>; ?& j/ V8 O- e. r* ?1 N9 v
  6.     </div>9 u# w! K! f% N# w. E6 I1 d2 \0 a+ }
  7. </div>
    5 A: W1 F6 \- b- D2 s

  8. 2 H; K- u1 u3 S* _' M
  9. <script>
    2 d5 g& b9 r. v2 V& J% u$ X
  10. Vue.component('button-counter', {
    5 G0 S4 d8 A6 _( _  g5 R- G% U
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',' k4 p# V9 d1 p9 a9 o% W) Y
  12.   data: function () {$ D: Y; T0 ?5 u: H- K
  13.     return {
    0 w) d9 |8 H( S" a3 {
  14.       counter: 0
    # Q  u: W) Z) `1 a, c7 |: u
  15.     }
    5 Q( ^! f( F2 A# i. q
  16.   },
    4 C9 p; q; O9 @) W& x* r
  17.   methods: {
    3 x9 F% }: I! J5 w! C; w
  18.     incrementHandler: function () {
    2 g( j/ x6 p" n' e
  19.       this.counter += 1( y, g' }9 k' O6 |
  20.       this.$emit('increment')
    0 f5 P: D6 O3 W' }) P
  21.     }
    9 x! D/ B4 M* N0 Q" [4 e% G
  22.   },% N4 ]+ c, G5 S
  23. })8 S# w8 F) T- j7 y
  24. new Vue({8 d' H) ?, X: x1 I* r( V$ S
  25.   el: '#counter-event-example',
    : {' p5 f0 S1 ^5 T
  26.   data: {* J+ b) @1 N# H7 G
  27.     total: 0
    0 y" H, {) Y) e
  28.   },  k2 z/ ]1 U" m/ j/ Z3 g9 ?" ^% l: M
  29.   methods: {
    3 W# Q3 n: S" R# d5 ^  L3 E& k% s( P6 f( q
  30.     incrementTotal: function () {
    - C' e. {9 z$ U& I: w+ \, z
  31.       this.total += 1
    # E% O# |5 k. e) q8 ~
  32.     }( E7 p) c6 {& h  T! P
  33.   }; m3 ^: ?( L( W1 q* ?* m
  34. })
    ; g5 R- P1 q: T  C
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册' \/ n( s8 y# C8 T: K. ^% i  z
  2. Vue.component('child', {
    9 f, |+ O1 E/ ~" e, L; g: [
  3.   // 声明 props
    8 N: |, U* D) g/ B% S0 @& S
  4.   props: ['message'],
    0 S3 U% Y* F1 a) i! h% F1 @
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ( u$ n4 E. w* |" w0 a: J9 {* V
  6.   template: '<span>{{ message }}</span>'1 x8 [6 o5 q9 x* P6 E& i) n% x- u
  7. })& N* ^* i4 F9 F. n% q% f
  8. // 创建根实例
    - c- n4 A: l% V1 ^& _, h
  9. new Vue({
    ; E' q5 ^( @; F
  10.   el: '#app',
    " d. \3 }1 f$ L$ t
  11.   data:{" C  Q+ a8 q6 f1 c! _3 |9 `
  12.     message:"hello",
    5 v9 O" T( _) T0 M0 A+ ?
  13.   }
    3 e, N+ F2 f. I) p2 H; C
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {6 Y% A, |+ c" N8 T+ V
  2.     incrementHandler: function (v) {
      d/ l1 u' r) P- c* A1 l' a5 u
  3.         if(v==1){
    # \$ |, I/ S2 T4 Z
  4.             this.counter -= 1
    $ F$ N" v8 i) y2 `! Y- r1 U
  5.             this.$emit('increment',[1])
    9 O' n5 I% N4 y4 ^, k2 U
  6.         }else{" f: G3 |6 T( G' C, Z
  7.             this.counter += 1) N) f- S2 D+ {5 }5 I# _
  8.             this.$emit('increment',[2])0 P; X% A9 T" T
  9.         }2 k$ o7 h7 y2 _1 N5 Q
  10.     }
    3 u# z5 z* ^( v( |- x
  11. }
复制代码

9 i. g$ C" X+ W' E: R$ _1 l- H1 U3 u$ L
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-16 17:24 , Processed in 0.090560 second(s), 23 queries .

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