SpringBoot 处理异常的几种常见姿式

![](https://oscimg.oschina.net/oscnet/8231bdeab4133d2c912740ef6f2a576094e.jpg)欢迎你们关注微信公众号

vue是数据驱动视图更新的框架, 因此对于vue来讲组件间的数据通讯很是重要,那么组件之间如何进行数据通讯的呢?vue

首先咱们须要知道在vue中组件之间存在什么样的关系, 才更容易理解他们的通讯方式, 就好像过年回家,坐着一屋子的陌生人,相互之间怎么称呼,这时就须要先知道本身和他们之间是什么样的关系。程序员

vue组件中关系说明:vuex

如上图所示, A与B、A与C、B与D、C与E组件之间是父子关系; B与C之间是兄弟关系;A与D、A与E之间是隔代关系; D与E是堂兄关系(非直系亲属)api

针对以上关系咱们归类为:数组

  •  父子组件之间通讯
  •  非父子组件之间通讯(兄弟组件、隔代关系组件等)

本文会介绍组件间通讯的8种方式以下图目录所示:并介绍在不一样的场景下如何选择有效方式实现的组件间通讯方式,但愿能够帮助小伙伴们更好理解组件间的通讯。微信

1、props / $emitsession

父组件经过props的方式向子组件传递数据,而经过$emit 子组件能够向父组件通讯。app

1. 父组件向子组件传值框架

下面经过一个例子说明父组件如何向子组件传递数据:在子组件article.vue中如何获取父组件section.vue中的数据articles:['红楼梦', '西游记','三国演义']异步

  1. // section父组件  

  2. <template>  

  3.   <div class="section">  

  4.     <com-article :articles="articleList"></com-article>  

  5.   </div>  

  6. </template>  

  7. <script>  

  8. import comArticle from './test/article.vue'  

  9. export default {  

  10.   name: 'HelloWorld',  

  11.   components: { comArticle },  

  12.   data() {  

  13.     return {  

  14.       articleList: ['红楼梦', '西游记', '三国演义']  

  15.     }  

  16.   }  

  17. }  

  18. </script>  

  19. // 子组件 article.vue  

  20. <template>  

  21.   <div>  

  22.     <span v-for="(item, index) in articles" :key="index">{{item}}</span>  

  23.   </div>  

  24. </template>  

  25. <script>  

  26. export default {  

  27.   props: ['articles']  

  28. }  

  29. </script> 

总结: prop 只能够从上一级组件传递到下一级组件(父子组件),即所谓的单向数据流。并且 prop 只读,不可被修改,全部修改都会失效并警告。

2. 子组件向父组件传值

对于$emit 我本身的理解是这样的: $emit绑定一个自定义事件, 当这个语句被执行时, 就会将参数arg传递给父组件,父组件经过v-on监听并接收参数。 经过一个例子,说明子组件如何向父组件传递数据。

在上个例子的基础上, 点击页面渲染出来的ariticle的item, 父组件中显示在数组中的下标

  1. // 父组件中  

  2. <template>  

  3.   <div class="section">  

  4.     <com-article :articles="articleList" @onEmitIndex="onEmitIndex"></com-article>  

  5.     <p>{{currentIndex}}</p>  

  6.   </div>  

  7. </template>  

  8. <script>  

  9. import comArticle from './test/article.vue'  

  10. export default {  

  11.   name: 'HelloWorld',  

  12.   components: { comArticle },  

  13.   data() {  

  14.     return {  

  15.       currentIndex: -1,  

  16.       articleList: ['红楼梦', '西游记', '三国演义']  

  17.     }  

  18.   },  

  19.   methods: {  

  20.     onEmitIndex(idx) {  

  21.       this.currentIndex = idx  

  22.     }  

  23.   }  

  24. }  

  25. </script>  

  26. <template>  

  27.   <div>  

  28.     <div v-for="(item, index) in articles" :key="index" @click="emitIndex(index)">{{item}}</div>  

  29.   </div>  

  30. </template>  

  31. <script>  

  32. export default {  

  33.   props: ['articles'],  

  34.   methods: {  

  35.     emitIndex(index) {  

  36.       this.$emit('onEmitIndex', index)  

  37.     }  

  38.   }  

  39. }  

  40. </script> 

2、 $children / $parent

上面这张图片是vue官方的解释,经过$parent和$children就能够访问组件的实例,拿到实例表明什么?表明能够访问此组件的全部方法和data。接下来就是怎么实现拿到指定组件的实例。

使用方法

  1. // 父组件中  

  2. <template>  

  3.   <div class="hello_world">  

  4.     <div>{{msg}}</div>  

  5.     <com-a></com-a>  

  6.     <button @click="changeA">点击改变子组件值</button>  

  7.   </div>  

  8. </template>  

  9. <script>  

  10. import ComA from './test/comA.vue'  

  11. export default {  

  12.   name: 'HelloWorld',  

  13.   components: { ComA },  

  14.   data() {  

  15.     return {  

  16.       msg: 'Welcome'  

  17.     }  

  18.   },  

  19.   methods: {  

  20.     changeA() {  

  21.       // 获取到子组件A  

  22.       this.$children[0].messageA = 'this is new value'  

  23.     }  

  24.   }  

  25. }  

  26. </script>  

  27. // 子组件中  

  28. <template>  

  29.   <div class="com_a">  

  30.     <span>{{messageA}}</span>  

  31.     <p>获取父组件的值为:  {{parentVal}}</p>  

  32.   </div>  

  33. </template>  

  34. <script>  

  35. export default {  

  36.   data() {  

  37.     return {  

  38.       messageA: 'this is old'  

  39.     }  

  40.   },  

  41.   computed:{  

  42.     parentVal(){  

  43.       return this.$parent.msg;  

  44.     }  

  45.   }  

  46. }  

  47. </script> 

要注意边界状况,如在#app上拿$parent获得的是new Vue()的实例,在这实例上再拿$parent获得的是undefined,而在最底层的子组件拿$children是个空数组。也要注意获得$parent和$children的值不同,$children 的值是数组,而$parent是个对象

总结

上面两种方式用于父子组件之间的通讯, 而使用props进行父子组件通讯更加广泛; 两者皆不能用于非父子组件之间的通讯。

3、provide/ inject

概念:

provide/ inject 是vue2.2.0新增的api, 简单来讲就是父组件中经过provide来提供变量, 而后再子组件中经过inject来注入变量。

注意: 这里不论子组件嵌套有多深, 只要调用了inject 那么就能够注入provide中的数据,而不局限于只能从当前父组件的props属性中回去数据

举例验证

接下来就用一个例子来验证上面的描述:

假设有三个组件: A.vue、B.vue、C.vue 其中 C是B的子组件,B是A的子组件

  1. // A.vue  

  2. <template>  

  3.   <div>  

  4.     <comB></comB>  

  5.   </div>  

  6. </template>  

  7. <script>  

  8.   import comB from '../components/test/comB.vue'  

  9.   export default {  

  10.     name: "A",  

  11.     provide: {  

  12.       for: "demo"  

  13.     },  

  14.     components:{  

  15.       comB  

  16.     }  

  17.   }  

  18. </script>  

  19. // B.vue  

  20. <template>  

  21.   <div>  

  22.     {{demo}}  

  23.     <comC></comC>  

  24.   </div>  

  25. </template>  

  26. <script>  

  27.   import comC from '../components/test/comC.vue'  

  28.   export default {  

  29.     name: "B",  

  30.     inject: ['for'],  

  31.     data() {  

  32.       return {  

  33.         demo: this.for  

  34.       }  

  35.     },  

  36.     components: {  

  37.       comC  

  38.     }  

  39.   }  

  40. </script>  

  41. // C.vue  

  42. <template>  

  43.   <div>  

  44.     {{demo}} 

  45.   </div>  

  46. </template>  

  47. <script>  

  48.   export default {  

  49.     name: "C",  

  50.     inject: ['for'],  

  51.     data() {  

  52.       return {  

  53.         demo: this.for  

  54.       }  

  55.     }  

  56.   }  

  57. </script> 

4、ref / refs

ref:若是在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;若是用在子组件上,引用就指向组件实例,能够经过实例直接调用组件的方法或访问数据, 咱们看一个ref 来访问组件的例子:

  1. // 子组件 A.vue  

  2. export default {  

  3.   data () {  

  4.     return {  

  5.       name: 'Vue.js'  

  6.     }  

  7.   },  

  8.   methods: {  

  9.     sayHello () {  

  10.       console.log('hello')  

  11.     }  

  12.   }  

  13. }  

  14. // 父组件 app.vue  

  15. <template>  

  16.   <component-a ref="comA"></component-a>  

  17. </template>  

  18. <script>  

  19.   export default {  

  20.     mounted () {  

  21.       const comA = this.$refs.comA;  

  22.       console.log(comA.name);  // Vue.js  

  23.       comA.sayHello();  // hello  

  24.     }  

  25.   }  

  26. </script> 

5、eventBus

eventBus 又称为事件总线,在vue中可使用它来做为沟通桥梁的概念, 就像是全部组件共用相同的事件中心,能够向该中心注册发送事件或接收事件, 因此组件均可以通知其余组件。

eventBus也有不方便之处, 当项目较大,就容易形成难以维护的灾难

在Vue的项目中怎么使用eventBus来实现组件之间的数据通讯呢?具体经过下面几个步骤

1. 初始化

首先须要建立一个事件总线并将其导出, 以便其余模块可使用或者监听它.

  1. // event-bus.js  
  2. import Vue from 'vue'  
  3. export const EventBus = new Vue() 

2. 发送事件

假设你有两个组件: additionNum 和 showNum, 这两个组件能够是兄弟组件也能够是父子组件;这里咱们以兄弟组件为例:

  1. <template>  

  2.   <div>  

  3.     <show-num-com></show-num-com>  

  4.     <addition-num-com></addition-num-com>  

  5.   </div>  

  6. </template>  

  7. <script>  

  8. import showNumCom from './showNum.vue'  

  9. import additionNumCom from './additionNum.vue'  

  10. export default {  

  11.   components: { showNumCom, additionNumCom }  

  12. }  

  13. </script>  

  14. // addtionNum.vue 中发送事件  

  15. <template>  

  16.   <div>  

  17.     <button @click="additionHandle">+加法器</button>      

  18.   </div>  

  19. </template>  

  20. <script>  

  21. import {EventBus} from './event-bus.js'  

  22. console.log(EventBus)  

  23. export default {  

  24.   data(){  

  25.     return{  

  26.       num:1  

  27.     }  

  28.   },  

  29.   methods:{  

  30.     additionHandle(){  

  31.       EventBus.$emit('addition', {  

  32.         num:this.num++  

  33.       })  

  34.     }  

  35.   }  

  36. }  

  37. </script> 

3. 接收事件

  1. // showNum.vue 中接收事件  
  2. <template>  
  3.   <div>计算和: {{count}}</div>  
  4. </template>  
  5. <script>  

  6. import { EventBus } from './event-bus.js'  
  7. export default {  
  8.   data() {  
  9.     return {  
  10.       count: 0  
  11.     }  
  12.   },  
  13.   mounted() {  
  14.     EventBus.$on('addition', param => {  
  15.       thisthis.count = this.count + param.num;  
  16.     })  
  17.   }  
  18. }  
  19. </script> 

这样就实现了在组件addtionNum.vue中点击相加按钮, 在showNum.vue中利用传递来的 num 展现求和的结果.

4. 移除事件监听者

若是想移除事件的监听, 能够像下面这样操做:

  1. import { eventBus } from 'event-bus.js'  
  2. EventBus.$off('addition', {}) 

6、Vuex

1. Vuex介绍

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的全部组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化.

Vuex 解决了多个视图依赖于同一状态和来自不一样视图的行为须要变动同一状态的问题,将开发者的精力聚焦于数据的更新而不是数据在组件之间的传递上

2. Vuex各个模块

  1.  state:用于数据的存储,是store中的惟一数据源
  2.  getters:如vue中的计算属性同样,基于state数据的二次包装,经常使用于数据的筛选和多个数据的相关性计算
  3.  mutations:相似函数,改变state数据的惟一途径,且不能用于处理异步事件
  4.  actions:相似于mutation,用于提交mutation来改变状态,而不直接变动状态,能够包含任意异步操做
  5.  modules:相似于命名空间,用于项目中将各个模块的状态分开定义和操做,便于维护

3. Vuex实例应用

  1. // 父组件  

  2. <template>  

  3.   <div id="app">  

  4.     <ChildA/>  

  5.     <ChildB/>  

  6.   </div>  

  7. </template>  

  8. <script>  

  9.   import ChildA from './components/ChildA' // 导入A组件  

  10.   import ChildB from './components/ChildB' // 导入B组件  

  11.   export default {  

  12.     name: 'App',  

  13.     components: {ChildA, ChildB} // 注册A、B组件  

  14.   }  

  15. </script>  

  16. // 子组件childA  

  17. <template>  

  18.   <div id="childA">  

  19.     <h1>我是A组件</h1>  

  20.     <button @click="transform">点我让B组件接收到数据</button>  

  21.     <p>由于你点了B,因此个人信息发生了变化:{{BMessage}}</p>  

  22.   </div>  

  23. </template>  

  24. <script>  

  25.   export default {  

  26.     data() {  

  27.       return {  

  28.         AMessage: 'Hello,B组件,我是A组件'  

  29.       }  

  30.     },  

  31.     computed: {  

  32.       BMessage() {  

  33.         // 这里存储从store里获取的B组件的数据  

  34.         return this.$store.state.BMsg  

  35.       }  

  36.     },  

  37.     methods: {  

  38.       transform() {  

  39.         // 触发receiveAMsg,将A组件的数据存放到store里去  

  40.         this.$store.commit('receiveAMsg', {  

  41.           AMsg: this.AMessage  

  42.         })  

  43.       }  

  44.     }  

  45.   }  

  46. </script>  

  47. // 子组件 childB  

  48. <template>  

  49.   <div id="childB">  

  50.     <h1>我是B组件</h1>  

  51.     <button @click="transform">点我让A组件接收到数据</button>  

  52.     <p>由于你点了A,因此个人信息发生了变化:{{AMessage}}</p>  

  53.   </div>  

  54. </template>  

  55. <script>  

  56.   export default {  

  57.     data() {  

  58.       return {  

  59.         BMessage: 'Hello,A组件,我是B组件'  

  60.       }  

  61.     },  

  62.     computed: {  

  63.       AMessage() {  

  64.         // 这里存储从store里获取的A组件的数据  

  65.         return this.$store.state.AMsg  

  66.       }  

  67.     },  

  68.     methods: {  

  69.       transform() {  

  70.         // 触发receiveBMsg,将B组件的数据存放到store里去  

  71.         this.$store.commit('receiveBMsg', {  

  72.           BMsg: this.BMessage  

  73.         })  

  74.       }  

  75.     }  

  76.   }  

  77. </script> 

vuex的store,js

  1. import Vue from 'vue'  
  2. import Vuex from 'vuex'  
  3. Vue.use(Vuex)  
  4. const state = {  
  5.   // 初始化A和B组件的数据,等待获取  
  6.   AMsg: '',  
  7.   BMsg: ''  
  8. }  
  9. const mutations = {  
  10.   receiveAMsg(state, payload) {  
  11.     // 将A组件的数据存放于state  
  12.     state.AMsg = payload.AMsg  
  13.   },  
  14.   receiveBMsg(state, payload) {  
  15.     // 将B组件的数据存放于state  
  16.     state.BMsg = payload.BMsg  
  17.   }  
  18. }  
  19. export default new Vuex.Store({  
  20.   state,  
  21.   mutations  
  22. }) 

7、 localStorage / sessionStorage

这种通讯比较简单,缺点是数据和状态比较混乱,不太容易维护。

经过window.localStorage.getItem(key) 获取数据

经过window.localStorage.setItem(key,value) 存储数据

注意用JSON.parse() / JSON.stringify() 作数据格式转换

localStorage / sessionStorage能够结合vuex, 实现数据的持久保存,同时使用vuex解决数据和状态混乱问题.

八 $attrs与 $listeners

如今咱们来讨论一种状况, 咱们一开始给出的组件关系图中A组件与D组件是隔代关系, 那它们以前进行通讯有哪些方式呢?

  1.  使用props绑定来进行一级一级的信息传递, 若是D组件中状态改变须要传递数据给A, 使用事件系统一级级往上传递
  2.  使用eventBus,这种状况下仍是比较适合使用, 可是碰到多人合做开发时, 代码维护性较低, 可读性也低
  3.  使用Vuex来进行数据管理, 可是若是仅仅是传递数据, 而不作中间处理,使用Vuex处理感受有点大材小用了.

在vue2.4中,为了解决该需求,引入了$attrs 和$listeners , 新增了inheritAttrs 选项。 在版本2.4之前,默认状况下,父做用域中不做为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外),将会“回退”且做为普通的HTML特性应用在子组件的根元素上。接下来看一个跨级通讯的例子:

  1. // app.vue  

  2. // index.vue  

  3. <template>  

  4.   <div>  

  5.     <child-com1  

  6.       :name="name"  

  7.       :age="age"  

  8.       :gender="gender"  

  9.       :height="height"  

  10.       title="程序员成长指北"  

  11.     ></child-com1>  

  12.   </div>  

  13. </template>  

  14. <script>  

  15. const childCom1 = () => import("./childCom1.vue");  

  16. export default {  

  17.   components: { childCom1 },  

  18.   data() {  

  19.     return {  

  20.       name: "zhang",  

  21.       age: "18",  

  22.       gender: "女",  

  23.       height: "158"  

  24.     };  

  25.   }  

  26. };  

  27. </script>  

  28. // childCom1.vue  

  29. <template class="border">  

  30.   <div>  

  31.     <p>name: {{ name}}</p>  

  32.     <p>childCom1的$attrs: {{ $attrs }}</p>  

  33.     <child-com2 v-bind="$attrs"></child-com2>  

  34.   </div>  

  35. </template>  

  36. <script>  

  37. const childCom2 = () => import("./childCom2.vue");  

  38. export default {  

  39.   components: {  

  40.     childCom2  

  41.   },  

  42.   inheritAttrs: false, // 能够关闭自动挂载到组件根元素上的没有在props声明的属性  

  43.   props: {  

  44.     name: String // name做为props属性绑定  

  45.   },  

  46.   created() {  

  47.     console.log(this.$attrs);  

  48.      // { "age": "18", "gender": "女", "height": "158", "title": "程序员成长指北" }  

  49.   }  

  50. };  

  51. </script>  

  52. // childCom2.vue  

  53. <template>  

  54.   <div class="border">  

  55.     <p>age: {{ age}}</p>  

  56.     <p>childCom2: {{ $attrs }}</p>  

  57.   </div>  

  58. </template>  

  59. <script>  

  60. export default {  

  61.   inheritAttrs: false,  

  62.   props: {  

  63.     age: String  

  64.   },  

  65.   created() {  

  66.     console.log(this.$attrs);   

  67.     // { "gender": "女", "height": "158", "title": "程序员成长指北" }  

  68.   }  

  69. };  

  70. </script> 

总结

常见使用场景能够分为三类:

  •  父子组件通讯: props; $parent / $children; provide / inject ; ref ; $attrs / $listeners
  •  兄弟组件通讯: eventBus ; vuex
  •  跨级通讯: eventBus;Vuex;provide / inject 、$attrs / $listeners
相关文章
相关标签/搜索