优雅地跨层级获取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;
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