组件通信之找到任意的组件实例

本文介绍了一种Vue组件间通信的方法——findComponents系列函数,包括向上、向下查找指定组件及查找兄弟组件等五个实用函数,提供了具体实现代码及应用场景示例。

今天向大家介绍另外一种组件之间通信的方法,也就是 findComponents 系列方法,它并非Vue.js内置,而是需要自行实现的,我们以工具函数的形式来使用,它是一系列的函数,可以说是组件通信的终极方案。findComponents 系列方法最终都是返回组件的实例,进而可以读取或调用该组件的数据和方法。

它的适用场景:

--由一个组件,向上找到最近的指定组件

--由一个组件,向上找到所有的指定组件

--由一个组件,向下找到最近的指定组件

--由一个组件,向下找到所有的的指定组件

--由一个组件,找到指定组件的兄弟组件

实现:

5个函数的原理,都是通过递归、遍历找到指定组件的name选项匹配的组件实例并返回

1. 向上找到最近的指定组件——findComponentUpward

//1.向上找到指定的组件实例
function findComponentUpward(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;
}

findComponentUpward 接收两个参数,第一个是当前上下文,比如你要基于哪个组件来向上寻找,一般都是基于当前的组件,也就是传入 `this`;第二个参数是要找的组件的 `name` 。

findComponentUpward 方法会在 while 语句里不断向上覆盖当前的 `parent` 对象,通过判断组件(即 parent)的 name 与传入的 componentName 是否一致,直到最近的一个组件为止。

与 dispatch 不同的是,findComponentUpward 是直接拿到组件的实例,而非通过事件通知组件。比如下面的示例

//父组件
<template>
    <div>
        <h1>父组件</h1>
        <C></C>
    </div>
</template>
<script>
import C from './c1.vue';
export default {
    name:'p1',
    data(){
        return {
            px:'我是父级数据'
        }
    },
    components:{
        C
    }
}
</script>
<style scoped>
</style>
<template>
    <div>
        <h1>子组件</h1>
    </div>
</template>
<script>
import {findComponentUpward} from './emitter.js/emitter.js';
export default {
    name:'c1',
    data(){
        return {
        }
    },
    mounted(){
        //comA就是找到的父级组件实例,可以调用其任何方法
        const comA=findComponentUpward(this,'p1');
        if(comA){
            console.log(comA.px)  //我是父级数据
        }
    }
}
</script>
<style scoped>  
</style>

2.向上找到所有的指定组件——findComponentsUpward

function findComponentsUpward (context, componentName) {
  let parents = [];
  const parent = context.$parent;

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

3.向下找到最近的指定组件——findComponentDownward

function findComponentDownward(context,componentName){
    const childrens=context.$children;  //数组
    let children=null;

    if(childrens.length){
        for(const child of childrens){
            const name=child.$options.name;

            if(name===componentName){
                children=child;
                break;
            }else{
                children=findComponentDownward(child,componentName);
                if(children){
                    break;
                }
            }
        }
    }
    return children;
}
export {findComponentDownward}

context.$children` 得到的是当前组件的全部子组件,所以需要遍历一遍,找到有没有匹配到的组件 `name`,如果没找到,继续递归找每个 $children 的 $children,直到找到最近的一个为止。

4.向下找到所有指定的组件——findComponentsDownward

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

这个函数实现的方式有很多,这里巧妙使用 `reduce` 做累加器,并用递归将找到的组件合并为一个数组并返回,代码量较少,但理解起来稍困难。这篇文章详细介绍了reduce的用法,供大家参考:https://www.jianshu.com/p/e375ba1cfc47

5.找到指定组件的兄弟组件——findBrothersComponents

function findBrothersComponents (context, componentName, exceptMe = true) {
  let res = context.$parent.$children.filter(item => {
    return item.$options.name === componentName;  //返回所有item.$options.name === componentName的item
  });
  let index = res.findIndex(item => item._uid === context._uid);  //findIndex() 方法返回传入一个测试条件(函数)符合条件的数组第一个元素位置。
  if (exceptMe) res.splice(index, 1);
  return res;
}
export { findBrothersComponents };

比其它 4 个函数,findBrothersComponents 多了一个参数 `exceptMe`,是否把本身除外,默认是 true。寻找兄弟组件的方法,是先获取 `context.$parent.$children`,也就是父组件的全部子组件,这里面当前包含了本身,所有也会有第三个参数 exceptMe。Vue.js 在渲染组件时,都会给每个组件加一个内置的属性 `_uid`,这个 _uid 是不会重复的,借此我们可以从一系列兄弟组件中把自己排除掉。

本文章由作者搜集整理,并非原创

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值