说明
【Vue 开发实战】学习笔记。
ref 引用信息
递归查找
- 代码繁琐.
- 性能低效
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>
然后点击三个按钮
这里面使用了 v-ant-ref
这个指令,用于通知上层节点更新。我们可以找一下依赖 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'; 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