美文网首页我爱编程Web前端之路
js 实现table表格拖拽改变列宽 (javascript r

js 实现table表格拖拽改变列宽 (javascript r

作者: EdmundChen | 来源:发表于2017-08-07 10:55 被阅读667次

    javascript 可拖动table列宽的library

    demo

    http://uso.oschina.io/resizable-colmuns-table

    github地址

    https://github.com/uso51984/resizable-columns-table

    调用方法

        createColResizable(domElemTable,options)
    options = {
        liveDrag: true, // 是否实时拖动
        defaultMinWidth: 30, //默认没列最小宽度
        headerOnly: true, // 拖动竖线是否只有thead
        disabledColumns: [], //不能拖动的th
        onResizing: null, // 正在拖动callback
        onResized: null // 拖动结束callback
    }
    # 每列单独宽度需要在对应th加入 自定义属性 data-min-width="number", eg:  data-min-width="300"
    
    • domElem 传入table dom元素
    • options 对象(可选)

    table 结构

          <table>
            <thead>
              <tr>
                <th></th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td>Mark</td>
              </tr>
            </tbody>
          </table>
    # 例如
          <table>
            <thead>
              <tr>
                <th>#</th>
                <th>First Name</th>
                <th>Last Name</th>
                <th>Username</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <th scope="row">1</th>
                <td>Mark</td>
                <td>Otto</td>
                <td>@mdo</td>
              </tr>
              <tr>
                <th scope="row">2</th>
                <td>Jacob</td>
                <td>Thornton</td>
                <td>@fat</td>
              </tr>
              <tr>
                <th scope="row">3</th>
                <td>Larry</td>
                <td>the Bird</td>
                <td>@twitter</td>
              </tr>
            </tbody>
          </table>
    

    代码

    index.js
    import isElement from 'lodash/isElement';
    import ColResizable from './colResizable';
    import '../style/index.less';
    
    const createColResizable = (domEleTable, options) => {
      if (isElement(domEleTable) && domEleTable.nodeName === 'TABLE') {
        return domEleTable.__resizable ||
          (domEleTable.__resizable = new ColResizable(domEleTable, options));
      }
    
      return null;
    };
    
    export default createColResizable;
    
    index.js
    import isFunction from 'lodash/isFunction';
    import isArray from 'lodash/isArray';
    import {
      tryParseInt,
      removeClass,
      addClass
    } from './utils';
    
    export default class ColResizable {
      static defaults = {
        liveDrag: true,
        defaultMinWidth: 30,
        headerOnly: true,
        disabledColumns: [],
        onResizing: null,
        onResized: null
      };
    
      constructor(domElmTable, options = {}) {
        this.options = { ...ColResizable.defaults, ...options };
        this.domElmTable = domElmTable;
    
        this.onGripMouseDown = this.onGripMouseDown.bind(this);
        this.onMouseMove = this.onMouseMove.bind(this);
        this.onMouseUp = this.onMouseUp.bind(this);
    
        this.init();
      }
    
      init() {
        addClass(this.domElmTable, 'table-col-resizer');
    
        this.domElmHandleList = [];
        this.domElmTableTheadThList = [];
        this.tableWidth = `${this.domElmTable.offsetWidth}px`;
    
        this.cellSpacing = tryParseInt(getComputedStyle(this.domElmTable).getPropertyValue('border-spacing'));
        this.borderLeftWidth = tryParseInt(getComputedStyle(this.domElmTable).getPropertyValue('border-left-width'));
    
        this.createGrips();
      }
    
      createGrips() {
        const thList = this.domElmTable.querySelectorAll('thead th');
    
        const domElmThList = [];
        this.domElmHandleContainer = this.domElmTable.previousSibling;
        const hasHandleContainer = this.domElmHandleContainer && this.domElmHandleContainer.className === 'col-resize-container';
    
        if (!hasHandleContainer) {
          this.domElmTable.insertAdjacentHTML('beforebegin', '<div class="col-resize-container"/>');
          this.domElmHandleContainer = this.domElmTable.previousSibling;
        } else {
          Array.prototype.push.apply(this.domElmHandleList, this.domElmHandleContainer.childNodes);
        }
    
        Array.prototype.push.apply(domElmThList, thList);
        this.thLength = domElmThList.length;
        this.lastThIndex = this.thLength - 1;
    
        let { disabledColumns } = this.options;
    
        if (!isArray(disabledColumns)) {
          disabledColumns = [];
        }
    
        domElmThList.forEach((domElmTh, index) => {
          const disabledColumn = disabledColumns.indexOf(index) !== -1;
          let domElmHandle;
          if (!hasHandleContainer) {
            this.domElmHandleContainer.insertAdjacentHTML('beforeend',
            `<div class="drag-handle">
              <i class="icon icon-caret-right"></i>
              <div class="col-resizer"></div>
              <i class="icon icon-caret-left"></i>
            </div>`
            );
            domElmHandle = this.domElmHandleContainer.lastChild;
          } else {
            domElmHandle = this.domElmHandleList[index];
          }
    
          if (index === this.lastThIndex && !hasHandleContainer) {
            addClass(domElmHandle, 'last-handle');
          }
    
          if (!disabledColumn && !hasHandleContainer) {
            domElmHandle.addEventListener('mousedown', this.onGripMouseDown);
          } else if (disabledColumn && !hasHandleContainer) {
            addClass(domElmHandle, 'disabled-drag');
          }
    
          domElmHandle.index = index;
          domElmTh.w = domElmTh.offsetWidth;
    
          domElmTh.style.width = `${domElmTh.offsetWidth}px`;
          if (!hasHandleContainer) {
            this.domElmHandleList.push(domElmHandle);
          }
          this.domElmTableTheadThList.push(domElmTh);
        });
        this.syncGrips();
      }
    
      syncGrips() {
        const { headerOnly } = this.options;
        const theadHight = this.domElmTableTheadThList[0].offsetHeight;
    
        let height;
        if (headerOnly) {
          height = theadHight;
        } else {
          height = this.domElmTable.offsetHeight;
        }
    
        for (let i = 0; i < this.thLength; i += 1) {
          const domElmTh = this.domElmTableTheadThList[i];
    
          let left;
          if (i === 0) {
            left = domElmTh.offsetWidth + (this.cellSpacing / 2);
          } else {
            const handleColLeft = this.domElmHandleList[i - 1].style.left + (this.cellSpacing / 2);
            left = tryParseInt(handleColLeft) + domElmTh.offsetWidth;
          }
    
          this.domElmHandleList[i].style.left = `${left}px`;
          this.domElmHandleList[i].style.height = `${height}px`;
        }
    
        const domElmIconList = [];
        const iconHeight = this.domElmHandleContainer.querySelector('.col-resize-container .icon').offsetHeight;
    
        const domElemIcons = this.domElmHandleContainer.querySelectorAll('.col-resize-container .icon');
        Array.prototype.push.apply(domElmIconList, domElemIcons);
    
        domElmIconList.forEach((el) => {
          const marginTopNumber = (theadHight - iconHeight) / 2;
          el.style.marginTop = `${tryParseInt(marginTopNumber)}px`;
        });
      }
    
      onGripMouseDown(e) {
        e.preventDefault();
        const { index } = e.currentTarget;
        const domElmHandle = this.domElmHandleList[index];
    
        addClass(domElmHandle, 'active-drag');
    
        domElmHandle.initPageLeftX = e.pageX;
        domElmHandle.initLeft = tryParseInt(domElmHandle.style.left);
        domElmHandle.x = domElmHandle.initLeft;
        this.drag = domElmHandle;
    
        document.addEventListener('mousemove', this.onMouseMove);
        document.addEventListener('mouseup', this.onMouseUp);
    
        return false;
      }
    
      onMouseMove(e) {
        e.preventDefault();
        if (!this.drag) {
          return false;
        }
    
        const { defaultMinWidth } = this.options;
        const index = this.drag.index;
    
        const minWidth = defaultMinWidth;
        const pageLeftX = e.pageX;
        let x = (pageLeftX - this.drag.initPageLeftX) + this.drag.initLeft;
    
        const l = (this.cellSpacing * 1.5) + minWidth + this.borderLeftWidth;
        const min = index ? tryParseInt(this.domElmHandleList[index - 1].style.left)
          + this.cellSpacing + minWidth : l;
    
        const max = tryParseInt(this.domElmHandleList[index + 1].style.left)
          - this.cellSpacing - minWidth;
    
        x = Math.max(min, Math.min(max, x));
    
        const inc = x - this.drag.initLeft;
        const domElmThNow = this.domElmTableTheadThList[index];
        const domElmThElmNext = this.domElmTableTheadThList[index + 1];
    
        const w = domElmThNow.w + inc;
        const w2 = domElmThElmNext.w - inc;
        const minWidthOne = tryParseInt(this.domElmTableTheadThList[index].getAttribute('data-min-width'));
        const minWidthTwo = tryParseInt(this.domElmTableTheadThList[index + 1].getAttribute('data-min-width'));
    
        if (minWidthOne > w) {
          x = (minWidthOne - domElmThNow.w) + this.drag.initLeft;
        } else if (minWidthTwo > w2) {
          x = (domElmThElmNext.w - minWidthTwo) + this.drag.initLeft;
        }
    
        this.drag.x = x;
        this.drag.style.left = `${x}px`;
    
        if (this.options.liveDrag) {
          this.syncCols(index);
          this.syncGrips();
          const { onResizing } = this.options;
    
          if (isFunction(onResizing)) {
            onResizing(e);
          }
        }
    
        return false;
      }
    
      syncCols(i, isOver) {
        const inc = this.drag.x - this.drag.initLeft;
        const domElmThNow = this.domElmTableTheadThList[i];
        const domElmThNext = this.domElmTableTheadThList[i + 1];
    
        const w = domElmThNow.w + inc;
        const w2 = domElmThNext.w - inc;
    
        domElmThNow.style.width = `${w}px`;
        domElmThNext.style.width = `${w2}px`;
    
        if (isOver) {
          domElmThNow.w = w;
          domElmThNext.w = w2;
        }
      }
    
      onMouseUp(e) {
        document.removeEventListener('mouseup', this.onMouseUp);
        document.removeEventListener('mousemove', this.onMouseMove);
    
        if (!this.drag) {
          return false;
        }
    
        removeClass(this.drag, 'active-drag');
        if (!(this.drag.x - this.drag.initLeft === 0)) {
          const index = this.drag.index;
          this.syncCols(index, true);
          this.syncGrips();
    
          const { onResized } = this.options;
          if (isFunction(onResized)) {
            onResized(e);
          }
        }
        this.drag = null;
    
        return true;
      }
    }
    
    utils.js
    import parseInt from 'lodash/parseInt';
    
    export const tryParseInt = (value, defaultValue = 0) => {
      const resultValue = parseInt(value);
    
      if (isNaN(resultValue)) {
        return defaultValue;
      }
      return resultValue;
    };
    
    
    export function addClass(elm, className) {
      if (!className) return;
    
      const els = Array.isArray(elm) ? elm : [elm];
    
      els.forEach((el) => {
        if (el.classList) {
          el.classList.add(className.split(' '));
        } else {
          el.className += ` ${className}`;
        }
      });
    }
    
    export function removeClass(elm, className) {
      if (!className) return;
    
      const els = Array.isArray(elm) ? elm : [elm];
    
      els.forEach((el) => {
        if (el.classList) {
          el.classList.remove(className.split(' '));
        } else {
          el.className = el.className.replace(new RegExp(`(^|\\b)${className.split(' ').join('|')}(\\b|$)`, 'gi'), ' ');
        }
      });
    }
    
    index.less
    import parseInt from 'lodash/parseInt';
    
    export const tryParseInt = (value, defaultValue = 0) => {
      const resultValue = parseInt(value);
    
      if (isNaN(resultValue)) {
        return defaultValue;
      }
      return resultValue;
    };
    
    
    export function addClass(elm, className) {
      if (!className) return;
    
      const els = Array.isArray(elm) ? elm : [elm];
    
      els.forEach((el) => {
        if (el.classList) {
          el.classList.add(className.split(' '));
        } else {
          el.className += ` ${className}`;
        }
      });
    }
    
    export function removeClass(elm, className) {
      if (!className) return;
    
      const els = Array.isArray(elm) ? elm : [elm];
    
      els.forEach((el) => {
        if (el.classList) {
          el.classList.remove(className.split(' '));
        } else {
          el.className = el.className.replace(new RegExp(`(^|\\b)${className.split(' ').join('|')}(\\b|$)`, 'gi'), ' ');
        }
      });
    }
    
    

    相关文章

      网友评论

        本文标题:js 实现table表格拖拽改变列宽 (javascript r

        本文链接:https://www.haomeiwen.com/subject/ylmolxtx.html