目录
一、效果展示
二、代码分析
2.1、两栏布局、表格编写与课程卡片
2.2、初始化数据与渲染
2.3、拖拽卡片到表格,进行插入
2.4、自定义指令进行删除
一、效果展示
二、代码分析
主页面代码:
<template>
<div class="board">
<div class="left">
<CoursePerson
v-for="({ name }, k) in datas.courses"
:key="k"
:courseName="name"
:courseKey="k"
@handleDragEnd="handleDragEnd"
></CoursePerson>
</div>
<div class="right" @dragover="handleDragOver" @dragenter="handleDragEnter">
<table border="1">
<tr>
<th>时间段 / 星期</th>
<th v-for="(w, i) in datas.weekday" :key="i">{{ w }}</th>
</tr>
<tr v-for="(t, i) in datas.time_slot" :key="i">
<th>{{ t }}</th>
<td v-for="n in 7" :key="n" :data-weekday="n" :data-time-slot="i">
<template v-if="cellData[`${n}-${i}`]">
<CoursePerson
:courseName="datas.courses[cellData[`${n}-${i}`]].name"
:courseKey="cellData[`${n}-${i}`]"
v-CoursePanel="{ cellData, n, timeSlot: i }"
></CoursePerson>
</template>
</td>
</tr>
</table>
</div>
</div>
</template>
<script>
import CoursePerson from "@/components/CoursePerson.vue";
export default {
components: {
CoursePerson,
},
directives: {
// 定义名为CoursePanel的指令,指向一个配置对象
CoursePanel: {
bind(el, bindings) {
const oRemoveBtn = el.querySelector(".remove-btn");
const { cellData, n, timeSlot } = bindings.value;
oRemoveBtn.addEventListener("click", handleRemovePanel, false);
function handleRemovePanel() {
delete cellData[`${n}-${timeSlot}`];
}
},
},
},
data() {
return {
datas: {
weekday: [
"星期一",
"星期二",
"星期三",
"星期四",
"星期五",
"星期六",
"星期日",
],
time_slot: [
"08:00-08:50",
"09:00-09:50",
"10:00-10:50",
"11:00-11:50",
"14:00-14:50",
"15:00-15:50",
"16:00-16:50",
"17:00-17:50",
],
courses: {
chinese: {
name: "语文",
teachers: ["张三", "李四"],
},
math: {
name: "数学",
teachers: ["张二", "李五"],
},
english: {
name: "英语",
teachers: ["张3", "李2"],
},
},
},
cellData: {
"1-1": "chinese",
"2-5": "math",
"3-3": "english",
},
targetCell: null,
};
},
methods: {
handleDragOver(e) {
e.preventDefault();
},
handleDragEnter(e) {
e.preventDefault();
const tar = e.target;
const tagName = tar.tagName.toLowerCase();
this.targetCell = tagName != "td" ? null : tar;
},
handleDragEnd(e) {
if (this.targetCell) {
const weekday = this.targetCell.dataset.weekday;
const timeSlot = this.targetCell.dataset.timeSlot;
const prop = `${weekday}-${timeSlot}`;
if (!this.cellData[prop]) {
//给表格中没有坐标的课程
const key = e.dataset.key;
this.$set(this.cellData, prop, key); //借助$set赋值,更新视图
// this.cellData[prop] = key; //赋值(vue2赋值视图不更新)
}
}
},
},
};
</script>
<style lang='less' scoped>
.board {
position: relative;
.left {
position: absolute;
top: 0;
left: 0;
width: 300px;
height: 100%;
}
.right {
width: 100%;
height: 800px;
padding-left: 300px;
box-sizing: border-box;
table {
width: 100%;
border-collapse: collapse;
table-layout: fixed;
td {
height: 60px;
text-align: center;
}
}
}
}
</style>
卡片组件代码:
<template>
<!-- draggable="true" 该盒子可被拖动 -->
<div
class="course-panel"
draggable="true"
@dragstart="handleDragStart"
@dragend="handleDragEnd"
:data-key="courseKey"
>
<h1>{{ courseName }}</h1>
<span class="remove-btn">x</span>
</div>
</template>
<script>
export default {
props: ["courseName", "courseKey"],
methods: {
handleDragStart(e) {
const tar = e.target;
tar.style.opacity = ".6";
},
handleDragEnd(e) {
const tar = e.target;
tar.style.opacity = "1";
this.$emit("handleDragEnd", tar);
},
},
};
</script>
<style lang='less' scoped>
.course-panel {
position: relative;
width: 100px;
height: 60px;
background-color: goldenrod;
margin: 10px auto;
padding: 10px;
box-sizing: border-box;
cursor: move;
h1 {
font-size: 20px;
text-align: center;
}
.remove-btn {
position: absolute;
top: 0px;
right: 10px;
}
}
</style>
2.1、表格编写与课程卡片
静态页面主要采用两栏布局。左侧为卡片组件,右侧为表格。
2.2、初始化数据与渲染
td是单元格,现在里面是一个7X7的表格,想要将指定课程的卡片渲染上去,我们可以借助cellData变量里的值,类似二维数组,我们找到坐标,就可以渲染上去。
2.3、拖拽卡片到表格,进行插入
拖拽效果:draggable="true" 意味着该盒子可被拖动,包括很多事件,比如:dragstart、dragend、dragover、dragenter等。
插入实现:看似是将左侧的卡片拖进去,实则是在进入表格时(拖拽结束)进行了数据的改动,就是给cellData这个对象里继续增加一个属性和属性值,达到插入效果。vue2里直接复制,视图不会变化,可以通过$set进行视图更新,this.$set(this.cellData, prop, key);
2.4、自定义指令进行删除
本例中通过视图中 v-CoursePanel="{ cellData, n, timeSlot: i }",结合directives里的CoursePanel指令进行表格内卡片的删除。这里的删除指删除表格内的任意卡片,而不能删除左侧的原始卡片。所以组件结合自定义指令去进行删除操作。
现在它删除有个bug,点击x删除,需要再次拖拽(添加)时,才会看到删除的卡片效果,尚待完善。。。