自适应浮动表单填充布局脚本

效果

1、适合搜素表单布局,查询重置等功能块始终位于最后一行的最后一列
在这里插入图片描述

2、适合普通多行两端对齐,未填充满的行左对齐
在这里插入图片描述

思路

  1. 此脚本目的为实现整齐风格的表单布局,为了达到整齐的效果,每个表单元素或者块都要设置一致的 宽度
  2. flex 布局不能适应多行不同的对齐需求,grid需要额外配置不同分辨率的分割,此脚本只需要设置块宽以及块的默认最小间隔(指效果图中灰色块,脚本中定义为box
  3. 通过已知的块宽和最小间隔能够计算出一行最多可容纳多少块,如果宽度富裕则计算出新的间隔
  4. 浮点运算的不准确,需要计算正数插值,将其平摊到具有右边距 的每个块

代码

此版本为jquery版,不过只是借用了其事件触发功能用以适应屏幕缩放,其他功能性脚本均为原生js,可以很容易转为其他框架比如vue

需要注意的是,所有的块默认为float:left

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <style>
    div {
    
    
      box-sizing: border-box;
    }
    .fit-box {
    
    
      border: 1px solid #aaa;
    }

    .fit-box:after {
    
    
      content: '';
      display: block;
      clear: both
    }
    .box {
    
    
      float: left;/*默认左浮动,必须*/
      width: 121px;
      height: 40px;
      margin-top: 10px;
      background: #c8c8c8;
      /*border: 1px solid #72b48b;*/
    }
  </style>
</head>
<body>
<!--div.fill-box*5>{
    
    $}-->
<div class="fit-box">
  <div class="box">1</div>
  <div class="box">2</div>
  <div class="box">3</div>
  <div class="box">4</div>
  <div class="box">5</div>
  <div class="box">6</div>
  <div class="box">7</div>
  <div class="box">8</div>
  <div class="box">9</div>
  <div class="box">10</div>
  <div class="box">11</div>
  <div class="box">12</div>
  <div class="box">13</div>
  <div class="box">14</div>
  <div class="box">15</div>
</div>
<script src="../../lib/jquery-1.11.3.min.js"></script>
<script>

;(function () {
    
    
  function DriftBox($el, options) {
    
    
    this._$el = $el;
    this._options = $.extend({
    
    }, options);
  }

  DriftBox.prototype = {
    
    
    init() {
    
    
      let _this = this;
      let {
    
     _$el, _options } = _this

      //初始化时执行一次计算
      _this.calculate();

      //监听窗口变动
      _$el.on('RZ', (e) => {
    
    
        ((fn, params, time) => {
    
    
          //如果当前存在延时,则清除并重新添加,注意保持method对象的稳定性,不然可能导致tId丢失
          clearTimeout(fn.tId);
          fn.tId = setTimeout(() => fn.call(_this, params), time)
        })(_this.calculate, e, _options.throttleTime)
      });
      $(window).resize(() => _$el.trigger($.Event('RZ')));
    },
    /**
     * FillBox宽度固定,需要计算每行数量,边距
     *
     */
    calculate() {
    
    
      let {
    
     searchLayout: isSearchLayout, marginRight: mr, boxSelector } = this._options
      let el = this._$el[0]
      let boxArr = el.querySelectorAll(boxSelector); //获取所有BOX
      let boxNum = boxArr.length;
      if (boxNum) {
    
    
        let rw = el.clientWidth,//行宽
          bw = boxArr[0].offsetWidth, //TODO 只考虑BOX同宽,BOX不同宽易导致自动分配的margin过大且需要传送式计算每行BOX数量
          num = Math.floor((rw + mr) / (bw + mr)), //每行最多几个BOx
          rowNum = Math.ceil(boxNum / num);//分几行

        if (num) {
    
    
          mr = Math.floor((rw - num * bw) / (num - 1));
          console.log("num:", num, 'rw:', rw, 'bw:', bw, 'mr:', mr)
          //满行最后一个BOX不设置margin-right;
          boxArr.forEach((d, i) => d.style.marginRight = (i + 1) % num && mr + 'px');
          //如果是类似表单查询的布局,查询和重置|按钮所在box需要右对齐
          if (isSearchLayout) {
    
    
            boxArr[boxNum - 1].style.marginRight = 0
            boxArr[boxNum - 1].style.float = 'right'
          }
          //浮点计算的不准确可能导致每行差几个像素,在视觉上不会太明显,默认将这些插值添加到每行的第一个非右对齐的元素
          let dif = rw - num * bw - (num - 1) * mr
          //处理每行的差值
          let box, marginRight, i, j, m;
          for (i = 0; i < rowNum; i++) {
    
    
            for (j = 0, m = 0; j < dif; m++) {
    
    
              box = boxArr[i * num + m % num]
              marginRight = parseInt(box.style.marginRight)
              if (box.style.float == 'right') break
              if (marginRight) {
    
    
                box.style.marginRight = marginRight + 1 + 'px'
                j++
              }
            }
          }
          console.log('dif:', dif, 'rowNum:', rowNum)
        }
        /**
         * 如果容器高度过大导致外层出现滚动条压缩压缩容器宽度,会使得计算的margin偏小,
         * 因此需要在计算完成后重新进行比对,如果容器宽度变化则重新计算一次
         */
        requestAnimationFrame(() => rw != el.clientWidth ? this.calculate() : '')
      }
    }
  }
  $.fn.DriftBox = function (options) {
    
    
    this.each(function (index, el) {
    
    
      new DriftBox($(el), options).init()
    });
    return $(this)
  }
})();

$('.fit-box').DriftBox({
    
    
  boxSelector: '.box',
  searchLayout: false,
  throttleTime: 150,
  marginRight: 20,//假如指定盒子最小边距为20像素
});

</script>
</body>
</html>

猜你喜欢

转载自blog.csdn.net/weixin_43954962/article/details/121441601