• Dom-Align


    聊聊 Dom-Align 这个包

    最近在写一个弹框的 service,用到了 Dom-Align,来挨着某个元素来弹框,遇到了些坑,记录一下,以免下次再掉进去。
    先聊聊 Dom-Align 怎么干活的。这个有个约定, target 指的是参考系,source(目标元素)指的是需要被定位的元素。

    • 我们一般直接调用alignElement(el,refNode,align)这个方法。第一个参数是目标元素,第二个是参考系元素,第三个是 AlignType. 这个方法里面先调用const refNodeRegion = getRegion(target);来获取参考系的可视区域。它是向对于 document 而言的,所以如果 document 有 scrollbar, 这个距离也是计算再内的,数据结构如下:
    {
        left:number,
        top:number,
        number,
        height:number,
    }
    
    • 在这个函数里面,会调用doAlign(el, refNodeRegion, align, isTargetNotOutOfVisible);
    • doAlign这个方法,跳过一些不重要的,就关注主要的,它会先计算 source的可视区域。const visibleRect = getVisibleRectForElement(source, alwaysByViewport);
    • 然后计算出source将要被放置的区域。
    // 当前节点将要被放置的位置
    // 这个函数主要是计算出最终的left,top的值。
    let elFuturePos = getElFuturePos(
      elRegion,
      tgtRegion,
      points,
      offset,
      targetOffset
    );
    // 当前节点将要所处的区域
    let newElRegion = utils.merge(elRegion, elFuturePos);
    
    • 下面就是微调,在adjustX,adjustY打开的情况下,如果source溢出,则会考虑在左右,上下进行颠倒来进行调整。
    // 如果可视区域不能完全放置当前节点时允许调整
    if (
      visibleRect &&
      (overflow.adjustX || overflow.adjustY) &&
      isTgtRegionVisible
    ) {
      if (overflow.adjustX) {
        // 如果横向不能放下
        if (isFailX(elFuturePos, elRegion, visibleRect)) {
          // 对齐位置反下
          const newPoints = flip(points, /[lr]/gi, {
            l: "r",
            r: "l",
          });
          // 偏移量也反下
          const newOffset = flipOffset(offset, 0);
          const newTargetOffset = flipOffset(targetOffset, 0);
          const newElFuturePos = getElFuturePos(
            elRegion,
            tgtRegion,
            newPoints,
            newOffset,
            newTargetOffset
          );
    
          if (!isCompleteFailX(newElFuturePos, elRegion, visibleRect)) {
            fail = 1;
            points = newPoints;
            offset = newOffset;
            targetOffset = newTargetOffset;
          }
        }
      }
    
      if (overflow.adjustY) {
        // 如果纵向不能放下
        if (isFailY(elFuturePos, elRegion, visibleRect)) {
          // 对齐位置反下
          const newPoints = flip(points, /[tb]/gi, {
            t: "b",
            b: "t",
          });
          // 偏移量也反下
          const newOffset = flipOffset(offset, 1);
          const newTargetOffset = flipOffset(targetOffset, 1);
          const newElFuturePos = getElFuturePos(
            elRegion,
            tgtRegion,
            newPoints,
            newOffset,
            newTargetOffset
          );
    
          if (!isCompleteFailY(newElFuturePos, elRegion, visibleRect)) {
            fail = 1;
            points = newPoints;
            offset = newOffset;
            targetOffset = newTargetOffset;
          }
        }
      }
    
      // 如果失败,重新计算当前节点将要被放置的位置
      if (fail) {
        elFuturePos = getElFuturePos(
          elRegion,
          tgtRegion,
          points,
          offset,
          targetOffset
        );
        utils.mix(newElRegion, elFuturePos);
      }
      const isStillFailX = isFailX(elFuturePos, elRegion, visibleRect);
      const isStillFailY = isFailY(elFuturePos, elRegion, visibleRect);
      // 检查反下后的位置是否可以放下了,如果仍然放不下:
      // 1. 复原修改过的定位参数
      if (isStillFailX || isStillFailY) {
        let newPoints = points;
    
        // 重置对应部分的翻转逻辑
        if (isStillFailX) {
          newPoints = flip(points, /[lr]/gi, {
            l: "r",
            r: "l",
          });
        }
        if (isStillFailY) {
          newPoints = flip(points, /[tb]/gi, {
            t: "b",
            b: "t",
          });
        }
    
        points = newPoints;
    
        offset = align.offset || [0, 0];
        targetOffset = align.targetOffset || [0, 0];
      }
      // 2. 只有指定了可以调整当前方向才调整
      newOverflowCfg.adjustX = overflow.adjustX && isStillFailX;
      newOverflowCfg.adjustY = overflow.adjustY && isStillFailY;
    
      // 确实要调整,甚至可能会调整高度宽度
      if (newOverflowCfg.adjustX || newOverflowCfg.adjustY) {
        newElRegion = adjustForViewport(
          elFuturePos,
          elRegion,
          visibleRect,
          newOverflowCfg
        );
      }
    }
    
    • 然后就是更新宽高,如果有变化,source的位置信息被更新。同时返回位置信息。

    这个里面用到了很多 Dom 的方法,例如计算可视区域,getVisibleRectForElement,它会递归的找 offsetParent,对于 overflow 不是 visible 的,都会叠加那个可视区域。可视区域是采用{left,top,bottom,right}来描述的,跟 css 里面的 clip 计算是一样的,都是相对于 viewport 的 left,top 来计算的,这样就有了一个矩形区域。在刚才提到的递归的过程,这个矩形区域是越来越小的,其实找的是他们的交集。

  • 相关阅读:
    android应用私有存储文件的写入与读取-openFileInput 和 openFileOutput
    android 8种对话框(Dialog)使用方法汇总
    Gradle环境变量的配置
    Activity标题(title)的显示和隐藏
    Android Studio配置Android Annotations框架详解--说说那些坑
    Android如何防止apk程序被反编译
    Android APK反编译 apktool使用教程
    关于Installation error: INSTALL_FAILED_NO_MATCHING_ABIS的解决方法
    Android解决NDK not configured问题
    Android SDK在线更新镜像服务器
  • 原文地址:https://www.cnblogs.com/kongshu-612/p/15142092.html
Copyright © 2020-2023  润新知