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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

8 `3 n0 E4 ^2 V: i0 z2 S7 l
  1. <div id="app">0 I$ K. |* `2 h: }. x$ x. F; k1 T
  2.     <runoob></runoob>
    # l8 Q7 N$ R. a- F$ p- \
  3. </div>
    . P* Y1 U9 {5 d9 q* O- ?1 b& G
  4.   C7 S8 f) M2 M+ Y* j! @$ x2 u
  5. <script>: G% n5 f/ S" \8 ?( F
  6. // 注册: f8 K7 _; Y* _
  7. Vue.component('runoob', {
    $ p6 f& t6 l- O4 f$ p- p! U
  8.   template: '<h1>自定义组件!</h1>'
    , J/ H$ I- V+ |; S& p2 r# G' ^' l
  9. })( R) s7 |" U- N
  10. // 创建根实例& B% I; k4 s, ^* W4 |3 [/ M
  11. new Vue({. c9 ]3 Q% S; @2 F% |
  12.   el: '#app'
    8 _5 V6 Z  w. i; O( _% c5 h! {' V8 H
  13. })5 b% M5 U8 o. u  k9 ^# s: _1 T
  14. </script>
复制代码
局部组件
我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
局部组件实例
注册一个简单的局部组件 runoob,并使用它:
- T4 N- `4 ]" ^4 ~, W
  1. <div id="app">1 H7 C2 o2 n' s# w$ f
  2.     <runoob></runoob>
    2 o  n9 l* j9 D5 e' g$ M
  3. </div>" D3 W+ n! l9 O1 F( X

  4. , J" s5 T/ U2 {( V
  5. <script>* T! V. P+ \* q" u
  6. var Child = {
    # e! e, s; G; V! Z
  7.   template: '<h1>自定义组件!</h1>'7 h1 Q! W6 |! E7 `
  8. }$ z  P, [/ E6 k0 a! L
  9. , F3 e* v2 T/ u7 W* R& H4 [) C
  10. // 创建根实例/ z0 j/ ~) O4 _8 k# `
  11. new Vue({
    % y- j; w9 E. F, T! `
  12.   el: '#app',
    7 H# U$ [" r; G6 Q, m- x
  13.   components: {' Z; _: T% a$ u/ ?6 Q7 c
  14.     // <runoob> 将只在父模板可用" f! f6 v2 B( A0 y1 S- G6 ~) {+ z
  15.     'runoob': Child! y; @' n" Q: B! D0 W
  16.   }
    ! w5 u/ j/ f# T' ]9 t. R3 R
  17. })( ~) P/ C# s2 G( u( Q$ ^& y- T
  18. </script>
复制代码
Prop
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
Prop 实例
8 p3 q8 ^- S9 D8 P# C3 m7 \6 p
  1. <div id="app">  H* I4 q2 k! p
  2.     <child message="hello!"></child>4 U( Q8 e: w5 x' m1 T
  3. </div>% ^! J5 S3 O" p9 Q

  4. 3 Y4 ?0 h" F) m& r' r
  5. <script>
    : {8 }$ M' O6 b( W- X
  6. // 注册
    ( l. H$ i+ ?$ H0 P3 T* ~
  7. Vue.component('child', {& C2 O7 e+ p- C" a( D
  8.   // 声明 props
    : ]1 }9 T) s% k3 c
  9.   props: ['message'],3 s! g3 c. g$ z
  10.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    ' Y9 m5 e: p. O! W" r
  11.   template: '<span>{{ message }}</span>'8 y) E1 p7 C7 y+ N3 q$ R( @. P
  12. })" a; ]% V. ]0 B& K  |2 G2 t
  13. // 创建根实例! |3 H5 g( Z" u4 S/ t
  14. new Vue({
    , E& A$ r* w  n" A1 c$ i
  15.   el: '#app'% _5 W1 y  k8 o3 L
  16. })$ q3 F* Y5 x) B6 ?$ _
  17. </script>
复制代码
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
Prop 实例. z* w. `# S* H0 ^
  1. <div id="app">
    ) I% Q6 t8 m6 ?2 g" b
  2.     <div>
    ( h( ]& M* x4 ^5 b8 o' g
  3.       <input v-model="parentMsg">
    * Y4 v, c' L2 l7 W" X+ @
  4.       <br>5 f2 g: z" R( j# f% M
  5.       <child v-bind:message="parentMsg"></child>0 W& b; K7 V3 |" J0 h
  6.     </div>/ h4 j1 d( f! u
  7. </div>
    ) u8 C6 i, U, \3 O' w& e  w, \

  8. : W" e/ u2 Q, z( I, X
  9. <script>9 |6 t- ~9 e& m
  10. // 注册
    0 F2 j6 X# c) L3 W! e
  11. Vue.component('child', {
    . }' R. F1 ^- N
  12.   // 声明 props* |4 y# u- a  Y2 n
  13.   props: ['message'],
    + I1 R$ `* c2 q
  14.   // 同样也可以在 vm 实例中像 "this.message" 这样使用
    # z# _5 D4 G! C' i9 N" X. a2 J) @: j4 e
  15.   template: '<span>{{ message }}</span>'
    5 |( p( r, {6 n# F% M' f
  16. })
    ! p  r5 s, H* c
  17. // 创建根实例
    4 l) l+ {3 _8 O2 p  `3 r
  18. new Vue({
    . C* t- I- r' M) u/ G
  19.   el: '#app',+ c; A& g; O# N( F4 C) R$ o/ k
  20.   data: {0 u& O- F4 l* P8 r; G5 s( L
  21.     parentMsg: '父组件内容'
      L: |2 g6 J: b+ X! q+ S+ u$ f4 Q) Z5 N
  22.   }
    + d/ }$ a1 A8 q! w, a3 |; `
  23. })6 p+ N6 u: @+ `' |" _* A
  24. </script>
复制代码
以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
Prop 实例
3 c  w: C) K+ o3 {- Q) a# Z
  1. <div id="app">3 |7 k. m  s3 j) q% O" j
  2.     <ol>9 d2 q! K$ H, w* _+ Z1 g
  3.     <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>) z. D% N8 @5 ^0 R8 L: x% O
  4.       </ol>
    , |* M2 I/ t7 N2 P
  5. </div>( S( ]  B) O9 v: U" e

  6. $ ]% f! q# Y  ?; {
  7. <script>
    9 e3 \! j( A7 G8 q0 }
  8. Vue.component('todo-item', {- C5 G$ o" h0 S
  9.   props: ['todo'],/ C# b0 C9 O- [
  10.   template: '<li>{{ todo.text }}</li>'+ X! [1 Q) Y# N3 |
  11. })1 |, {" ~6 }# S* g% ?2 C- D
  12. new Vue({/ P+ P+ V; n/ C$ p) z! @9 E7 }
  13.   el: '#app',
    5 V, t0 X+ t4 X/ Q  R. R
  14.   data: {
    4 X; L0 t7 ~  C  M5 {! f  ~
  15.     sites: [6 ?. q+ ]! i& |6 R& r- E, ^, [
  16.       { text: 'Runoob' },4 C. S' Y9 S6 c% @- I  r  [- I
  17.       { text: 'Google' },6 N- r" }  l/ n8 l  `8 s( A4 e
  18.       { text: 'Taobao' }
    * [& ^: @- }/ v
  19.     ]
    ) V: l2 m3 v7 N# q) _" I+ b
  20.   }
    1 A! T0 s; N* w2 a( i
  21. })
    0 D' L# E) x- N& ~, F) n
  22. </script>
复制代码
注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
Prop 验证
组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:
  1. Vue.component('example', {
    : R& n) a6 K3 N4 {4 Y/ A, o$ [
  2.   props: {
    & ]( @# R$ F  K! ]
  3.     // 基础类型检测 (`null` 意思是任何类型都可以); ]# v; S3 c7 z0 t* h4 W
  4.     propA: Number,
    * `3 @( u: K8 V* G& n6 u
  5.     // 多种类型/ V% u' J6 j2 `3 \
  6.     propB: [String, Number],, l8 v6 v5 L! s8 x/ O6 o
  7.     // 必传且是字符串
    ; E& t. c8 [1 T9 v; L
  8.     propC: {7 g1 z& \7 n" R( a9 v3 u
  9.       type: String,, w* s, Q$ H) [
  10.       required: true
    4 l( l' h8 Q* X! W( Z( G' M
  11.     },+ ^; {5 w" v( I! X
  12.     // 数字,有默认值
    ' g0 t' r; j& z1 j. q, D9 |
  13.     propD: {/ m* s5 U2 \+ c, W, w
  14.       type: Number,6 K/ K) ^/ o& `7 i2 N* Z" q' ~
  15.       default: 100
    $ H5 |9 w9 M0 }& X9 j
  16.     },, X, ?, h' n& N* ~) D8 L1 l
  17.     // 数组/对象的默认值应当由一个工厂函数返回
    * t4 J- G* V# h3 Y8 F
  18.     propE: {
    / U5 N/ e) R, k' ~) w
  19.       type: Object,
    . R; U" s0 d6 t0 Q) @: K
  20.       default: function () {
    & r# n  J: `1 w7 L( |: `0 G$ h
  21.         return { message: 'hello' }
    * C0 F) {- n, F% y
  22.       }1 c! _9 b# Q8 w* ^0 d) T
  23.     },8 b; q) c8 p" A% C/ {8 _
  24.     // 自定义验证函数& R* I0 L# E5 [+ I# \
  25.     propF: {
    & d: e. q$ S' `
  26.       validator: function (value) {
    + Q) q& O& z; ^- y
  27.         return value > 10
    $ d3 v9 {8 J- n* f5 F9 F& [7 V
  28.       }
    : _4 k$ T, l" U% ]9 E
  29.     }
    $ d. m/ E4 j/ N& T: o3 u# z3 P) v
  30.   }6 G- ]  [, v/ h+ \
  31. })
复制代码
type 可以是下面原生构造器:
  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array% [% D$ m9 `7 o) _. `( S
type 也可以是一个自定义构造器,使用 instanceof 检测。

自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
    ' |& [% {' @7 K% C; v
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
实例
& l2 Y; B( i. w$ @
  1. <div id="app">
    3 k& ^+ e+ A2 D' x1 m
  2.     <div id="counter-event-example">' }. i1 L; ?7 H: \6 p& y2 E* R5 m
  3.       <p>{{ total }}</p>
    . D/ q- _8 r/ k
  4.       <button-counter v-on:increment="incrementTotal"></button-counter>
    ' l& R* u9 S6 Y  L( @% K! E
  5.       <button-counter v-on:increment="incrementTotal"></button-counter>8 Z# [# }; l" E9 z8 |/ l3 v
  6.     </div>8 p) M( Q+ e/ q) ^1 _7 n, E8 b
  7. </div>
    ( I5 i% ^2 Q8 }, ]4 e( k

  8. 1 f7 Q3 l0 M( O1 b: G) j+ c
  9. <script>) h1 B2 i/ \% W8 `" P
  10. Vue.component('button-counter', {
    / k0 o) U# W  [- Q# I4 s1 z
  11.   template: '<button v-on:click="incrementHandler">{{ counter }}</button>',% J( B: \% D. P; K, w$ |  y1 _
  12.   data: function () {
    ( p: O: l# o/ J% A
  13.     return {
    - `% p2 q) H) _
  14.       counter: 0
    ( d- n0 [7 T$ ?) _" N  e) A' r* \
  15.     }. q. u4 S7 l. X* U, l$ f
  16.   },8 V% w7 N6 g) R4 `
  17.   methods: {
    * M) w/ T" X5 {* W2 N
  18.     incrementHandler: function () {
    / R" _  ]6 m0 \' D- v, g- A/ T
  19.       this.counter += 1
    * ]9 ]% T1 \& X% C! M
  20.       this.$emit('increment')( P8 V8 }4 ]+ x
  21.     }
    ; R7 H5 e% Q3 T+ Z+ h( Q
  22.   },% Z' v7 x; H- \6 @$ S
  23. })2 e& w2 v6 o. ^
  24. new Vue({! z: p- d$ o: b5 Y
  25.   el: '#counter-event-example',
    6 [) ?3 L9 }4 Q7 L) l9 c* s
  26.   data: {
    9 e% q/ A. O  R
  27.     total: 0
    4 c( ?( ?6 n& ?0 z+ a2 o
  28.   },( H# ^4 ~  K2 {$ x* {$ \
  29.   methods: {: d* p. G/ r& ~$ U4 M
  30.     incrementTotal: function () {: H. V+ m, _: n) f
  31.       this.total += 1
    1 ]6 x4 l; K, v( w8 {9 v
  32.     }. ^9 i+ P9 q: U$ V) k
  33.   }
    ( }, Z  K' d% f8 T
  34. })
    + |2 R- \0 P* Y8 a+ d7 q* i
  35. </script>
复制代码
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
  1. <my-component v-on:click.native="doTheThing"></my-component>
复制代码
父组件给子组件传值的时候,如果想传入一个变量,写法如下:
  1. // 注册
    4 H% f/ V: I- a
  2. Vue.component('child', {
    3 e2 B, B$ w' B# n& f
  3.   // 声明 props; y$ W% |: D3 o
  4.   props: ['message'],
    $ J/ j" K; W5 A: x$ [) d
  5.   // 同样也可以在 vm 实例中像 "this.message" 这样使用( m! t& {* f3 T& ~
  6.   template: '<span>{{ message }}</span>'
    . L* r+ _% f9 a! w+ K1 P8 {& A
  7. })3 t; s# M( p( N6 E  u* Y
  8. // 创建根实例7 k( r/ d# K% {# U8 j" M! s
  9. new Vue({3 m1 f' |7 T2 f1 h2 Y: }* a8 y
  10.   el: '#app',
    6 P- l5 x7 F+ A* K/ i
  11.   data:{
    ' Q: O; q9 ]9 }4 Q
  12.     message:"hello",
    7 B$ V' c* k& U; t$ G8 i9 M
  13.   }! \5 V4 U  e% s" h& h5 S9 Q
  14. })
复制代码
子组件通过 $emit 触发父组件的方法时,如果需要传递参数,可在方法名后面加参数数组。
比如 $emit("FunctionName") 当要传递参数时 :$emit("FunctionName",[arg1,arg2...])。
  1. methods: {
    # |) q3 n7 V9 e/ m9 s3 l) C
  2.     incrementHandler: function (v) {
    3 H( j& H2 z3 F. d7 V5 c& F
  3.         if(v==1){3 C) x/ m: @) R+ x6 e
  4.             this.counter -= 1
    % K. X1 ?4 x! W4 t
  5.             this.$emit('increment',[1])
    / e) A6 R7 p) U% Y  V( u2 T7 k
  6.         }else{! p, A: V# [: N- O7 q/ y
  7.             this.counter += 1
    ; t2 Z5 X+ K1 i5 ?  N& u
  8.             this.$emit('increment',[2])
    8 m/ o3 k4 K* e, w( C5 R
  9.         }1 W7 a1 N/ F4 d9 g& |
  10.     }5 _9 ]' L  @( S1 F) {
  11. }
复制代码

+ \, f# l& |5 V/ u+ Z7 v: ?% O* o- C' Z- c. q3 j5 D
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-17 20:17 , Processed in 0.064097 second(s), 23 queries .

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