Adaptive floating form fill layout script

Effect

1. Suitable for search form layout, function blocks such as query reset are always located in the last column of the last row
insert image description here

2. It is suitable for aligning both ends of ordinary multi-lines, and left-aligning unfilled lines
insert image description here

train of thought

  1. The purpose of this script is to achieve a neat style of form layout. In order to achieve a neat effect, each form element or block must be set to a consistent width
  2. The flex layout cannot adapt to the different alignment requirements of multiple lines. The grid needs to be additionally configured with different resolutions. This script only needs to set the block width and the default minimum interval of the block ( referring to the gray block in the rendering, defined in the script as box)
  3. Through the known block width and minimum interval, it is possible to calculate the maximum number of blocks that can be accommodated in a line, and calculate the new interval if the width is rich.
  4. The inaccuracy of floating-point operations requires the calculation of positive interpolation, which is amortized to each block with a right margin

the code

This version is jquerythe version, but it only borrows its event trigger function to adapt to screen scaling, and other functional scripts are all native js, which can be easily converted to other frameworks such asvue

Note that all blocks default tofloat: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>

Guess you like

Origin blog.csdn.net/weixin_43954962/article/details/121441601