Vue组件跨层级获取组件实例

本文探讨了在Vue中如何优雅地解决组件跨层级获取实例的问题,包括使用`ref`的限制及其工作原理,以及如何通过安装和使用特定插件来实现更高效的方法。虽然`ref`可以用于直接子组件的访问,但跨级访问则变得复杂且效率低下。通过引入插件,可以简化这一过程,提高代码的可读性和性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

this.$parent 访问父实例
this.$children 当前实例的直接子组件。(不保证顺序,不是响应式)
this.$parent.$parent.$refs.xxx 跨级访问父组件
this.$children.$children.$refs.xxx 跨级访问子组件
这种递归的方式 代码繁琐 性能低效

this.$parent打印结果

ref

只能获取当前组件上下文组件 无法跨层级

ref 是字符串 被用来给元素或子组件注册引用信息。
引用信息将会注册在父组件的 $refs 对象上。
如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;
如果用在子组件上,引用就指向组件实例

<!-- vm.$refs.p/this.$refs.p 获取DOM node -->
<p ref="p">hello</p>
<!-- vm.$refs.child/this.$refs.child 获取组件实例 -->
<child-component ref="child"></child-component>

注:

  • 因为 ref 本身是作为渲染结果被创建的,在初始渲染的时候你不能访问它们,它们还不存在
  • $refs 不是响应式的,因此你不应该试图用它在模板中做数据绑定。
  • 这仅作为一个用于直接操作子组件的“逃生舱”——你应该避免在模板或计算属性中访问 $refs。
  • 当 ref 和 v-for 一起使用的时候,你得到的引用将会是一个包含了对应数据源的这些子组件的数组。

如何优雅的获取跨层级实例 ?

  1. npm install vue-ref || yarn add vue-ref 安装vue-ref插件
  2. 导入import ref from "vue-ref"
  3. 使用插件Vue.use(ref, { name: "ant-ref" });name是给插件起名

插件使用方法

//使用`provide` 在根组件提供数据 
provide() {
  return {
    //主动通知 将组件实例绑定在根组件上
    setChildrenRef: (name, ref) => {
      this[name] = ref;
    },
    //主动获取 获取绑定的组件
    getChildrenRef: name => {
      return this[name];
    },
    // 获取根组件
    getRef: () => {
      return this;
    }
  }
}
// 使用`inject` 在子组件中注入数据
inject: {
  setChildrenRef: {
    default: () => {}
  },
  getParentRef: {
    from: "getRef",
    default: () => {}
  },
  getParentChildrenRef: {
    from: "getChildrenRef",
    default: () => {}
  }
}

//使用指令注册子组件
<ChildrenH v-ant-ref="c => setChildrenRef('childrenH', c)" />
//使用指令注册DOM元素
<h3 v-ant-ref="c => setChildrenRef('childrenE', c)">E 结点</h3>
//获取根组件实例 
this.getParentRef()
//获取指定名称组件实例
this.getParentChildrenRef("childrenH")
//这里输出的事DOM
this.getParentChildrenRef("childrenE")

vue-ref插件源码

"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = {
  install: function install(Vue) {
    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
    var directiveName = options.name || 'ref';
    console.log(arguments)
    Vue.directive(directiveName, {
      bind: function bind(el, binding, vnode) {
        //自定义指令传入值 是函数, 在这里执行 传入组件实例
        binding.value(vnode.componentInstance || el, vnode.key); //vnode.key 是使用插件时起的名称
      },
      update: function update(el, binding, vnode, oldVnode) {
        if (oldVnode.data && oldVnode.data.directives) {
          var oldBinding = oldVnode.data.directives.find(function (directive) {
            var name = directive.name;
            return name === directiveName;
          });
          if (oldBinding && oldBinding.value !== binding.value) {
            oldBinding && oldBinding.value(null, oldVnode.key);
            // 如果指令绑定的值有变化,则更新 组件实例
            binding.value(vnode.componentInstance || el, vnode.key);
            return;
          }
        }
        // Should not have this situation
        if (vnode.componentInstance !== oldVnode.componentInstance || vnode.elm !== oldVnode.elm) {
          binding.value(vnode.componentInstance || el, vnode.key);
        }
      },
      unbind: function unbind(el, binding, vnode) {
        binding.value(null, vnode.key);
      }
    });
  }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值