一、实现如图所示功能

在这里插入图片描述

二、鼠标mousedown事件和click事件重复,不设置click事件可以达到相同效果
// 代码如下
<template>
  <el-dialog
    title="时间段选择"
    :visible.sync="dialogVisible"
    :close-on-click-modal="false"
    custom-class="custom-dialog-style"
    width="1000px"
    :close="close"
  >
    <div class="container">
      <div class="wrap">
        <div class="left">
          <div class="merge-column">星期/时间</div>
          <div class="td-title" v-for="(weekItem, index) in week" :key="index">{{ weekItem }}</div>
        </div>
        <div class="right">
          <div class="top">
            <div class="merge-row">00:00-12:00</div>
            <div class="merge-row">12:00-24:00</div>
            <div class="unit" v-for="(item, index) in 24" :key="index">{{ index }}</div>
          </div>
          <div class="bottom" @mousedown="handleMouseDown">
            <div
              :style="'width:' + mask_width + 'left:' + mask_left + 'height:' + mask_height + 'top:' + mask_top"
              v-show="positionList.is_show_mask"
              class="mask"
            ></div>
            // 鼠标mousedown事件和click事件重复,不设置click事件可以达到相同效果 @click="handleClickSelected(item)"
            <div
              class="select-item"
              v-for="(item, index) in dataItem"
              :key="index"
              :class="{selected: item.selected ? true : false}"
            ></div>
          </div>
        </div>
      </div>
    </div>
    <div slot="footer">
      <el-button @click="close">取 消</el-button>
      <el-button type="primary" @click="submit">确 定</el-button>
    </div>
  </el-dialog>
</template>

<script>
const positionList = {
  is_show_mask: false,
  box_screen_left: 0, // 盒子距离浏览器左侧的距离
  box_screen_top: 0, //盒子距离浏览器顶部的距离
  start_x: 0,
  start_y: 0,
  end_x: 0,
  end_y: 0
};
export default {
  data() {
    return {
      dialogVisible: false,
      week: ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"],
      totalNum: 336,
      dataItem: [],
      isClick: true,
      positionList: {...positionList}
    };
  },
  computed: {
    mask_width() {
      return `${Math.abs(this.positionList.end_x - this.positionList.start_x)}px;`;
    },
    mask_height() {
      return `${Math.abs(this.positionList.end_y - this.positionList.start_y)}px;`;
    },
    mask_left() {
      return `${Math.min(this.positionList.start_x, this.positionList.end_x) - this.positionList.box_screen_left}px;`;
    },
    mask_top() {
      return `${Math.min(this.positionList.start_y, this.positionList.end_y) - this.positionList.box_screen_top}px;`;
    }
  },
  methods: {
    init() { // ref 调用init弹窗即可
      this.dialogVisible = true;
      this.initList();
    },
    initList() {
      for (let i = 1; i <= this.totalNum; i++) {
        let map = {
          selected: false,
          key: i
        };
        this.dataItem.push(map);
      }
    },
    setData(value) {
      this.initList();
      value.forEach((v) => {
        this.dataItem[v-1].selected = true;
      });
    },
    handleMouseDown(event) {
      this.positionList.is_show_mask = true;
      this.positionList.start_x = event.clientX;
      this.positionList.start_y = event.clientY;
      this.positionList.end_x = event.clientX;
      this.positionList.end_y = event.clientY;
      this.positionList.box_screen_left = document.querySelector(".bottom").getBoundingClientRect().left;
      this.positionList.box_screen_top = document.querySelector(".bottom").getBoundingClientRect().top;
      document.body.addEventListener("mousemove", this.handleMouseMove); //监听鼠标移动事件
      document.body.addEventListener("mouseup", this.handleMouseUp); //监听鼠标抬起事件
    },
    handleMouseMove(event) {
      this.positionList.end_x = event.clientX;
      this.positionList.end_y = event.clientY;
    },
    handleMouseUp(event) {
      document.body.removeEventListener("mousemove", this.handleMouseMove);
      document.body.removeEventListener("mouseup", this.handleMouseUp);
      this.positionList = {...positionList};
      this.positionList.is_show_mask = false;
      this.handleDomSelect();
      this.resSetXY();
    },
    handleDomSelect() {
      const dom_mask = window.document.querySelector(".mask");
      // getClientRects()方法 每一个盒子的边界矩形的矩形集合
      const rect_select = dom_mask.getClientRects()[0];
      document.querySelectorAll(".select-item").forEach((node, index) => {
        const rects = node.getClientRects()[0];
        if (this.collide(rects, rect_select) === true) {
          this.dataItem[index].selected = !this.dataItem[index].selected;
        }
      });
    },
    collide(rect1, rect2) {
      const maxX = Math.max(rect1.x + rect1.width, rect2.x + rect2.width);
      const maxY = Math.max(rect1.y + rect1.height, rect2.y + rect2.height);
      const minX = Math.min(rect1.x, rect2.x);
      const minY = Math.min(rect1.y, rect2.y);
      return maxX - minX <= rect1.width + rect2.width && maxY - minY <= rect1.height + rect2.height;
    },
    resSetXY() {
      this.positionList.start_x = 0;
      this.positionList.start_y = 0;
      this.positionList.end_x = 0;
      this.positionList.end_y = 0;
    },
    handleClickSelected(item) {
      item.selected = !item.selected;
    },
    close() {
      this.dialogVisible = false;
      this.dataItem = [];
    },
    submit() {
      const list = [];
      for (let i = 0; i < this.dataItem.length; i++) {
        if (this.dataItem[i].selected == true) {
          list.push(this.dataItem[i].key);
        }
      }
      if (list.length == 0) {
        this.$message({
          message: "请选择时间段",
          type: "warning"
        });
        return;
      } else {
        this.close();
        this.$emit("event-data", list);
      }
    }
  }
};
</script>

