仿今日头条 时间段选择器组件封装

增加鼠标拖动多选择
看代码吧!
 

首先看代码使用

<el-form-item label="呼叫时间段:" ref="outTimes" prop="outboundTime"
            >(最小可选呼叫时间段为1小时,双击已选中时间段可取消选择)<br />
            <div class="timeul">
              <drag-weektime
                v-model="outboundTime"
                :data="weektimeData"
                @on-clear="clearWeektime"
              />
            </div>
          </el-form-item>

//js

import DragWeektime from "./date.vue";
import weektimeData from "./weektime_data";

components: { DragWeektime },
  computed: {
    outboundTime() {
      return this.weektimeData.map((item) => {
        return {
          id: item.row,
          week: item.value,
          value: this.splicing(item.child),
        };
      });
    },
  },
 created() {
    this.weektimeData = weektimeData;
  },
  mounted() {
    this.weektimeData = weektimeData;
  },
data(){
    return {
        weektimeData: [],
        outboundData: "",
    }
},

methods:{
    clearWeektime() {
      this.weektimeData.forEach((item) => {
        item.child.forEach((t) => {
          this.$set(t, "check", false);
        });
      });
    },

    splicing(list) {
      let same;
      let i = -1;
      const len = list.length;
      const arr = [];

      if (!len) return;
      while (++i < len) {
        const item = list[i];
        if (item.check) {
          if (item.check !== Boolean(same)) {
            arr.push(...["、", item.begin, "~", item.end]);
          } else if (arr.length) {
            arr.pop();
            arr.push(item.end);
          }
        }
        same = Boolean(item.check);
      }
      arr.shift();
      this.outboundData = arr.join("");
      return arr.join("");
    },
}

date.vue
 

<template>
  <div class="c-weektime">
    <div class="c-schedue"></div>
    <div
      :class="{ 'c-schedue': true, 'c-schedue-notransi': mode }"
      :style="styleValue"
    ></div>
    <table :class="{ 'c-min-table': colspan < 2 }" class="c-weektime-table">
      <tbody class="c-weektime-body">
        <tr v-for="t in data" :key="t.row">
          <td
            v-for="n in t.child"
            :key="`${n.row}-${n.col}`"
            :data-week="n.row"
            :data-time="n.col"
            :class="selectClasses(n)"
            @mouseenter="cellEnter(n)"
            @mousedown="cellDown(n)"
            @mouseup="cellUp(n)"
            class="weektime-atom-item"
          ></td>
        </tr>
        <tr>
          <td v-for="t in theadArr" :key="t" :colspan="colspan">{{ t }}:00</td>
        </tr>
      </tbody>
    </table>
  </div>
