this.$parent获取不到父组件_vue6种组件通信优劣及应用场景

本文详细探讨了Vue中六种组件通信方式,包括prop、this.$parent、provide/inject、vuex、EventBus(两种实现)。分别阐述了它们的优缺点和适用场景,如prop适用于简单父子通信,vuex适合处理复杂组件通信,EventBus提供灵活的跨组件通信。选择哪种通信方式取决于业务需求和项目规模。
摘要由CSDN通过智能技术生成

acba47417502e713dec06b61d31cac4c.png

一 、prop

绑定:<son:fatherMes="sendSonMes" @sonSay="sonSay" />

触发:this.$emit("sonSay",data);

区别与react:react组件更新来源于props更新和自身state改变,当props改变,会默认更新组件。而在Vue中,如果我们对父组件传过来的新的props没有做依赖收集(template模版收集,computed计算属性收集),组件是不会触动更新的。

数据格式化:

   computed:{
       computedFatherMes(){
           return this.fatherMes + '  '
       }
   },

数据监听:当我们根据props改变不想更新视图,或者不想立即更新视图,那么可以用watch来监听来自父组件的props的变化

watch:{
    fatherMes(newVaule){
        console.log(  newVaule) 
    }
},

优点:灵活简单,可以对props数据进行计算属性,数据监听等处理。一层父组件通信方便

缺点

1 、props篡改

基础类型修改报错:

mounted:{ this.fatherMes= 'hello ,father' }

引用类型:子属性可被篡改

mounted:{ this.fatherMes.name= 'change father name from children' }

2 、跨层级通信,兄弟组件通讯困难

父组件-子组件-子组件的子组

父子-子孙通信:这种通信方式需要我们一层一层的prop绑定属性和方法,如果遇到更复杂的情况,实现起来比较困难。

实现子组件-> 父组件 -> 子组件

兄弟组件通信:如果想要通过父组件做媒介,那么必定会造成父组件重新渲染,为了实现兄弟组件通信付出的代价比较大。

应用场景:

正常不是嵌套很深的父子组件通信,和关系不是很复杂的兄弟组件组件通信。


二 、this.$xxx

组件和组件通过this.$childrenthis.$parent指针关联起来,

理论上,我们可以找到通过this.$childrenthis.$parent来访问页面上的任何一个组件 ,但是实际上如何精确匹配到目标组件,确是一个无比棘手的问题。

vue本身也不提倡这种通信方式。而且这种通信方式也有很多风险性

优点:更加的简单直接获取vue实例,对vue实例下的数据和方法直接获取或者引用。

缺点:

1、$this.children不可控性大,有一定风险(通过v-if改变组件状态,很容易出现调用错误)

这时可用ref获取对应子组件的实例

2 、不利于组件化

组件开发思路初衷,也不是由组件外部来对内部作出一定改变,而往往是内部的改变,通知外部绑定的方法事件。反过来如果是子组件内部,主动向父组件传递一些信息,也不能确定父组件是否存在。

3 、兄弟组件深层次嵌套组件通讯困难(向上或向下获取实例风险都会逐层加大)

应用场景

直接通过实例获取的通信方式适合已知的固定化的页面结构,这种方式更适合页面组件,而不适合一些第三方组件库,或者是公共组件


三 、provide inject

vueprovideinject和reactcontext 上下文两个作用一定程度十分相似,

// 父组件
provide(){        
      return {            /* 将自己暴露给子孙组件 ,这里声明的名称要于子组件引进的名称保持一致 */
           father:this        
      }    
},



/* 子组件中:引入父组件 */
   inject:['father'],

组件,插槽引入是一样的;

// 也可以暴露方法
   provide(){
       return {
           /* 将通信方法暴露给子孙组件(注意绑定this) */
           grandSonSay:this.grandSonSay.bind(this),
           sonSay:this.sonSay.bind(this)
       }
   },   
   methods:{
      /* 接受孙组件信息 */
      grandSonSay(value){
          this.grandSonMes = value
      },
      /* 接受子组件信息 */ 
      sonSay(value){
          this.sonMes = value
      },
   },

优点

e4eb8d9814241d8a8399efac28b035a6.png

1、适用于插槽,嵌套插槽

2、组件通信不受到子组件层级的影响

缺点:

1、不适合兄弟通讯

2、provide-inject协调作用就是获取父级组件们提供的状态,方法,属性等,流向一直都是由父到子,

3、父级组件无法主动通信

应用场景

provide-inject这种通信方式,更适合深层次的复杂的父子代通信,子孙组件可以共享父组件的状态,还有一点就是适合el-form el-form-item这种插槽类型的情景。


四 、vuex

vuex算是vue中处理复杂的组件通信的最佳方案

36dd9573a6a5772f54606d02a0f5f00a.png

vuex声明

import Vuex from 'vuex'
import Vue from 'vue'

Vue.use(Vuex)

export default new Vuex.Store({
    state:{
        fatherMes:'',
        sonMes:'',
        fatherMesAsync:''
    },
    mutations:{
       sayFaher(state,value){
           state.fatherMes = value
       },
       saySon(state,value){
           state.sonMes = value
       },
       sayAsyncFather(state,value){
           state.fatherMesAsync = value
       }
    },
    actions:{
       // 异步action
       asyncSayFather({ commit },payload){
           return new Promise((resolve)=>{
               setTimeout(()=>{
                   resolve(payload)
               },2000)
           }).then(res=>{
               commit('sayAsyncFather',res)
           })
       }
    }
})

main.js注入store

import store from './components/vuex/store'

