今天有时间就录制一个我最近在座的一个需求吧,我最近在做学校的项目,拖拽盒子调课,例如把第三周的星期二第4节课拖动到第三周星期四的第六节课,因为我们的课表是采用的表格进行展示的,用到的表格是ag-grid-vue组件,下面就看我如何做的吧
export const COURSE_SCHEDULING_COLUMNS = [
{
headerName: '',
field: 'name',
minWidth: 100,
maxWidth: 100,
tooltipField: 'name',
wrapText: true,
menuTabs: false,
cellStyle: {lineHeight: 1, paddingTop: '15px'}
},
{
headerName: '一',
field: 'Monday',
minWidth: 200,
width: 200,
autoHeight: true,
cellRenderer: 'CourseDetail',
menuTabs: false,
cellStyle: {padding: 0}
},
{
headerName: '二',
field: 'Tuesday',
minWidth: 200,
autoHeight: true,
width: 200,
cellRenderer: 'CourseDetail',
menuTabs: false,
cellStyle: {padding: 0}
},
{
headerName: '三',
field: 'Wednesday',
minWidth: 200,
autoHeight: true,
width: 200,
cellRenderer: 'CourseDetail',
menuTabs: false,
cellStyle: {padding: 0}
},
{
headerName: '四',
field: 'Thursday',
minWidth: 200,
autoHeight: true,
width: 200,
cellRenderer: 'CourseDetail',
menuTabs: false,
cellStyle: {padding: 0}
},
{
headerName: '五',
field: 'Friday',
minWidth: 200,
autoHeight: true,
width: 200,
cellRenderer: 'CourseDetail',
menuTabs: false,
cellStyle: {padding: 0}
},
{
headerName: '六',
field: 'Saturday',
minWidth: 200,
autoHeight: true,
width: 200,
cellRenderer: 'CourseDetail',
menuTabs: false,
cellStyle: {padding: 0}
},
{
headerName: '日',
minWidth: 200,
autoHeight: true,
width: 200,
field: 'Sunday',
cellRenderer: 'CourseDetail',
menuTabs: false,
cellStyle: {padding: 0}
}
];
上面是我列配置,这里面用到的是有一个很重要的字段cellRenderer: 'CourseDetail'他是自定义组件配置字段,
接下来就要实现拖拽啦
`
<div
v-for='(item,index) in params.value'
:key='index'
:draggable='true'
class='course-item'
@click='routerCourseDetails(item)'
@dragstart='onDragStart($event,item)'
></div>
这是自定义单元格组件根标签,我在他身上设置:draggable='true'和@dragstart='onDragStart($event,item)'第一个属性是为了能够开启拖拽,第二个属性是为了拖拽的时候参数传递
onMounted(() => {
// 只有课表明细才能进行拖拽
if (isScheduleDetails.value) {
nextTick(() => {
props.params.eGridCell.addEventListener('dragover', onDragOver);
props.params.eGridCell.addEventListener('drop', onDrop);
props.params.eGridCell.addEventListener('dragenter', onDragenter);
props.params.eGridCell.addEventListener('dragleave', onDragleave);
props.params.eGridCell.addEventListener('dragend', onDragEnd);
});
}
});
这里我在自定义单元格组件的onMounted事件之中挂载5个拖拽事件,是为了能够更好地带来用户体验
// 拖动开始
const onDragStart = (event, params) => {
const { currentTime } = props.params.context;
// 全部都小于当前周那就直接禁止拖动
const isWeek = params.weeks.every(item => item < currentTime.week);
if (isWeek) {
event.preventDefault();
ElMessage.warning('本门课程在当前周已经完结');
return;
}
// 如果是单周的情况,就判断当前周和选择的周相同,如果相同就判断星期
if (params.weeks.length === 1 && params.weeks.includes(currentTime.weeks)) {
if (params.dayRange < currentTime.dayRange) {
event.preventDefault();
ElMessage.warning('本门课程在当前周已经完结');
return;
// 如果当前选择的星期和当前星期相等
} else if (params.dayRange === currentTime.dayRange) {
// 判断课节是否相等,当前选择的课节小于当前课节也应该提示
if (params.numRange <= currentTime.numRange) {
event.preventDefault();
ElMessage.warning('本门课程在当前周已经完结');
return;
}
}
}
// 储存自定义属性
compId.value = props.params.eGridCell.getAttribute('comp-id');
// 删除本身的onDragOver事件,是为了不让本身能够触发弹框事件
props.params.eGridCell.removeEventListener('dragover', onDragOver);
// 数据传递
event.dataTransfer.setData(
'text/plain',
JSON.stringify(params)
);
};
// 阻止默认行为,
const onDragOver = (event) => {
const types = event.dataTransfer.types;
const dragSupported = types.length;
if (dragSupported) {
event.dataTransfer.dropEffect = 'move';
}
event.preventDefault();
};
// 拖拽结束后
const onDrop = (event) => {
event.preventDefault();
// 将被拖动元素移动到选定的目标元素中
const target = event.target.closest('.ag-cell-auto-height');
if (target) {
// 检查鼠标离开的元素是否是拖拽目标元素的子元素
if (!target.contains(event.relatedTarget)) {
// 删除背景样式
target.classList.remove('dragover');
// 获取数据
const textData = event.dataTransfer.getData('text/plain');
// 转化为对象
const data = JSON.parse(textData);
const { rowIndex, column } = props.params;
props.params.context.openReparationDialog({
...data,
newDayRange: WEEK_ENGLISH_KEY.findIndex(item => item === column.colId) + 1,
newNumRange: rowIndex + 1
});
}
}
};
// 进入拖拽的盒子之中
const onDragenter = (event) => {
// 在可拖动元素进入潜在的放置目标时高亮显示该目标
const target = event.target.closest('.ag-cell-auto-height');
// 符合目标元素,并且不是本身的父盒子就高亮父元素
if (target && target.getAttribute('comp-id') !== compId.value) {
target.classList.add('dragover');
}
};
// 离开拖拽的盒子之中
const onDragleave = (event) => {
// 在可拖动元素离开潜在放置目标元素时重置该目标的背景
const target = event.target.closest('.ag-cell-auto-height');
if (target) {
// 检查鼠标离开的元素是否是拖拽目标元素的子元素
if (!target.contains(event.relatedTarget)) {
target.classList.remove('dragover');
}
}
};
// 拖拽结束触发
const onDragEnd = () => {
const elementWithCustomAttribute = document.querySelector(`[comp-id='${compId.value}']`);
compId.value = '';
elementWithCustomAttribute.addEventListener('dragover', onDragOver);
};
这里就可以大体实现了功能啦,拖拽开始的这个onDragStart事件谁可以帮我代码再精简一下啊,真的不知道怎么优化了,感觉还是很臃肿