客户体验提升的一小步(关于table中select的菜单不跟随滑动)

107 阅读1分钟

问题

在开发中遇到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;
    },
  });
}