1

目标

单元格宽高固定,当随着单元格内字数增加,当单元格不足以容纳当前字号的内容时,自动缩小字号(达到最小字号不再缩放),如下图

image.png

参考案例

技术说明

  1. 给原来单元格增加一个子级div和一个孙级div
  2. 子级div继承原来单元格宽高
  3. 以孙级div的高度不超过父级div的高度为边界,自动缩小字体大小

ps: cells对象中的属性type,会随着type的变化而给原单元格增加不同的class,所以增加2个额外的div,不修改原jsspreadsheet的设计,以免发生不可预测的意外,如下图2。

image.png

image.png

代码

<html>
  <script src="https://jspreadsheet.com/v8/jspreadsheet.js"></script>
  <script src="https://jsuites.net/v5/jsuites.js"></script>
  <link
    rel="stylesheet"
    href="https://jspreadsheet.com/v8/jspreadsheet.css"
    type="text/css"
  />
  <link
    rel="stylesheet"
    href="https://jsuites.net/v5/jsuites.css"
    type="text/css"
  />

  <div id="spreadsheet"></div>

  <script>
    function initSheet() {
      jspreadsheet.setLicense(
        "MDkyYTljZTJmYzA2MGVkOWVjOTJhMTYxNjg5NDg4YzcwNDE0OWJjZjVkZTJmMzI0NmU2MjQxMjZmNWI4YjYwOTI1N2UxOWJkY2ViZmFkOGE2YTMwNDA1MjExMzcyYzkyMTVkMWFhMjk0M2VmOTZkNzlmNzFjM2U4NTlhZWJkMjYsZXlKdVlXMWxJam9pU25Od2NtVmhaSE5vWldWMElpd2laR0YwWlNJNk1UY3dNVEV6T0RZNU1Td2laRzl0WVdsdUlqcGJJbXB6Y0hKbFlXUnphR1ZsZEM1amIyMGlMQ0pqYjJSbGMyRnVaR0p2ZUM1cGJ5SXNJbXB6YUdWc2JDNXVaWFFpTENKamMySXVZWEJ3SWl3aWQyVmlJaXdpYkc5allXeG9iM04wSWwwc0luQnNZVzRpT2lJek5DSXNJbk5qYjNCbElqcGJJblkzSWl3aWRqZ2lMQ0oyT1NJc0luWXhNQ0lzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklsMHNJbVJsYlc4aU9uUnlkV1Y5"
      );

      const sheetOptions = {
        data: [
          [
            "工程名称工工程名名称程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程",
          ],
          [
            "工程名称工工程名名称程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程",
            "1000",
          ],
          [
            "工程名称工工工程名称工程称工程名称称工程名称工程名称工程名称工程名称工程名称工程名称工程名称工工程名称工程名称工程名称工程名称工程名称工程名称工程名称工程名称程名称工程名",
            "500",
          ],
        ],
        columns: [{ width: "300px" }, { width: "200px" }],
        rows: {
          0: { height: "100px" },
          1: { height: "50px" },
          2: { height: "50px" },
        },
        cells: {
          A1: { type: "text", isshrinkToFit: false },
          A2: { type: "text", isshrinkToFit: true },
          A3: { type: "html", isshrinkToFit: true },
        },
        //此处为事件监听,如根据业务需要,初始化或者后续合,如下: sheetEvents
        // onchange: function (instance, cell, x, y, value) {
        //   replaceCell(cell);
        // },
      };

      const sheetEvents = {
        onchange: function (instance, cell, x, y, value) {
          replaceCell(cell);
        },
      };

      Object.assign(sheetOptions, sheetEvents);
      sheet = jspreadsheet(
        document.getElementById("spreadsheet"),
        sheetOptions
      );
    }

    function replaceCells(sheet) {
      const config = sheet.getConfig();
      const shrinkToFitCells = [];

      // 找到需要自适应字体的单元格
      for (let key in config.cells) {
        if (config.cells[key]["isshrinkToFit"]) {
          shrinkToFitCells.push(key);
        }
      }

      //根据单元格名字(cellName),找到对应的dom元素
      //如: A1=> <div data-x="0" data-y="0"></div>
      shrinkToFitCells.forEach((item) => {
        const cellXY = jspreadsheet.helpers.getCoordsFromColumnName(item);
        const cell = document.querySelector(
          `td[data-x='${cellXY[0]}'][data-y='${cellXY[1]}']`
        );
        replaceCell(cell);
      });
    }

    //给原来单元格增加一个子级div和一个孙级div
    //子级div继承原来单元格宽高
    //以孙级div的高度不超过父级div的高度为边界,自动缩小字体大小
    function replaceCell(cell, unit = "px") {
      let maxContainer = document.createElement("div");
      let textContainer = document.createElement("div");

      textContainer.innerHTML = cell.innerHTML;
      cell.innerHTML = "";
      cell.style.whiteSpace = "initial";
      cell.style.padding = 0;

      maxContainer.style.height = cell.offsetHeight + unit;
      maxContainer.style.weight = cell.offsetWidth + unit;

      cell.append(maxContainer);
      maxContainer.append(textContainer);

      shrinkToFit(maxContainer, textContainer);
    }

    /**
     * 根据文字个数自动适配单元格
     * @param maxContainer 单元格子容器,文字容器最大边界
     * @param textContainer 文字容器
     * @param fontSize 原字体大小
     * @param mixFontSize 最小字体大小
     * @param unit 计量单位
     * @return
     */
    function shrinkToFit(
      maxContainer,
      textContainer,
      fontSize = 14,
      mixFontSize = 8,
      unit = "pt"
    ) {
      const maxContainerHeight = maxContainer.offsetHeight;
      const maxContainerWidth = maxContainer.offsetWidth;
      let textContainerHeight;
      let textContainerWidth;
      //此处用do while 至少执行一次
      do {
        console.log("fontSize", fontSize);
        textContainer.style.fontSize = fontSize + unit;
        textContainer.style.lineHeight = fontSize + unit;
        textContainerHeight = textContainer.offsetHeight;
        textContainerWidth = textContainer.offsetWidth;
        fontSize--;
      } while (
        (textContainerHeight > maxContainerHeight ||
          textContainerWidth > maxContainerWidth) &&
        fontSize > mixFontSize
      );
    }
  </script>
  <script>
    let sheet = "";
    initSheet();
    replaceCells(sheet);
  </script>
</html>

数据设计

cells

给cell增加额外的isShrinkToFit,用于判断该单元格是否要做字体自适应
ps: 可根据业务调整isShrinkToFit属性的存放位置,与产品和后端人员沟通

        cells: {
          A1: { type: "text", isShrinkToFit: false },
          A2: { type: "text", isShrinkToFit: true },
          A3: { type: "html", isShrinkToFit: true },
            ....
        },

image.png

参考链接

rows

用于固定单元格的高度

        rows: {
          0: { height: "100px" },
          1: { height: "50px" },
          2: { height: "50px" },
        },

image.png

columns

用于固定单元格的宽度
ps:当前业务暂不需要
参考链接


aaaa
5 声望0 粉丝