问题
在开发中遇到select组件在table组件中使用是会发生select菜单不跟随滑动的问题,初步判断是element的自身缺陷,可以通过编写一个指令解决这个问题。
解决table中select以及cascader滑动定位问题,以及当划出table的隐藏显示菜单问题
解决方案
思路:
1.由于select的menu菜单实际是添加到body上的,当页面滑动时通过计算位置来定位
2.由于在table中滑动不能触发计算位置的逻辑
3.我们只需要构建一个触发计算逻辑的回调事件即可
代码实现:
export default function install(Vue) {
function setCb({ cb, isRun }) {
const timer = requestAnimationFrame(function fn() {
cb();
if (isRun) {
requestAnimationFrame(fn);
} else {
cancelAnimationFrame(timer);
}
});
}
function getTableDom(el) {
let tableDom = el;
while (true) {
tableDom = tableDom.parentElement;
if (tableDom.tagName === "BODY") {
tableDom = undefined;
break;
}
if (tableDom.className.indexOf("el-table__body-wrapper") >= 0) {
break;
}
}
return tableDom;
}
Vue.directive("handleSelectPostion", {
bind(el, binding, vnode) {
el.polyData = {
cb: () => {
const rect = el.getBoundingClientRect();
if (
rect.top !== el.polyData.oldTop ||
rect.left !== el.polyData.oldLeft
) {
if (
vnode.componentInstance.$el.className.indexOf("el-cascader") >= 0
) {
// 级联组件
const cascaderPlan = vnode.componentInstance.$children[1];
if (vnode.componentInstance.dropDownVisible) {
vnode.componentInstance.updatePopper();
const menuRect = cascaderPlan.$el.getBoundingClientRect();
const tableDom = getTableDom(el);
if (!tableDom) {
return;
}
const tableRect = tableDom.getBoundingClientRect();
if (
menuRect.top < tableRect.top ||
menuRect.top > tableRect.top + tableRect.height
) {
cascaderPlan.$el.parentElement.style.opacity = 0;
cascaderPlan.$el.parentElement.style.pointerEvents = "none";
} else {
cascaderPlan.$el.parentElement.style.opacity = 1;
cascaderPlan.$el.parentElement.style.pointerEvents = "unset";
}
} else {
cascaderPlan.$el.parentElement.style.opacity = 1;
cascaderPlan.$el.parentElement.style.pointerEvents = "unset";
}
} else {
// select组件
const selectMenu = vnode.componentInstance.$children[1];
if (selectMenu.$parent.visible) {
selectMenu.updatePopper();
const menuRect = selectMenu.$el.getBoundingClientRect();
const tableDom = getTableDom(el);
if (!tableDom) {
return;
}
const tableRect = tableDom.getBoundingClientRect();
if (
menuRect.top < tableRect.top ||
menuRect.top > tableRect.top + tableRect.height
) {
selectMenu.$el.style.opacity = 0;
selectMenu.$el.style.pointerEvents = "none";
} else {
selectMenu.$el.style.opacity = 1;
selectMenu.$el.style.pointerEvents = "unset";
}
} else {
selectMenu.$el.style.opacity = 1;
selectMenu.$el.style.pointerEvents = "unset";
}
}
}
el.polyData.oldTop = rect.top;
el.polyData.oldLeft = rect.left;
},
isRun: true,
oldTop: 0,
oldLeft: 0,
};
setCb(el.polyData);
},
unbind(el) {
el.polyData.isRun = false;
},
});
}