优雅地跨层级获取vue组件实例
在实际的项目开发中,经常遇到组件一层嵌套一层的场景。当组件一两层还好,可以直接用$refs.A.$refs.B
形式去获取组件的实例。但是,如果组件嵌套层级超过两层时,使用这种方式就不是那么方便了,尤其是获取兄弟组件节点的实例,更加困难。
vue 2.2版本时,新增了provide/inject
属性,通过provide
可以轻松地跨层级获取父组件的实例。
// 父组件
provide() {
return { root: this };
},
// 子组件
inject: ['root'];
这就解决了从子级获取父级的问题。
但是父级怎么获取子级呢?
使用遍历递归的方式可以做到。通过给子组件设置一个名称,不断的递归$children
,直到找到正确名称的组件为止。虽然,使用这种方式可以找到自组件实例,但是总是执行递归操作是一件对性能造成浪费的事情。
下面就介绍一下另一种解决办法。
在根组件中设置缓存变量,在每一个组件初始化或更新的时候将对应的实例或者HTMLElement添加到根组件的缓存中,为了实现每一次初始化和更新都调用,这里使用自定义指令。
核心代码如下
export default {
install(Vue, options = {}) {
const directiveName = options.name || "ref";
Vue.directive(directiveName, {
bind(el, binding, vnode) {
binding.value(vnode.componentInstance || el, vnode.key);
},
update(el, binding, vnode, oldVnode) {
if (oldVnode.data && oldVnode.data.directives) {
const oldBinding = oldVnode.data.directives.find(
directive => directive.name === directiveName
);
if (oldBinding && oldBinding.value !== binding.value) {
oldBinding && oldBinding.value(null, oldVnode.key);
binding.value(vnode.componentInstance || el, vnode.key);
return;
}
}
if (
vnode.componentInstance !== oldVnode.componentInstance ||
vnode.elm !== oldVnode.elm
) {
binding.value(vnode.componentInstance || el, vnode.key);
}
},
unbind(el, binding, vnode) {
binding.value(null, vnode.key);
}
});
}
};
这也是vue-ref的实现代码。
在根组件中通过provide
向外提供设置实例与获取实例的几个关键方法。
provide() {
return {
setChildrenRef: (name, ref) => {
this[name] = ref;
},
getChildrenRef: name => this[name],
getRef: () => this
};
},
使用指令的代码
Vue.use(vueRef, {name: 'ref'})
这样,在全局就有了v-ref
指令,它有点类似于React的ref
指令,可以在里面传递一个回调函数,第一个参数就是当前的实例。
<E ref="E" v-ref="c => setChildrenRef($refs.E.$options.name, c)"></E>
如果您觉得本文对您有用,欢迎捐赠或留言~
- 本博客所有文章除特别声明外,均可转载和分享,转载请注明出处!
- 本文地址:https://www.leevii.com/?p=2380