Element分析(工具篇)——TableLayout

说明

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;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,511评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,495评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,595评论 0 225
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,558评论 0 190
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,715评论 3 270
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,672评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,112评论 2 291
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,837评论 0 181
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,417评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,928评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,316评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,773评论 2 234
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,253评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,827评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,440评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,523评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,583评论 2 249

推荐阅读更多精彩内容

  • 问答题47 /72 常见浏览器兼容性问题与解决方案? 参考答案 (1)浏览器兼容问题一:不同浏览器的标签默认的外补...
    _Yfling阅读 13,611评论 1 92
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,471评论 25 707
  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,158评论 0 17
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,551评论 4 58
  • 自从遇到你, 我的PH 总是小于7。
    似与游者相乐阅读 211评论 0 0