vuex2 implements time list selector

Table of contents

1. Effect display

2. Code analysis

2.1. Area determination and coordinate acquisition

2.2. Single click and one-time click

1. Effect display

 

  Mainly achieved with the help of custom instructions. Move the frame selection on the "tds" of the table. There are one-time frame selection and single frame selection. Remove the clearTargetNodes() in the custom instruction and the td will be continuous. After the continuous frame selection, the corresponding value will be obtained and can be assembled again. .

2. Code analysis

<template>
  <div>
    <table border="1" v-cellSelect="weekdayTimeData">
      <tr>
        <th rowspan="2">星期 / 时间</th>
        <th colspan="12">00:00 - 12:00</th>
        <th colspan="12">12:00 - 24:00</th>
      </tr>
      <tr>
        <th v-for="n in 24" :key="n">{
   
   { n - 1 }}</th>
      </tr>
      <tr v-for="n in 7" :key="n" :data-weekday="n - 1">
        <th class="weekday-title">{
   
   { weekdayTitle[n - 1] }}</th>
        <td v-for="m in 24" :key="m" :data-time="m - 1"></td>
      </tr>
    </table>
  </div>
</template>
<script>
export default {
  directives: {
    cellSelect: {
      bind(el, bindings) {
        el.addEventListener("mousedown", handleMouseDown, false);
        function handleMouseDown(e) {
          const tar = e.target;
          const tagName = tar.tagName.toLowerCase();
          const els = this;
          clearTargetNodes(els); //防止单个点击时"td"们连在一起。不加该函数,点击的"td"们会连在一起
          if (tagName === "td") {
            els.start = tar;
            const rowIndex = Number(els.start.parentNode.dataset.weekday);
            const columnIndex = Number(els.start.dataset.time);
            // ===========拿到移动开始时的最终坐标
            setWeekdayTimeData(els, rowIndex, columnIndex);
            addTargetNode(els, tar); //情况一:单个点击移动框选
            els.addEventListener("mousemove", handleMouseMove, false);
            els.addEventListener("mouseup", handleMouseUp, false);
          }
        }
        function handleMouseMove(e) {
          const tar = e.target;
          const tagName = tar.tagName.toLowerCase();
          const els = this;
          if (tagName === "td") {
            const startTarget = els.start;
            const endTarget = tar;
            const startRow = Number(startTarget.parentNode.dataset.weekday);
            const startColumn = Number(startTarget.dataset.time);
            const endRow = Number(endTarget.parentNode.dataset.weekday);
            const endColumn = Number(endTarget.dataset.time);
            // ===========拿到移动停止时的最终坐标
            const currentTargetNodes = getTargetNodes(
              els,
              startRow,
              startColumn,
              endRow,
              endColumn
            );
            // ============拿到起始到结束的所有td数组
            getTargetNodeDiff(els, els.targetNodes, currentTargetNodes);
          }
        }
        function getTargetNodes(els, startRow, startColumn, endRow, endColumn) {
          const { allRows } = els;
          const startR = startRow > endRow ? endRow : startRow;
          const startC = startColumn > endColumn ? endColumn : startColumn;
          const endR = startRow > endRow ? startRow : endRow;
          const endC = startColumn > endColumn ? startColumn : endColumn;
          const targetNodes = new Set(); //防止来回移动,造成冗余数据
          allRows.forEach((tr, rowIndex) => {
            if (rowIndex >= startR && rowIndex <= endR) {
              [...tr.querySelectorAll("td")].forEach((td, columnIndex) => {
                if (columnIndex >= startC && columnIndex <= endC) {
                  targetNodes.add(td);
                  setWeekdayTimeData(els, rowIndex, columnIndex);
                }
              });
            }
          });
          return targetNodes;
        }
        function getAllRows(el) {
          const oAllRows = el.querySelectorAll("tr"); //[tr, tr, tr, tr, tr, tr, tr, tr, tr]
          return [...oAllRows].reduce((prev, tr) => {
            if (tr.dataset.weekday) {
              prev.push(tr);
            }
            return prev;
          }, []);
        }
        function handleMouseUp() {
          const els = this;
          els.removeEventListener("mousemove", handleMouseMove, false);
          els.removeEventListener("mouseup", handleMouseUp, false);
        }
        el.allRows = getAllRows(el); //[tr, tr, tr, tr, tr, tr, tr],原本有9个,只取出带":data-weekday"的tr
        el.targetNodes = new Set();
        el.weekdayTimeData = bindings.value;
        //情况二:"一气呵成"点击移动框选
        function getTargetNodeDiff(els, targetNodes, currentTargetNodes) {
          // currentTargetNodes里面有,而targetNodes没有,就要增加
          currentTargetNodes.forEach((td) => {
            !targetNodes.has(td) && addTargetNode(els, td);
          });
          // targetNodes里面有,而currentTargetNodes没有,就要减少
          targetNodes.forEach((td) => {
            !currentTargetNodes.has(td) && removeTargetNode(els, td);
          });
        }
        function addTargetNode(el, target) {
          //框选完继续扩大面积
          el.targetNodes.add(target);
          target.classList.add("target");
        }
        function removeTargetNode(el, target) {
          //框选完缩小了面积
          el.targetNodes.delete(target);
          target.classList.remove("target");
        }
        function clearTargetNodes(el) {
          el.targetNodes.forEach((target) => {
            target.classList.remove("target");
          });
          el.targetNodes = new Set();
          el.weekdayTimeData = [];
        }
        function setWeekdayTimeData(el, weekday, time) {
          console.log(weekday, time, "el, weekday, time", el.weekdayTimeData);
          //结果:  [ {3: {0, 1, 2, 3}},{4:{0, 1, 2, 3}}]
          //参考: {0:[0,1,2,3]}===>星期一:00:00,01:00,02:00,03:00
          el.weekdayTimeData[weekday]
            ? el.weekdayTimeData[weekday].add(time)
            : (el.weekdayTimeData[weekday] = new Set([time]));
        }
      },
    },
  },
  data() {
    return {
      weekdayTimeData: [],
      weekdayTitle: [
        "星期一",
        "星期二",
        "星期三",
        "星期四",
        "星期五",
        "星期六",
        "星期日",
      ],
    };
  },
};
</script>
<style lang='less' scoped>
table {
  border-collapse: collapse;
  .weekday-title {
    width: 100px;
  }
  tr {
    height: 50px;
  }
  td {
    width: 50px;
    &.target {
      background-color: aqua;
    }
  }
}
</style>

