# 实现拖拽
拖拽是该项目实现的关键,在这里我们使用的拖拽库是 vue3-dnd。
# vue3-dnd
vue3-dnd
是基于 react-dnd
开发的 ,它们两个语法 API 几乎一致,用过 react-dnd
的同学使用 vue3-dnd
几乎是无缝衔接。
后面的内容不会介绍 vue3-dnd
具体 API
的使用,只会介绍 vue3-dnd
在项目中的应用;
对 vue-dnd
或者 react-dnd
不熟悉的同学建议先查阅此文档 示例 (opens new window),否则后面的内容会有点晦涩难懂;
具体的业务实现代码,就不在这写了,没有多大意义,下面只分享一下实现思路;
# useDrag
useDrag
函数提供了一种将你的组件作为拖拽源连接到 DnD 的方法。
# Forward、Event、Backward 拖动源
下面是一个 event
事项在页面中的 DOM
结构,可以看到,class
为 forward
、content
、backward
的 section
都具有拖拽属性 draggable
;
forward
:将事项向左拖拽进行跨天,比如将 12号 单天的事项变为 11号 至 12号 两天的连贯事项
content
:事项本身的拖拽(组件名称为 Event)
backward
:将事项向右拖拽进行跨天,比如将 12号 单天的事项变为 12号 至 13号 两天的连贯事项
# 拖动的事件处理
这三个拖动源在拖动结束时去更改一个当前事项的 startTime 和 endTime。
# New 拖动源
当前日期中无事项时,可以通过拖拽空白处,创建新的事项。
# Day 拖动源
Day 组件很特殊,因为它本身即是拖动源又是放置目标。
当其作为拖动源时,功能和 New 拖动源功能一致。
# useDrap
useDrop
函数提供了一种将你的组件作为放置目标连接到 DnD 的方法。
# Day 放置源
Day 放置源会接受来自其他拖动源的信息。
Day 放置源暴露了两个属性,其可以使拖拽源在拖拽结束(end方法)时被获取。
fullTime:放置源的日期。
dateIndex:放置源在当前日期面板中的索引。
drop: () => ({
// drag 侧可以通过 monitor.getDropResult() 拿到该值
dropTime: props.dateInfo.fullTime,
dateIndex: props.dateInfo.dateIndex,
}),
2
3
4
5
# 放置过程中的事件处理
当有拖拽组件经过时,该组件就会触发 hover 事件,并改变样式。
# 事件的渲染
# 获取当月的所有事项
单个事件的携带信息:
字段 | 描述 |
---|---|
startTime | 事项的开始时间 |
endTime | 事项的结束时间 |
isDone | 事项是否已完成 |
priority | 事项的重要程度 |
title | 事项标题 |
description | 事项的描述信息 |
# 将事项派发到每一天
获取到当月所有的事项后,通过 getRenderEventList 函数与当月的日历进行处理后返回一个 renderList 列表。
watchEffect(async () => {
const { renderList } = getRenderEventList(
calendarInfo.value,
eventList.value
);
renderEventList.value = renderList;
});
2
3
4
5
6
7
经过处理后返回的是一个长度为 42 的二维数组,一个数组代表一天的数据,而在这个数组内又有内层数组,内层数组中存放着每一个具体的事项。
# 事项分类
经过处理后的 renderList 中,事项可以分为两大类,当天事项和跨天事项。
# 单天事项
如果 startTime
和 endTime
是同一天,那么代表该事项只在当天展示;
# 跨天事项
如果 startTime
和 endTime
不一样,那么代表该事项是跨天事项。
# hasLast 和 hasNext 标识的作用
hasLast
和 hasNext
的 标识符控制着 Forward
组件和 Backward
组件是否展示,我们在上文提到过,Forward
组件 和 Backward
组件都是拖动源,它的存在与否其实就代表着这个事项是否可以进行跨天拖拽。
我们以 12号这天的事项举例
如果 hasLast
为 false
,那么渲染 Forward
组件,事项可以向左进行跨天拖拽
如果 hasNext
为 true
,那么不渲染 Backward
组件,同时,事项还需要将右侧的留白位置进行样式填充
# 事项的渲染位置
在经过数据处理后,有一个字段 _index
,这个字段帮助我们定位渲染的初始位置。
我们以 11号 标题为 “举个例子” 这个事项为例,在 11号这天,它的渲染位置是第 2 个,那么如何保证后面的 12 号 至 15号,它的渲染位置一直是第 2 个呢?通过 _index
字段确认。
接收的参数:
dateIndex
:日历每天的日期索引,0 开始,41结束,总共 42 天
lastEventList
:日历中每天的 hasNext
属性为 true 的事项
eventAllList
:当天的需要展示的所有事项
实现思路:
1.根据 dateIndex
获取前一天的所有 hasNext
属性的事项,并赋值给变量 lastEvents
。
2.声明 showEventList
,存放当天最终需要渲染的事项。
3.将 lastEvents
和 当天的所有的事项根据 eventId
进行对比:
a.如果 eventId
相等,那么代表该事项是跨天事项(因为前一天和当天的事项列表中都存在该事项)。
b.将前一天的 _index
赋值给当天的 _index
,由此便确认了位置信息。
c.通过 showEventList[_index]
进行保存。
4.处理当天和以当天为开始日期的跨天事项,并赋值 _index
。
5.在后续的展示过程中,就可以通过 _index
进行排序,由此确认事项的渲染位置