【Vue 开发实战】基础篇 # 13:如何优雅地获取跨层级组件实例(拒绝递归)

简介: 【Vue 开发实战】基础篇 # 13:如何优雅地获取跨层级组件实例(拒绝递归)

说明

【Vue 开发实战】学习笔记。



ref 引用信息

3c3120d5c5a44dc794d804e6f29bac1e.png


递归查找

  • 代码繁琐.
  • 性能低效


2f5b4680bed44e31abd06e56c168cc43.png


callback ref

  • 主动通知(setXxxRef)
  • 主动获取(getXxxRef)


比如E节点更新就通知A组件,A组件进行ref的缓存即可

组件A

<template>
  <div class="border">
    <h1>A 结点</h1>
    <button @click="getHRef">获取子孙节点 E Ref</button>
    <ChildrenB />
    <ChildrenC />
    <ChildrenD />
  </div>
</template>
<script>
import ChildrenB from "./ChildrenB";
import ChildrenC from "./ChildrenC";
import ChildrenD from "./ChildrenD";
export default {
  components: {
    ChildrenB,
    ChildrenC,
    ChildrenD
  },
  provide() {
    return {
      setChildrenRef: (name, ref) => {
        console.log("A 组件 setChildrenRef", name);
        this[name] = ref;
      },
      getChildrenRef: name => {
        console.log("A 组件 getChildrenRef", name);
        return this[name];
      },
      getRef: () => {
        console.log("A 组件 getRef");
        return this;
      }
    };
  },
  data() {
    return {
      color: "blue"
    };
  },
  methods: {
    getHRef() {
      console.log(this.childrenE);
    }
  }
};
</script>



组件D

<template>
  <div class="border1">
    <h2>D 结点</h2>
    <ChildrenG />
    <ChildrenH v-ant-ref="c => setChildrenRef('childrenH', c)" />
    <ChildrenI />
  </div>
</template>
<script>
import ChildrenG from "./ChildrenG";
import ChildrenH from "./ChildrenH";
import ChildrenI from "./ChildrenI";
export default {
  components: {
    ChildrenG,
    ChildrenH,
    ChildrenI
  },
  inject: {
    setChildrenRef: {
      default: () => {}
    }
  }
};
</script>


组件E

<template>
  <div class="border2">
    <h3 v-ant-ref="c => setChildrenRef('childrenE', c)">
      E 结点
    </h3>
  </div>
</template>
<script>
export default {
  components: {},
  inject: {
    setChildrenRef: {
      default: () => {}
    }
  }
};
</script>


组件F

<template>
  <div class="border2">
    <h3>F 结点</h3>
    <button @click="getARef">获取祖先节点 A Ref</button>
    <button @click="getHRef">获取同级节点 H Ref</button>
  </div>
</template>
<script>
export default {
  components: {},
  inject: {
    getParentRef: {
      from: "getRef",
      default: () => {}
    },
    getParentChildrenRef: {
      from: "getChildrenRef",
      default: () => {}
    }
  },
  methods: {
    getARef() {
      console.log(this.getParentRef());
    },
    getHRef() {
      console.log(this.getParentChildrenRef("childrenH"));
    }
  }
};
</script>


84f39ca46c3645e698d0e66ef42cfb5b.png

然后点击三个按钮

61295b66d1af4d36840d3dd49e41c30e.png


这里面使用了 v-ant-ref 这个指令,用于通知上层节点更新。我们可以找一下依赖 vue-ref 这个包,看一下指令源码

18c2a2d7b1c54dc9b41c69ac235726c1.png

"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';
    Vue.directive(directiveName, {
      bind: function bind(el, binding, vnode) {
        binding.value(vnode.componentInstance || el, 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);
      }
    });
  }
};


完整demo源码可以参考这个https://github.com/kaimo313/vue-development-practice/tree/master/vue-demo/src/views/demo13


目录
相关文章
|
1天前
|
JavaScript 前端开发
vue3中使用动态组件
vue3中使用动态组件
|
1天前
|
JavaScript 前端开发 容器
Vue 3 中 <transition-group> 组件报错的非 props 属性传递问题
Vue 3 中 <transition-group> 组件报错的非 props 属性传递问题
12 1
|
1天前
|
移动开发 JavaScript 前端开发
ruoyi-nbcio-plus基于vue3的flowable的自定义业务显示历史信息组件的升级修改
ruoyi-nbcio-plus基于vue3的flowable的自定义业务显示历史信息组件的升级修改
|
1天前
|
移动开发 前端开发
ruoyi-nbcio-plus基于vue3的flowable的自定义业务撤回申请组件的升级修改
ruoyi-nbcio-plus基于vue3的flowable的自定义业务撤回申请组件的升级修改
|
JavaScript 测试技术 容器
Vue2+VueRouter2+webpack 构建项目
1). 安装Node环境和npm包管理工具 检测版本 node -v npm -v 图1.png 2). 安装vue-cli(vue脚手架) npm install -g vue-cli --registry=https://registry.
987 0
|
2天前
|
JavaScript
VUE里的find与filter使用与区别
VUE里的find与filter使用与区别
11 0
|
2天前
|
JavaScript
vue页面加载时同时请求两个接口
vue页面加载时同时请求两个接口
|
2天前
|
JavaScript
vue里样式不起作用的方法,可以通过deep穿透的方式
vue里样式不起作用的方法,可以通过deep穿透的方式
10 0
|
2天前
|
移动开发 JavaScript 应用服务中间件
vue打包部署问题
Vue项目`vue.config.js`中,`publicPath`设定为&quot;/h5/party/pc/&quot;,在线环境基于打包后的`dist`目录,而非Linux的`/root`。Nginx代理配置位于`/usr/local/nginx/nginx-1.13.7/conf`,包含两个相关配置图。
vue打包部署问题
|
2天前
|
JavaScript 前端开发
iconfont 图标在vue里的使用
iconfont 图标在vue里的使用
11 0