【vue回顾系列】11-使用vue-ref插件实现跨级获取组件实例

使用场景

举个例子啊,简单的单链条组件dom树
在这里插入图片描述
平时不跨层的第一层的A组件获取第二层的A组件很容易,直接一个ref的官方api搞定,但是如果有这样以下的跨级场景:

  1. Index要获取第二层的A组件实例
  2. 第二层的A组件想获取Index实例
  3. 第二层的B组件想获取第二层的A组件实例

是不是就比较麻烦,使用传统的方法解决也是麻烦的,白嫖一下别人写的传统方法哈哈

this.$parent // 访问父实例
this.$children // 当前实例的直接子组件。(不保证顺序,不是响应式)
this.$parent.$parent.$refs.xxx // 跨级访问父组件
this.$children.$children.$refs.xxx // 跨级访问子组件

这种递归的方式,执行流程繁琐,不能缓存,性能低效,不能及时更新实例。

现在有个vue-ref的api能够完美的解决以上需求。


vue-ref的使用

以下以上图dom组件结构举例

安装与引入

// npm安装
npm install vue-ref --save

// main.js中
import ref from "vue-ref"

Vue.use(ref, { name: "ant-ref" }) // name是自定义api名称

在根组件中提供api

注意:这个根组件不是固定说一定要最高层的那个组件,任意一个组件都可作为起始的根组件

<template>
  <div>
    <button @click="getSecondFloorADom">index获取secondFloorA实例</button>
    <firstFloorA></firstFloorA>
    <firstFloorB></firstFloorB>
  </div>
</template>

<script>
import firstFloorA from "@/components/firstFloorA.vue";
import firstFloorB from "@/components/firstFloorB.vue";

export default {
  //使用provide在根组件提供api
  provide() {
    return {
      //这个api设定主动通知 将组件实例绑定在根组件上
      setChildrenRef: (name, ref) => {
        this[name] = ref;
      },
      //这个api是主动获取绑定的组件
      getChildrenRef: (name) => {
        return this[name];
      },
      // 这个是获取根组件
      getRef: () => { 
        return this;
      },
    };
  },
  methods: {
    getSecondFloorADom() {
      console.log('secondFloorA', this.secondFloorA)
    },
  },
  components: {
    firstFloorA,
    firstFloorB,
  },
};
</script>

链条下的子组件

主要通过inject来获取根组件提供的api,子组件需要哪些api就写哪些

inject: {
    setChildrenRef: { // 注册子组件
      default: () => {},
    },
    getParentRef: {  // 获取根组件实例
      from: "getRef",
      default: () => {},
    },
    getParentChildrenRef: {  // 获取根组件链下任何注册的子组件
      from: "getChildrenRef",
      default: () => {},
    },
},

firstFloorA

<template>
  <div>
    <secondFloorA
      v-ant-ref="(dom) => setChildrenRef('secondFloorA', dom)"  // 看到没注册的形式和根组件提供的api是一样的
    ></secondFloorA>
    <button @click="getSecondFloorADom">firstFloorA获取secondFloorA的实例</button>
  </div>
</template>

<script>
import secondFloorA from "../components/secondFloorA";
export default {
  inject: {
    setChildrenRef: {
      default: () => {},
    },
    getParentChildrenRef: {
      from: "getChildrenRef",
      default: () => {},
    },
  },
  methods: {
    getSecondFloorADom() {
      console.log('secondFloorA' , this.getParentChildrenRef('secondFloorA'));
    },
  },
  components: {
    secondFloorA,
  },
};
</script>

secondFloorA

<template>
  <div></div>
</template>

<script>
export default {
    inject:{
        setChildrenRef:{
            default: () => {}
        }
    },
}
</script>

firstFloorB

<template>
  <div>
    <secondFloorB
      v-ant-ref="(dom) => setChildrenRef('secondFloorB', dom)"
    ></secondFloorB>
    <button @click="getParentDom">firstFloorB获取index的实例</button>
  </div>
</template>

<script>
import secondFloorB from "../components/secondFloorB";
export default {
  inject: {
    setChildrenRef: {
      default: () => {},
    },
    getParentRef: {
      from: "getRef",
      default: () => {},
    },
  },
  methods: {
    getParentDom() {
      console.log('index',this.getParentRef());
    },
  },
  components: {
    secondFloorB,
  },
};
</script>

secondFloorB

<template>
  <div>
    <button @click="getParentDom">secondFloorB获取index实例</button>
    <button @click="getSecondFloorADom">secondFloorB获取secondFloorA实例</button>
  </div>
</template>

<script>
export default {
  inject: {
    getParentRef: {
      from: "getRef",
      default: () => {},
    },
    getParentChildrenRef: {
      from: "getChildrenRef",
      default: () => {},
    },
  },
  methods: {
    getParentDom() {
      console.log("index", this.getParentRef());
    },
    getSecondFloorADom() {
      console.log('secondFloorA', this.getParentChildrenRef('secondFloorB'))
    }
  },
};
</script>

对于普通dom节点

普通的dom节点也是能够这样获取的,未来可以试试,比如index获取secondFloorB的某个普通dom节点


vue-ref的优点

除了使用上的优点外,被注册的组件实例如果有更新,会让根组件缓存中对应的实例也进行实时的更新。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值