vue组件通信方式小结

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/dongguan_123/article/details/88935470

vue项目中,组件间的通信是最常用到的,也是面试必问的问题之一。

组件通信可以分为几种类型:

1、父子通信

   1.1 父传子

   1.2 子传父

2、跨级传递

   2.1祖父传孙

   3.1孙传祖父

3、同级组件间通信

首先说一下通用的方式,即不管哪种场景都在功能上可以实现,撇开具体场景的适合程度,其实也就是全局的通信方式。

一、vue bus  以vue实例为总线,传递数据

新建bus.js和busA.vue、busB.vue:

bus.js

import Vue from "vue"
const Bus = new Vue();
export default Bus;

在main.js引入,挂载到全局上去:

import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
import Bus from "@/utils/bus";

Vue.config.productionTip = false;
Vue.prototype.bus = Bus;

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

busA.vue:

<template>
    <div class="input">
        <button @click="handleClick">click</button>
    </div>
</template>

<script>
export default {
    data() {
        return {
        };
    },
    methods: {
      handleClick() {
        this.bus.$emit("change", 12333) // 触发事件
      }
    }
};
</script>
<style>
.input{
  display: flex;
}
</style>

busB.vue:

<template>
    <div class="input">
    </div>
</template>

<script>
export default {
    data() {
        return {
        };
    },
    created() {
      this.bus.$on('change', this.handleClick) // 监听事件
    },
    methods: {
      handleClick(val) {
        console.log(val)
      }
    }
};
</script>
<style>
.input{
  display: flex;
}
</style>

这样就实现了兄弟组件之间的数据传递,当然也适合所有类型的组件通信。

二、vuex  官方提供的状态管理器,统一管理状态可参考官方文档

 

接下来就是比较定制化的通信方式了:

一、父子通信

1、父传子:props

子传父:$emit

这两种方式都是最常用也是最简单的,可参考官方文档

2、通过实例通信:

$children

$parent

获取节点实例,然后访问实例下的数据或方法

3、父组件里给子组件设置ref属性,通过this.$refs.name访问子组件实例

二、隔代传递

利用组件的name属性作为标识,通过递归、遍历找到name对应的实例并返回,只要拿到了实例,那就可以随意访问实例下的数据和方法了。

1、向上查找最近指定节点

export const findComponentUpword = (context,componentName) => {
    let parent = context.$parent;
    let name = parent.$options.name;
    while(parent && (!name || [componentName].indexOf(name) < 0) {
        parent = parent.$parent;
        if(parent) {
            name = parent.$options.name;
        }
    }
    return parent || null;
}

组件中调用(父组件一定要有具体的name属性才行,不然找不到):

import {findComponentUpward} from "@/utils"
、、、、
、、、、
let fatherComponent = findComponentUpward(this,"FatherName"); // 父组件名称

2、向上查找所有指定节点

export const findComponentsUpward = (context,componentName) => {
    let parents = [];
    let parent = context.$parent;
    let name = parent.$options.name;
    if(parent) {
        if(name === componentName) {
            parents.push(parent);
        }
        return parents.concat(findComponentsUpward(parent,componentName));
    }else {
        return [];
    }
}

组件中调用:

import {findComponentsUpward} from "@/utils"
、、、、
、、、、
let fatherComponent = findComponentsUpward(this,"FatherName"); // 父组件名称, 返回匹配组件的实例数组

3、向下查找最近的指定节点

export const findComponentDownward = (context,componentName) => {
        let children = context.$children;
        let child = null;
        if(children.length) {
            for(const childItem in children) {
                const name = childItem.$options.name;
                if(name === componentName) {
                    child = childItem;
                    break;
                }else {
                    child = findComponentDownward(childItem,componentName);
                    if(child) {break}
                }
            }
        }
        return child;
    }

4、向下查找所有的指定节点

export const findComponentsDownwards = (context,componentName) => {
    return context.$children.reduce((components, child) => {
        if(child.$options.name === componentName) {
            components.push(child);
        }
        const findChildren = findComponentsDownwards(child,componentName);
        return [...components,...findChildren];
    },[])
}

5、provide、inject方式

vue的api原生提供的方法,在父组件向下注入一个provide,不管子组件嵌套有多深,都可以通过inject获取到

父组件:

<template>
  <div class="wrapper">
  </div>
</template>

<script>
export default {
  props: {
  },
  // provide() {  // 如果父组件本身是一个组件
  //  return {
  //   father:this
  // }
  provide: {
        father: this
    }
  },
  data() {
    return {
        testData: "哈哈哈哈"
    };
  },
  created() {
  },
  methods: {
  }
};
</script>

子组件:

<template>
  <div class="son">
   
  </div>
</template>

<script>
export default {
  inject: ['father'],
  props: {
  },
  data() {
    return {
    };
  },
  mounted() {
    console.log(this.father.testData) // 哈哈哈哈
  },
  methods: {}
};
</script>
<style lang="css">
</style>

有了这些组件通信方式,再复杂的业务需求也能得到满足了

展开阅读全文

没有更多推荐了,返回首页