</template>
<script>
const createArr = (len) => {
  return Array.from(Array(len)).map((ret, id) => id);
};
export default {
  name: "DragWeektime",
  props: {
    value: {
      type: Array,
      required: true,
    },
    data: {
      type: Array,
      required: true,
    },
    colspan: {
      type: Number,
      default() {
        return 2;
      },
    },
  },
  data() {
    return {
      width: 0,
      height: 0,
      left: 0,
      top: 0,
      mode: 0,
      row: 0,
      col: 0,
      theadArr: [],
    };
  },
  computed: {
    styleValue() {
      return {
        width: `${this.width}px`,
        height: `${this.height}px`,
        left: `${this.left}px`,
        top: `${this.top}px`,
      };
    },
    selectValue() {
      return this.value;
    },
    selectState() {
      return this.value.some((ret) => ret.value);
    },
    selectClasses() {
      return (n) => (n.check ? "ui-selected" : "");
    },
  },
  created() {
    this.theadArr = createArr(24).slice(8, -1);
  },
  methods: {
    cellEnter(item) {
      const ele = document.querySelector(
        `td[data-week='${item.row}'][data-time='${item.col}']`
      );
      if (ele && !this.mode) {
        this.left = ele.offsetLeft;
        this.top = ele.offsetTop;
      } else if (item.col <= this.col && item.row <= this.row) {
        this.width = (this.col - item.col + 1) * ele.offsetWidth;
        this.height = (this.row - item.row + 1) * ele.offsetHeight;
        this.left = ele.offsetLeft;
        this.top = ele.offsetTop;
      } else if (item.col >= this.col && item.row >= this.row) {
        this.width = (item.col - this.col + 1) * ele.offsetWidth;
        this.height = (item.row - this.row + 1) * ele.offsetHeight;
        if (item.col > this.col && item.row === this.row)
          this.top = ele.offsetTop;
        if (item.col === this.col && item.row > this.row)
          this.left = ele.offsetLeft;
      } else if (item.col > this.col && item.row < this.row) {
        this.width = (item.col - this.col + 1) * ele.offsetWidth;
        this.height = (this.row - item.row + 1) * ele.offsetHeight;
        this.top = ele.offsetTop;
      } else if (item.col < this.col && item.row > this.row) {
        this.width = (this.col - item.col + 1) * ele.offsetWidth;
        this.height = (item.row - this.row + 1) * ele.offsetHeight;
        this.left = ele.offsetLeft;
      }
    },
    cellDown(item) {
      const ele = document.querySelector(
        `td[data-week='${item.row}'][data-time='${item.col}']`
      );
      this.check = Boolean(item.check);
      this.mode = 1;
      if (ele) {
        this.width = ele.offsetWidth;
        this.height = ele.offsetHeight;
      }

      this.row = item.row;
      this.col = item.col;
    },
    cellUp(item) {
      if (item.col <= this.col && item.row <= this.row) {
        this.selectWeek(
          [item.row, this.row],
          [item.col, this.col],
          !this.check
        );
      } else if (item.col >= this.col && item.row >= this.row) {
        this.selectWeek(
          [this.row, item.row],
          [this.col, item.col],
          !this.check
        );
      } else if (item.col > this.col && item.row < this.row) {
        this.selectWeek(
          [item.row, this.row],
          [this.col, item.col],
          !this.check
        );
      } else if (item.col < this.col && item.row > this.row) {
        this.selectWeek(
          [this.row, item.row],
          [item.col, this.col],
          !this.check
        );
      }

      this.width = 0;
      this.height = 0;
      this.mode = 0;
    },
    selectWeek(row, col, check) {
      const [minRow, maxRow] = row;
      const [minCol, maxCol] = col;
      this.data.forEach((item) => {
        item.child.forEach((t) => {
          if (
            t.row >= minRow &&
            t.row <= maxRow &&
            t.col >= minCol &&
            t.col <= maxCol
          ) {
            this.$set(t, "check", check);
          }
        });
      });
    },
  },
};
</script>
<style lang="scss" scoped>
.c-weektime {
  min-width: 490px;
  height: 30px;
  position: relative;
  display: inline-block;
}
.c-schedue {
  background: #598fe6;
  position: absolute;
  width: 0;
  height: 0;
  opacity: 0.6;
  pointer-events: none;
}
.c-schedue-notransi {
  transition: width 0.12s ease, height 0.12s ease, top 0.12s ease,
    left 0.12s ease;
}
.c-weektime-table {
  border-collapse: collapse;
  th {
    vertical-align: inherit;
    font-weight: bold;
  }
  tr {
    height: 30px;
  }
  tr,
  td,
  th {
    user-select: none;
    border: 1px solid #cccccc;
    text-align: center;
    min-width: 15px;
    line-height: 1.8em;
    transition: background 0.2s ease;
  }
  .c-weektime-head {
    font-size: 12px;
    .week-td {
      width: 70px;
    }
  }
  .c-weektime-body {
    font-size: 10px;
    tr:nth-child(2) {
      border: 0px;
      height: 10px;
      td {
        border: 0px;
      }
    }
    td {
      &.weektime-atom-item {
        user-select: unset;
        background-color: #fff;
      }
      &.ui-selected {
        background-color: #598fe6;
      }
    }
  }
}
.c-min-table {
  tr,
  td,
  th {
    min-width: 24px;
  }
}
.g-clearfix {
  &:after,
  &:before {
    clear: both;
    content: " ";
    display: table;
  }
}
.g-pull-left {
  float: left;
}
.g-pull-right {
  float: right;
}
.g-tip-text {
  color: #999;
}
</style>

weektime_data.js
 

const formatDate = (date, fmt) => {
    const o = {
      'M+': date.getMonth() + 1,
      'd+': date.getDate(),
      'h+': date.getHours(),
      'm+': date.getMinutes(),
      's+': date.getSeconds(),
      'q+': Math.floor((date.getMonth() + 3) / 3),
      S: date.getMilliseconds()
    }
    if (/(y+)/.test(fmt)) {
      fmt = fmt.replace(
        RegExp.$1,
        (date.getFullYear() + '').substr(4 - RegExp.$1.length)
      )
    }
    for (const k in o) {
      if (new RegExp('(' + k + ')').test(fmt)) {
        fmt = fmt.replace(
          RegExp.$1,
          RegExp.$1.length === 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length)
        )
      }
    }
    return fmt
  }
   
  const createArr = (len) => {
    return Array.from(Array(len)).map((ret, id) => id)
  }
   
  const formatWeektime = (col) => {
    const timestamp = 1018483200000 // '2018-11-17 00:00:00'
    const beginstamp = timestamp + col * 1800000 // col * 30 * 60 * 1000
    const endstamp = beginstamp + 1800000
   
    const begin = formatDate(new Date(beginstamp), 'hh:mm')
    const end = formatDate(new Date(endstamp), 'hh:mm')
    return `${begin}~${end}`
  }
   
  const data = [
    '时间'].map((ret, index) => {
    const children = (ret, row, max) => {
      return createArr(max).map((t, col) => {
        return {
        //   week: ret,
          value: formatWeektime(col),
          begin: formatWeektime(col).split('~')[0],
          end: formatWeektime(col).split('~')[1],
          row,
          col
        }
      })
    }
    return {
      value: ret,
      row: index,
      child: children(ret, index, 30)
    }
  })
  export default data

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值