<style lang="scss" scoped>
.container {
  .wrap {
    display: flex;
    border: 1px solid #f1f1f1;
    border-bottom: 0;
    .left {
      .merge-column {
        width: 4vw;
        height: 6vh;
        padding: 3px 5px;
        min-width: 76px;
        min-height: 55px;
        display: flex;
        align-items: center;
        border-right: 1px solid #f1f1f1;
        border-bottom: 1px solid #f1f1f1;
      }
      .td-title {
        width: 4vw;
        height: 3vh;
        min-height: 27px;
        min-width: 76px;
        padding: 3px 5px;
        text-align: center;
        border-right: 1px solid #f1f1f1;
        border-bottom: 1px solid #f1f1f1;
      }
      &:last-child {
        border-bottom: 0;
      }
    }
    .right {
      display: flex;
      flex-wrap: wrap;
      .top {
        width: 100%;
        display: flex;
        flex-wrap: wrap;
        align-content: flex-start;
        .merge-row {
          width: 50%;
          height: 3vh;
          padding: 3px 5px;
          min-width: 420px;
          min-height: 27px;
          text-align: center;
          border-right: 1px solid #f1f1f1;
          border-bottom: 1px solid #f1f1f1;
          &:nth-child(2) {
            border-right: 0;
          }
        }
        .unit {
          width: calc(100% / 24);
          height: 3vh;
          padding: 3px 5px;
          min-width: 35px;
          min-height: 27px;
          text-align: center;
          border-right: 1px solid #f1f1f1;
          border-bottom: 1px solid #f1f1f1;
          &:last-child {
            border-right: 0;
          }
        }
      }
      .bottom {
        width: 100%;
        position: relative;
        display: flex;
        flex-wrap: wrap;
        .mask {
          position: absolute;
          background: #409eff;
          opacity: 0.4;
          z-index: 100;
          left: 0;
          top: 0;
        }
        .select-item {
          width: calc(100% / 48);
          height: 3vh;
          min-width: 17px;
          min-height: 27px;
          cursor: pointer;
          padding: 3px 5px;
          border-right: 1px solid #f1f1f1;
          border-bottom: 1px solid #f1f1f1;
          &:hover {
            background: #f1f1f1;
          }
        }
        .selected {
          background: #7bc8ff;
          &:hover {
            background: #7bc8ff;
          }
        }
        *:nth-child(48n + 1) {
          border-right: 0;
        }
      }
    }
  }
}
</style>
参考文章:https://blog.csdn.net/qq_37656005/article/details/123656240
Logo

前往低代码交流专区

更多推荐