new Vue({
  render: h => h(App),
  store
}).$mount('#app')

获取和改变store

computed:{
       sonMes(){
           return this.$store.state.sonMes
       }
   },
   mounted(){
       console.log(this.$store)
   },
   methods:{
      /* 触发mutations,传递数据给子组件 */
      send(){
        this.$store.commit('sayFaher',this.mes)
      },
      /* 触发actions,传递数据给子组件 */
      asyncSend(){
         this.$store.dispatch('asyncSayFather',this.asyncMes) 
      }
   },

优点:

根本解决复杂组件的通信问题

支持异步组件通信

vuexactions允许我们做一些异步操作,然后通过commit可以把数据传入对应的mutation,至于actions为什么可以执行异步,是因为里面底层通过Promise.resolve能够获取异步任务完成的状态。

缺点:

流程相比稍微复杂------不同的模块,需要建立独立的modules

应用场景:

vuex的出现,就是解决这些比较复杂的组件通信场景。对于中大型项目,vuex是很不错的状态管理,数据通信方案。


五 、事件总线一 EventBus

EventBus事件总线,EventBus所有事件统一调度,有一个统一管理事件中心,一个组件绑定事件,另一个组件触发事件,所有的组件通信不再收到父子组件的限制,那个页面需要数据,就绑定事件,然后由数据提供者触发对应的事件来提供数据

EventBus核心思想是事件的绑定和触发

废话少说,直接看代码

export default class EventBus {
    es = {}
     /* 绑定事件 */ 
    on(eventName, cb) {
        if (!this.es[eventName]) {
            this.es[eventName] = []
        }
        this.es[eventName].push({
            cb
        })
    }
    /* 触发事件 */
    emit(eventName, ...params) {
        const listeners = this.es[eventName] || []
        let l = listeners.length

        for (let i = 0; i < l; i++) {
            const { cb } = listeners[i]
            cb.apply(this, params)
        }
    }
}

export default new EventBus()

父组件

import EventBus from './eventBus'
export default {
   name:'father',
   components:{
       son ,/* 子组件 */
       brotherSon, /* 子组件 */
   },
   data(){
       return {
          mes:'',
          sonMes:''/* 发送给子组件的信息  */
       } 
   },
   mounted(){
      /* 绑定事件 */
      EventBus.on('sonSay',this.sonSay)
   },
   methods:{
      /* 传递给子组件 */
      send(){
          EventBus.emit('fatherSay',this.mes)
      },
      /* 接受子组件信息 */ 
      sonSay(value){
          this.sonMes = value
      },
   },
}

子组件

import EventBus from './eventBus' 
export default {
   name:'son',
   data(){
       return {
           mes:'',
           brotherMes:'',
           fatherMes:''
       }
   },
   mounted(){
       /* 绑定事件 */
       EventBus.on('fatherSay',this.fatherSay)
   },
   methods:{
       /* 向父组件传递信息 */
       send(){
          EventBus.emit('sonSay',this.mes)
       },
       /* 向兄弟组件传递信息 */
       sendBrother(){
          EventBus.emit('brotherSay',this.brotherMes)
       },
       /* 父组件对我说 */
       fatherSay(value){
          this.fatherMes = value
       }
   },
    
}

注意:兄弟组件处理逻辑和父子之间没什么区别

优点:

简单灵活,父子兄弟通信不受限制。

通信方式不受框架影响。

通过eventBus可以绕过渲染层,直接有逻辑层讲数据进行推送,节约了性能的开销。(小程序)

缺点:

维护困难,容易引起连锁问题

需要谨小慎微的命令规范

不利于组件化开发--------一个页面上有多个公共组件,我们只要向其中的一个传递数据,但是每个公共组件都绑定了数据接受的方法。我们怎么样做到把数据传递给需要的组件呢?


六 、事件总线二 new Vue

new Vue 这种通信方式和eventBus大致差不多,

不同点是,以vue实例作为eventBus中心,除了我们可以用$on,$emit之外,我们还可以用vue下的data,watch等方法,而且我们建立多个多个vue,作为不同模块的数据通信桥梁,相比上边那个EventBus方法,new Vue这种方法更高效,更适合vue项目场景

vueBus

import Vue from 'vue'

export default new Vue()

用法:

import VueBus from './vueBus'
export default {
   /* 父组件 */ 
   name:'father',
   components:{
       son ,/* 子组件 */
   },
   data(){
       return {
          mes:'',
          sonMes:'' /* 发送给子组件的信息  */
       } 
   },
   created(){
       /* 绑定属性 */
       VueBus._data.mes = 'hello,world'
   },
   mounted(){
      /* 绑定事件 */
      VueBus.$on('sonSay',this.sonSay)
   },
   methods:{
      /* 传递给子组件 */
      send(){
         VueBus.$emit('fatherSay',this.mes)
      },
      /* 接受子组件信息 */ 
      sonSay(value){
          this.sonMes = value
      },
   },
}

优点:

简单灵活,任意组件之间通信。

除了通信还可以使用watch , computed等方法

缺点:

基本上EventBus的缺点,都在vue这种通信方式中都有存在

应用场景:

在项目中不考虑用vuex的中小型项目中,可以考虑采用vue事件总线这种通信方式,在使用的这种方式的时候,我们一定要注意命名空间,不要重复绑定事件名称。分清楚业务模块,避免后续维护困难。


最后

vue项目中,具体要用什么通信方式,还要看具体的业务场景,项目大小等因素综合评估。

如果大家觉得有点帮助的话,就 点赞 或 关注 一波

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值