美文网首页Element非官方分析js
Element分析(工具篇)——TableLayout

Element分析(工具篇)——TableLayout

作者: liril | 来源:发表于2017-02-16 15:25 被阅读1074次

    说明

    table-layout是对整个表格宽高等布局进行修改的。

    源码解读

    import scrollbarWidth from 'element-ui/src/utils/scrollbar-width';
    
    class TableLayout {
      constructor(options) {
        this.table = null;
        this.store = null;
        this.columns = null;
        this.fit = true;
        this.showHeader = true;
    
        this.height = null;
        this.scrollX = false;
        this.scrollY = false;
        this.bodyWidth = null;
        this.fixedWidth = null;
        this.rightFixedWidth = null;
        this.tableHeight = null;
        this.headerHeight = 44; // 表头高度
        this.viewportHeight = null; // 表格高度 - 滚动条的高度
        this.bodyHeight = null; // 表格高度 - 表头高度
        this.fixedBodyHeight = null; // 表格高度 - 表头高度 - 滚动条高度
        this.gutterWidth = scrollbarWidth();  // 滚动条宽度
    
        for (let name in options) {
          if (options.hasOwnProperty(name)) {
            this[name] = options[name];
          }
        }
    
        if (!this.table) {
          throw new Error('table is required for Table Layout');
        }
        if (!this.store) {
          throw new Error('store is required for Table Layout');
        }
      }
    
      /**
       * 更新 scrollY
       */
      updateScrollY() {
        const height = this.height;
        if (typeof height !== 'string' && typeof height !== 'number') return;
        const bodyWrapper = this.table.bodyWrapper;
        if (this.table.$el && bodyWrapper) {
          const body = bodyWrapper.querySelector('.el-table__body');
          this.scrollY = body.offsetHeight > bodyWrapper.offsetHeight;
        }
      }
    
      /**
       * 设置高度
       * @param value 高度值
       * @param prop 设置的属性名
       */
      setHeight(value, prop = 'height') {
        const el = this.table.$el;
        if (typeof value === 'string' && /^\d+$/.test(value)) {
          value = Number(value);
        }
    
        this.height = value;
    
        if (!el) return;  // 没有挂载的的 DOM
        if (typeof value === 'number') {
          el.style[prop] = value + 'px';
    
          this.updateHeight();
        } else if (typeof value === 'string') {
          this.updateHeight();
        }
      }
    
      /**
       * 设置最高高度
       * @param value 高度值
       * @returns {*}
       */
      setMaxHeight(value) {
        return this.setHeight(value, 'max-height');
      }
    
      /**
       * 更新高度
       */
      updateHeight() {
        const height = this.tableHeight = this.table.$el.clientHeight;
        const noData = !this.table.data || this.table.data.length === 0;
        const { headerWrapper } = this.table.$refs;
        if (this.showHeader && !headerWrapper) return;  // 如果要显示 header,却没 headerWrapper
        if (!this.showHeader) {  // 如果不显示表头
          this.headerHeight = 0;  // 表头高度为 0
          if (this.height !== null && (!isNaN(this.height) || typeof this.height === 'string')) {
            this.bodyHeight = height;  // 说明表的主体部分充斥了整个表格
          }
          // 固定表体的高度
          this.fixedBodyHeight = this.scrollX ? height - this.gutterWidth : height;
        } else {  // 如果显示表头
          const headerHeight = this.headerHeight = headerWrapper.offsetHeight;
          const bodyHeight = height - headerHeight;
          if (this.height !== null && (!isNaN(this.height) || typeof this.height === 'string')) {
            this.bodyHeight = bodyHeight;
          }
          this.fixedBodyHeight = this.scrollX ? bodyHeight - this.gutterWidth : bodyHeight;
        }
        this.viewportHeight = this.scrollX ? height - (noData ? 0 : this.gutterWidth) : height;
      }
    
      /**
       * 更新
       */
      update() {
        const fit = this.fit;
        const columns = this.table.columns;
        const bodyWidth = this.table.$el.clientWidth;
        let bodyMinWidth = 0;
    
        const flattenColumns = [];
        columns.forEach((column) => {
          if (column.isColumnGroup) {  // 如果是列组,就放入其包含的列
            flattenColumns.push.apply(flattenColumns, column.columns);
          } else {
            flattenColumns.push(column);
          }
        });
    
        // 自适应的列
        let flexColumns = flattenColumns.filter((column) => typeof column.width !== 'number');
    
        // 如果有自适应的列,并且规定了自适应
        if (flexColumns.length > 0 && fit) {
          flattenColumns.forEach((column) => {
            bodyMinWidth += column.width || column.minWidth || 80;
          });
    
          if (bodyMinWidth < bodyWidth - this.gutterWidth) { // DON'T HAVE SCROLL BAR 没有滚动条
            this.scrollX = false;  // 没有横向滚动条
    
            const totalFlexWidth = bodyWidth - this.gutterWidth - bodyMinWidth;  // 剩余可分配的宽度
    
            if (flexColumns.length === 1) {  // 如果自适应的列只有一个
              flexColumns[0].realWidth = (flexColumns[0].minWidth || 80) + totalFlexWidth;
            } else {
              // 总宽度
              const allColumnsWidth = flexColumns.reduce((prev, column) => prev + (column.minWidth || 80), 0);
              // 平分
              const flexWidthPerPixel = totalFlexWidth / allColumnsWidth;
    
              let noneFirstWidth = 0;
    
              // 按比例平分宽度
              flexColumns.forEach((column, index) => {
                if (index === 0) return;
                const flexWidth = Math.floor((column.minWidth || 80) * flexWidthPerPixel);
                noneFirstWidth += flexWidth;
                column.realWidth = (column.minWidth || 80) + flexWidth;
              });
    
              // 剩余宽度都放到第一列
              flexColumns[0].realWidth = (flexColumns[0].minWidth || 80) + totalFlexWidth - noneFirstWidth;
            }
          } else { // HAVE HORIZONTAL SCROLL BAR 如果有垂直滚动条
            this.scrollX = true;
            flexColumns.forEach(function(column) {
              column.realWidth = column.minWidth;
            });
          }
    
          this.bodyWidth = Math.max(bodyMinWidth, bodyWidth);
        } else {  // 如果没有自适应的
          flattenColumns.forEach((column) => {
            // 根据 width、minWidth、80 的顺序设置高度
            if (!column.width && !column.minWidth) {
              column.realWidth = 80;
            } else {
              column.realWidth = column.width || column.minWidth;
            }
    
            bodyMinWidth += column.realWidth;
          });
          // 设置是否有横向的滚动
          this.scrollX = bodyMinWidth > bodyWidth;
    
          this.bodyWidth = bodyMinWidth;
        }
    
        const fixedColumns = this.store.states.fixedColumns;
    
        // 如果有左侧固定列
        if (fixedColumns.length > 0) {
          // 计算固定列的宽度
          let fixedWidth = 0;
          fixedColumns.forEach(function(column) {
            fixedWidth += column.realWidth;
          });
    
          this.fixedWidth = fixedWidth;
        }
    
        // 计算右侧固定咧的宽度
        const rightFixedColumns = this.store.states.rightFixedColumns;
        if (rightFixedColumns.length > 0) {
          let rightFixedWidth = 0;
          rightFixedColumns.forEach(function(column) {
            rightFixedWidth += column.realWidth;
          });
    
          this.rightFixedWidth = rightFixedWidth;
        }
      }
    }
    
    export default TableLayout;
    
    

    相关文章

      网友评论

        本文标题:Element分析(工具篇)——TableLayout

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