vue.draggable拖拽生成课程表
根据数据源提供的科目及教师信息,拖拽至空白课表内,生成一份课表。首先科目有多个,教师也有多个。数据源部分做一个切换选择科目的效果,选取科目后,提供科目及授课人名字。课表可以是一张空白课表,也可以默认指定某日某节某人某课。课表使用表格呈现,这样区域方便划分。表头是工作日,表体部分的第一列是节次。为了更方便查看,最左边设计上中下午段的划分。拖拽效果有比较成熟的组件库了:Vue-Draggable。它是
需求
根据数据源提供的科目及教师信息,拖拽至空白课表内,生成一份课表。
需求分析
数据源
首先科目有多个,教师也有多个。数据源部分做一个切换选择科目的效果,选取科目后,提供科目及授课人名字。
课表
课表可以是一张空白课表,也可以默认指定某日某节某人某课。
课表使用表格呈现,这样区域方便划分。
表头是工作日,表体部分的第一列是节次。为了更方便查看,最左边设计上中下午段的划分。
设计稿
实现
Vue-Draggable
拖拽效果有比较成熟的组件库了:Vue-Draggable。
它是基于Sortable.js实现的,适用vue项目,可以在pc端使用也可以在移动端使用
官网地址:GitHub - SortableJS/Vue.Draggable: Vue drag-and-drop component based on Sortable.js
线上演示地址:https://sortablejs.github.io/Vue.Draggable/
特性
- 支持可触摸设备
- 支持拖动选取和文本选取
- 智能滚动
- 支持在不同列表间拖拽
- 没有jQuery依赖项
- 拖拽可撤销
- 拖拽有过渡动画
使用
引入
首先进入你的vue项目,引入组件库
npm i vuedraggable -S
这第一步就报错的估计就只有我了,node-module包删删引引好多次,就是不行。
报错就是让我去看一个debug文件:nodejs\node_cache_logs\2022-06-29T04_30_02_307Z-debug-0.log
实不相瞒,真看不懂。
求助度娘,说是需要清除npm的缓存,这里也有两个槽点。唉,接着看吧:
npm cache clean --force
上面指令执行后没一点用,还是出错,又启用了下面这个指令:
npm cache verify
你们自己看着用吧(如果和我一样第一步就出错的😅)
组件注册
如果你项目使用这个拖拽功能比较多,就全局注册。
单个页面使用的话就局部注册好了:
① import draggable from ‘vuedraggable’
② export default {
components: {
draggable,
},
可要注意了,组件注册需要两步,这里就不要踩坑啦!!
基础使用
<draggable v-model="myArray" @start="onStart" @end="onEnd">
<div class="item" v-for="element in myArray" :key="element.id">{{element.name}}</div>
</draggable>
myArray: [{ people: 'cn', id: 1, name: 'www.itxst.com' },
{ people: 'cn', id: 2, name: 'www.baidu.com' },
{ people: 'cn', id: 3, name: 'www.taobao.com' },
{ people: 'us', id: 4, name: 'www.google.com' }
]
进阶使用—带过渡效果
<draggable v-model="myArray" @start="onStart" @end="onEnd">
<transition-group>
<div class="item" v-for="item in myArray" :key="item.id">{{item.name}}</div>
</transition-group>
</draggable>
配置项
1. list
作为value属性的替代方法,list 是通过拖放进行同步的数组。
主要区别在于list属性由可拖动组件使用拼接方法更新,而value属性是不可变的。
❗需要注意的是:不要与value一起使用。
2. tag
配置该属性后,draggable标签将会作为指定标签渲染。
也就是说,tag是用来设置节点类型的。
默认值是:div,接收字符串类型的数据。
3.group
这个是实现不同组之间相互拖拽的关键属性。
有两种使用方式:
①字符串类型
直接给两组配置相同的组名,eg:group:‘course’
②对象类型
name:设置组名
pull:true/false是否允许拖出当前组
put:true/false是否允许拖入当前组
group:{
name:'course',//组名为itxst
pull: true|false| 'clone'|array|function,//是否允许拖出当前组
put:true|false|array|function,//是否允许拖入当前组
}
常用的也就这些,其他配置项没有深入了解就不在这里介绍了,有需要请移步官网哦~
不过需要提醒的是:
✨如果需要配置clone,disable,sort等属性时,切记放在options里面才能生效。
:options=“{group:{name: ‘itxst’,pull:‘clone’},sort: true}”
事件
choose:被选中时触发
unchoose:未选择时触发
start:开始拖拽时触发
end:拖拽结束时触发
add:元素从一个组内拖拽到另一个组内触发
Update:在组内拖拽更改了顺序触发
sort:对列表的任何更改调用(添加/更新/删除)
remove:元素从一个列表中删除到另一个列表
move:在列表中或在列表之间移动项目的事件
clone:创建元素克隆时被调用
change:拖动元素更改位置时被调用
事件介绍就是上面的了,怎么用也不需要举栗啦。
就简单介绍一下事件里面事件对象e的内容吧!
evt.to; // target list
evt.from; // previous list
evt.oldIndex; // element's old index within old parent
evt.newIndex; // element's new index within new parent
evt.oldDraggableIndex; // element's old index within old parent, only counting draggable elements
evt.newDraggableIndex; // element's new index within new parent, only counting draggable elements
evt.clone // the clone element
evt.pullMode; // when item is in another sortable: `"clone"` if cloning, `true` if moving
关于被拖动的元素在拖动过程中呈现半透明样式的修改
对于:拖拽的阴影为啥是透明渐变的问题(官方的默认样式)
自定义的话——>
我们的解决方案是:
首先添加forceFallback属性,设置为true。
然后使用dragClass属性添加被拖拽过程中呈现的样式类名。
最后拖拽过程中的元素就会呈现dragClass设置的样式名所写的样式啦.
感谢吉吉安伙伴的友情分享:
代码部分
大篇幅可能懒得看,我简短说一下实现思路:
1、左边拖拽到右边课程表的时候使用end事件,事件里面的事件对象e可以拿到e.to也就是目标位置的所有信息。
2、右边的课程表绑定自定义属性用来传递节次信息,key绑定周次信息。
3、在e.to对象里面,自己细心找一下周次、节次怎么获取。
4、直接展示拖拽后的内容,用innerHTML把拖拽的元素直接塞里面。
5、最后肯定是要生成课表的,我们借助二维数组来存放课程信息。第一层为周次,第二层为节次,根据元素内容把数据组合好,最后页面效果有了,课程表的数据也有了。。
html
<a-card :style="`min-height: ${minHeight}px;`" class="mt50">
<a-row type="flex" justify="space-between">
<a-col :md="4" :sm="6" :xs="6" :span="4">
<a-tabs default-active-key="activetab" tab-position="left" @change="tabChange">
<a-tab-pane v-for="(item, index) in list" :key="index" :tab="item[0].name">
<draggable class="dragArea list-group" :list="listDate" :group="{ name: 'people', pull: 'clone', put: false, animation: '300' }" @end="onEnd">
<transition-group>
<div class="a-row" v-for="element in listDate" :key="element.id">
<p>{{ element.name }}</p>
<p>{{ element.teacher }}</p>
</div>
</transition-group>
</draggable>
</a-tab-pane>
</a-tabs></a-col
>
<a-col :md="2" :sm="4" :xs="4" :span="2"></a-col>
<a-col :md="16" :sm="24" :xs="24" :span="16">
<div class="course">
<table>
<thead>
<tr>
<th colspan="2"></th>
<th v-for="(val, weekindex) in weeks" :key="weekindex">{{ val }}</th>
</tr>
</thead>
<tbody>
<tr v-for="index of 11" :key="index">
<td class="week-td" rowspan="4" v-if="index == 1">上午</td>
<td class="week-td" rowspan="4" v-if="index == 5">下午</td>
<td class="week-td" rowspan="3" v-if="index == 9">晚上</td>
<td class="week-td">{{ index }}</td>
<draggable group="people" v-for="(val, weekindex) in weeks" :key="weekindex" :dataindex="index" :week="val" tag="td"> </draggable>
</tr>
</tbody>
</table>
</div>
</a-col>
</a-row>
</a-card>
我vue项目用的是ant design vue组件库,各位看官请挑选自己需要的部分食用吧!
js
import draggable from 'vuedraggable';
export default {
name: 'custom-clone',
display: 'Custom Clone',
order: 3,
components: {
draggable,
},
data() {
return {
minHeight: window.innerHeight - 224,
list: [
[
{ name: '语文', id: 1, teacher: '张老师1' },
{ name: '语文', id: 2, teacher: '张老师2' },
{ name: '语文', id: 3, teacher: '张老师3' },
{ name: '语文', id: 4, teacher: '张老师4' },
],
[
{ name: '数学', id: 1, teacher: '王老师1' },
{ name: '数学', id: 2, teacher: '王老师2' },
{ name: '数学', id: 3, teacher: '王老师3' },
{ name: '数学', id: 4, teacher: '王老师4' },
],
[
{ name: '英语', id: 1, teacher: '李老师1' },
{ name: '英语', id: 2, teacher: '李老师2' },
{ name: '英语', id: 3, teacher: '李老师3' },
{ name: '英语', id: 4, teacher: '李老师4' },
],
],
listDate: [],
activetab: 0,
weeks: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
tableDate: [[], [], [], [], [], [], []],
weekIndex: '',
courseIndex: '',
};
},
mounted() {
this.listDate = this.list[this.activetab];
},
methods: {
onEnd(e) {
this.weekIndex = e.to.cellIndex;
this.courseIndex = e.to.__vue__.$vnode.data.attrs.dataindex;
e.to.innerHTML = e.clone.outerHTML;
let arr = {
courseindex: this.courseIndex,
weekindex: this.weekindex,
course: e.clone.childNodes[0].innerText,
teacher: e.clone.childNodes[1].innerText,
};
this.$set(this.tableDate[this.weekIndex - 1], this.courseIndex - 1, arr);
},
tabChange(key) {
this.activetab = key;
this.listDate = this.list[key];
},
},
};
css
<style lang="less">
.course {
height: 700px;
overflow-y: auto;
overflow-x: hidden;
table {
border: 1px solid #ebebeb;
margin: 20px auto;
text-align: center;
border-collapse: collapse;
}
.week-td {
background-color: #f7f7f7;
}
table th {
border: 1px solid #ebebeb;
background-color: #f7f7f7;
padding: 10px;
width: 100px;
height: 40px;
font-size: 14px;
}
table td {
border: 1px solid #ebebeb;
padding: 4px 10px;
height: 40px;
color: #000000;
font-size: 14px;
}
}
</style>
效果展示
这里是飞鱼爱吃米,只授渔,不授鱼!
更多推荐
所有评论(0)