2.1. Area determination and coordinate acquisition

(1) Bind a custom command to the table to get it itself, and get all the td (total area of ​​the box selection) when pressed. See the handleMouseDown() function.

(2) Prevent "td" from being connected together when a single click is made. Without this function, the clicked "td"s will be connected together, see clearTargetNodes() function

(3) Get the final coordinates when the movement starts: rowIndex, columnIndex;

    Get the final coordinates when the movement stops: startRow, startColumn, endRow, endColumn

(4) Get all the td arrays from the beginning to the end. See the getTargetNodes() function to prevent moving back and forth and causing redundant data . There are originally 9, and only the tr with ":data-weekday" is taken out.

2.2. Single click and one-time click

Scenario 1: Single click to move the frame selection

When handleMouseDown, directly call the addTargetNode() function

Scenario 2: "All in one go" click to move the frame selection

The comparison function getTargetNodeDiff is to compare the expansion/reduction of the original selection area:

There is one in currentTargetNodes, but not in targetNodes, so you need to add ==》After selecting the box, continue to expand the area addTargetNode()

There is one in targetNodes, but not in currentTargetNodes, so it needs to be reduced==》After the box selection is completed, the area is reduced removeTargetNode()

Guess you like

Origin blog.csdn.net/qq_44930306/article/details/131458351