vue2一天时间段选择库(drag-weektime)代码学习
Posted 胖鹅68
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue2一天时间段选择库(drag-weektime)代码学习相关的知识,希望对你有一定的参考价值。
文章目录
一、参考
二、问题描述
看着这个组件可以选择时间段范围,而且又选中表格的过程,好奇心想了解实现过程
三、原理说明
-
将一天24小时分为48个半个小时,一周七天,按照这个逻辑就知道每个单元格的坐标
-
每个时间单元格添加 mouseenter 、 mousedown 、 mouseup 事件
-
鼠标任意选中一个节点触发 mousedown事件,鼠标移动到最终节点 触发 mouseUp 时间,就知道起始单元格和最终单元格
-
利用 mouseenter 事件 就可以
计算出选中区域的 起始点的坐标 和 距离最终点的坐标的 width(宽度) 和 height(高度),画出用户选择的范围(实际上是一个绝对定位的范围,在表格的上面)
-
为了让选择范围的过程不那么突兀,
利用了 css3的过渡补间动画 transition 就可以让样式的变动产生柔和动画效果
这个动画时间不能太短:就没有选中过程了,只有起始点到终点的跳跃,用户感受不好
这个动画时间不能太长: 用户选择完全,动画还没有完成
四、代码过程解析
- 引用组件
<template>
<div class="about">
<drag-weektime
v-model="mult_timeRange"
:data="weektimeData"
@on-clear="clearWeektime">
</drag-weektime>
</div>
</template>
<script>
import moment from 'moment'
import weektimeData from '@/data/weektime_data'
import DragWeektime from '@/components/drag-weektime'
function splicing (list)
let same
let i = -1
let len = list.length
let 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()
return arr.join('')
export default
name: 'About',
components: DragWeektime , //, DatePicker
computed:
mult_timeRange ()
return this.weektimeData.map(item =>
return
id: item.row,
week: item.value,
value: splicing(item.child)
)
,
data ()
return
weektimeData: weektimeData
,
methods:
moment,
// 清空时间段
clearWeektime ()
this.weektimeData.forEach(item =>
item.child.forEach(t =>
this.$set(t, 'check', false)
)
)
</script>
- drag-weektime 组件内容
<template>
<div class="c-weektime">
<div class="c-schedue"></div>
<!-- mode 为1 表示正在选中, 'c-schedue-notransi' 样式就是选择淡蓝色 框的 -->
<div :class="'c-schedue': true, 'c-schedue-notransi': mode" :style="styleValue"></div>
<table class="c-weektime-table" :class="'c-min-table': colspan < 2">
<thead class="c-weektime-head">
<tr>
<th rowspan="8" class="week-td">星期/时间</th>
<th :colspan="12 * colspan">00:00 - 12:00</th>
<th :colspan="12 * colspan">12:00 - 24:00</th>
</tr>
<tr>
<td v-for="t in theadArr" :key="t" :colspan="colspan">t</td>
</tr>
</thead>
<tbody class="c-weektime-body">
<tr v-for="t in data" :key="t.row">
<td>t.value</td>
<td
v-for="n in t.child"
:key="`$n.row-$n.col`"
:data-week="n.row"
:data-time="n.col"
@mouseenter="cellEnter(n)"
@mousedown="cellDown(n)"
@mouseup="cellUp(n)"
:class="selectClasses(n)"
class="weektime-atom-item">
</td>
</tr>
<tr>
<td colspan="49" class="c-weektime-preview">
<div class="g-clearfix c-weektime-con">
<span class="g-pull-left">selectState ? '已选择时间段' : '可拖动鼠标选择时间段'</span>
<a class="g-pull-right" @click.prevent="$emit('on-clear')">清空选择</a>
</div>
<div v-if="selectState" class="c-weektime-time">
<div v-for="t in selectValue" :key="t.id">
<p v-if="t.value">
<span class="g-tip-text">t.week:</span>
<span>t.value</span>
</p>
</div>
</div>
</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
,
data:
type: Array
,
colspan:
type: Number,
default ()
return 2
,
computed:
// 用于计算 用户选择时间段的范围
styleValue ()
return
width: `$this.widthpx`,
height: `$this.heightpx`,
left: `$this.leftpx`,
top: `$this.toppx`
,
selectValue ()
return this.value
,
selectState ()
return this.value.some(ret => ret.value)
,
selectClasses ()
return n => n.check ? 'ui-selected' : ''
,
methods:
// 鼠标悬浮的最后位置
cellEnter (item)
console.log('cellEnter')
// 找到鼠标最终悬停位置的 表格
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 // 根据起始点 和 最终点, 计算出 选中框的 left、top 属性 和 width 和 height 高度
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)
console.log('cellDown')
debugger
// item =
// 'week': '星期一',
// 'value': '01:00~01:30',
// 'begin': '01:00',
// 'end': '01:30',
// 'row': 0, // 代表星期几, 0 代表星期一 6 代表星期 天
// 'col': 2 // 代表哪个时段 (半个小时为一个时段,一天有48个时段)
//
// 获取用户选中的点
const ele = document.querySelector(`td[data-week='$item.row'][data-time='$item.col']`)
// 判断用户选中的格子是否被选中
this.check = Boolean(item.check) // 用于样式的渲染
this.mode = 1 // mode 为1 表示正在选中 的样式
if (ele) // with 和 height 是用户手动选择的范围
this.width = ele.offsetWidth
this.height = ele.offsetHeight
// 起始行
this.row = item.row
// 起始列
this.col = item.col
,
cellUp (item)
console.log('cellUp')
// 最终的节点,在起始点的 —— 左上角
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 // 选中的宽度为 0
this.height = 0 // 选中的高度为 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)
)
)
,
data ()
return
width: 0,
height:以上是关于vue2一天时间段选择库(drag-weektime)代码学习的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Vue2 中的 Sass 后缀 (&__) 选择器上实现 ::v-deep?
vue2+echarts:后台传递一天有多类数据的时候,如何渲染柱状图