Draggable拖拽

由于目前所在的公司做的是学校管理的项目,功能中就包含课程表定制,学生排序,邮箱回执插入等,都需要用到拖拽的功能,以下就介绍下项目中用的draggable实现的拖拽排序

实现效果图

功能描述:搜索框输入首字母或者姓名可快速定位到该学生,根据键盘上键和下键可进行学生的选择,enter键或者鼠标点击即选中学生(选中后定位到该学生,该学生变色,方便查找),点击学生即可进行拖拽排序

以下为一个弹窗


下拉框列表选择学生


选中学生定位到该学生并变色


拖拽效果


1.安装

npm install vuedraggable复制代码

2.引入

import draggable from 'vuedraggable'复制代码


3.根据vuetify的v-menu来做一个点击输入框,下拉显示列表的功能

具体函数功能会在下面附上完整代码,太多了就不截图了~~~


根据输入框的内容对下拉列表的内容进行筛选,后台返回的数据如下


4.拖拽的基本用法

布局


参数配置


以上就是大体的结构,下面附上所有代码,注释的很详细了哦

5.所有代码

<template>    
    <div class="draggable-roster">        
        <my-dialog ref="draggable_roster_dialog" :width="studentInfo.length > 63 ? 1012 : 1005"  @handle="changeMuster">            
            <div class="draggable-title" slot="title">自定义排序</div>            
            <div class="draggable-content" slot="content">                
                <!-- 下拉框搜索内容 -->                
                <v-menu offset-y v-model="show" fixed max-height="240" class="search-student">                    
                    <header slot="activator" class="select-header">                                               
                        <input ref="input" type="text" v-model.trim="inputValue" placeholder="请输入学生姓名或者首字母" @keydown.delete="deleteInputVal" @keydown="onKeyDown" @keyup.enter="onKeyEnter">                    
                    </header>                    
                    <main class="select-wrap">                        
                        <ul v-if="filterList && filterList.length > 0"  ref="content">                            
                            <li v-for="(item, i) in filterList" :key="i" @click="selectListOne(item)" @keydown.delete="deleteInputVal" :class="{'key-down-select': i === listIndex}">                                
                                <span>{{item.name}}</span>                            
                            </li>                        
                        </ul>                        
                        <div v-else class="empty-data">没有符合条件的结果</div>                    
                    </main>                
                </v-menu>                
                <ul class="studentContainer clear">                    
                    <!-- 拖拽内容 -->                    
                    <draggable :options="studentTable" v-model="studentInfo">                        
                        <li v-for="(student,stIndex) in studentInfo" :key="stIndex" :class="{selected: student.id === inputValueId}">                            
                            <i></i>                            
                            <div>                                
                                <span>{{student.name}}</span>                                
                                <var>{{student.id}}</var>                            
                            </div>                        
                        </li>                    
                    </draggable>                
                </ul>            
            </div>        
        </my-dialog>    
    </div>
</template>
<script>
    import myDialog from '@/components/myDialog'
    import draggable from 'vuedraggable'
    import {mapState} from 'vuex'
    export default {    
        name: 'draggableRoster',    
        props: {        
            // 学生列表        
            studentList: {            
                type: Array,            
                default: ()=>{                
                    return []            
                }        
            }    
        },    
        components: {        
            draggable,        
            myDialog    
        },    
        data(){        
            return {            
                kSchoolId: this.$common.getSession("userData").school.id,            
                kSchoolYearId: this.$common.getSession("userData").schoolYear.id,            
                studentInfo: [], //学生信息            
                studentTable: {                
                    group: {name: 'draggableRoster'},                
                    sort: true,                
                    animation: 150,                
                    // ghostClass: 'rosterDraggableGhost',  // 拖动影子元素class                
                    chosenClass: 'rosterDraggableChosen', // 选中的元素class                
                    dragClass: 'rosterDrag', //拖动过程class            
                },//拖拽参数设置            
                show: false, //一开始隐藏搜索框列表            
                inputValue: '', //搜索框内容            
                inputValueId: '', //选中的学生id            
                courseInfomation: {}, //班级信息            
                listIndex: 0, // 当前keydown的项        
            }    
        },    
        computed: {        
            // 下拉列表内的数据 (根据输入框的内容进行筛选)       
            filterList() {            
                if (this.inputValue === '') return this.studentInfo            
                let filterList = [];            
                filterList = this.studentInfo.filter(val => {                
                    let {name, firstName} = val;                
                    if (name.includes(this.inputValue) || firstName.includes(this.inputValue)) {                    
                        return true                
                    }            
                })            
            return filterList        
        },        
        ...mapState('semester',['newSemester']) 
    },    
    methods: {  
        //打开vuetify的v-dialog弹窗      
        open(courseInfo) {            
            this.studentInfo = this.studentList; //学生信息赋值            
            this.courseInfomation = courseInfo; //班级信息赋值            
            this.$refs.draggable_roster_dialog.open(); //打开vuetify的v-dialog弹窗       
        },        
        // 选择下拉列表的一个名字        
        selectListOne(item) {            
            this.inputValue = item.name;            
            this.inputValueId = item.id;            
            this.show = false;        
        },        
        // 删除输入框中的内容        
        deleteInputVal() {            
            this.inputValueId = '';            
            this.show = true;        
        },        
        // 列表向下向上键        
        onKeyDown (e) {            
            const keyCodes = Object.freeze({                
                enter: 13,                
                up: 38,                
                down: 40,            
            })            
            if (e.keyCode === keyCodes.down && this.listIndex < this.filterList.length - 1) {                
                this.listIndex++            
            } else if (e.keyCode === keyCodes.up && this.listIndex > 0) {                
                this.listIndex--            
            }        
        },        
        // enter键选中        
        onKeyEnter(){            
            let item = this.filterList[this.listIndex]            
            if (!item) {                
                // 没有选择项,点击enter提示                
                this.$message.warning('请选择学生');                
                return            
            } else {                
                // 有选择项,点击enter则选择此项                
                this.selectListOne(item);                
                return            
            }        
        },        
        // 更改排序        
        changeMuster() {            
            let studentArr = [];            
            this.studentInfo.forEach(item=>{                
                studentArr.push(item.id)            
            })            
            let params = {                
                kSchoolId: this.kSchoolId,                
                kSchoolYearId: this.kSchoolYearId,                
                kSemesterId: this.newSemester.id,                
                kGradeId: this.courseInfomation.kGradeId,                
                classType: this.courseInfomation.classType,                
                studentIdList: studentArr            
            }            
            if(this.courseInfomation.classType === 0) {                
                params.kClassesGroupId = this.courseInfomation.kClassesGroupId;            
            }else{                
                params.kCourseId = this.courseInfomation.kCourseId;                
                if(this.courseInfomation.classType === 1 || this.courseInfomation.classType === 6) {                    
                    params.kClassesGroupId = this.courseInfomation.kClassesGroupId;                
                }else{                    
                    params.kClassId = this.courseInfomation.kClassId;                
                }            
            }            
            this.$ajax.post(this.$api.SAVE_MUSTER, params).then(res => {                
                if (res.code == 200) {                    
                    this.$refs.draggable_roster_dialog.close(); //关闭弹窗                    
                    this.$message.success('自定义排序成功!');                    
                    this.$emit('refreshRoster'); //给父级发送请求,告知父级重新渲染列表               
            }            
        });        
    }    
},    
watch: {        
    // 输入搜索词,index重置为0        
    inputValue (next, prev) {            
        this.listIndex = 0; //输入框变化时置0.默认选中第一个        
    }    
}}
</script>
<style lang="less" scoped>    
    @import '~@/style/common';    
    .draggable-content {        
        .search-student {            
            margin-bottom: 20px;            
            input {                
                width: 215px;                
                height: 24px;                
                border-bottom: 1px solid #BEBEBE;                
                color: #4A4A4A;                
                cursor: text;            
            }        
        }        
        .studentContainer {            
            overflow: auto;            
            width: 100%;            
            max-height: 335px;            
            border: 1px solid #C1D4D8;            
            li {                
                float: left;                
                width: 107px;                
                height: 46px;                
                cursor: pointer;                
                border-right: 1px solid #d8d8d8;                
                border-bottom: 2px solid #BDCBB3;                
                i {                    
                    float: left;                    
                    width: 16px;                    
                    height: 44px;                    
                    margin-right: 1px;                
                }                
                div {                    
                    float: right;                    
                    width: 89px;                    
                    padding-top: 5px;                    
                    font-size: 14px;                    
                    line-height: 18px;                    
                    span {                        
                        display: block;                        
                        color: #4A4A4A;                        
                        .ellipsis1;                    
                    }                    
                    var {                        
                        display: block;                        
                        color: #A2A2A2;                        
                        font-style: normal;                        
                        .ellipsis1;                    
                    }                
                }            
            }            
            li:nth-child(9n){                
                border-right: 0;            
            }   
            //拖拽列表鼠标移入时的灰色样式         
            li:hover {                
                i {                    
                    background: #D8D8D8 url('~@/assets/yidong.png') center center no-repeat;                
                }            
            }  
            //拖拽列表学生被选中的样式          
            li.selected {                
                background: #E4F2F3;            
            }     
            //拖拽的绿色样式       
            .rosterDraggableChosen,            
            .rosterDrag {                
                i {                    
                    background: #9EC583 url('~@/assets/yidong.png') center center no-repeat !important;                
                }            
            }        
        }    
    }    
    //搜索下拉框的样式
    .select-wrap {        
        background: #fff;        
        >ul {            
            >li {                
                cursor: pointer;                
                padding-left: 10px;                
                height: 36px;                
                line-height: 36px;                
                &:hover {                    
                    background: #F5FAFB;                
                }            
            }            
            .key-down-select {                
                background: #F5FAFB;                
                color: #0E858E;            
             }        
        }        
        .empty-data {            
            text-align: center;            
            color: #8C8C8C;;            
            padding-top: 10px;            
            padding-bottom: 10px;        
        }    
    }
</style>复制代码


6.基本配置

option配置项

option配置项
group: string or array 分组用的,同一组的不同list可以相互拖动
sort: boolean 定义是否可以拖拽
delay:number 定义鼠标选中列表单元可以开始拖动的延迟时间
disabled: boolean 定义是否此sortable对象是否可用,为true时sortable对象不能拖放排序等功能
animation: umber 单位:ms 动画时间
handle: selector 格式为简单css选择器的字符串,使列表单元中符合选择器的元素成为拖动的手柄,只有按住拖动手柄才能使列表单元进行拖动
filter: selector 格式为简单css选择器的字符串,定义哪些列表单元不能进行拖放,可设置为多个选择器,中间用“,”分隔
preventOnFilter: 当拖动filter时是否触发event.preventDefault()默认触发
draggable: selector 格式为简单css选择器的字符串,定义哪些列表单元可以进行拖放
ghostClass: selector 格式为简单css选择器的字符串,当拖动列表单元时会生成一个副本作为影子单元来模拟被拖动单元排序的情况,此配置项就是来给这个影子单元添加一个class,我们可以通过这种方式来给影子元素进行编辑样式
chosenClass: selector 格式为简单css选择器的字符串,目标被选中时添加
dragClass:selector 格式为简单css选择器的字符串,目标拖动过程中添加
forceFallback: boolean 如果设置为true时,将不使用原生的html5的拖放,可以修改一些拖放中元素的样式等
fallbackClass: string 当forceFallback设置为true时,拖放过程中鼠标附着单元的样式
dataIdAttr: data-id
scroll:boolean当排序的容器是个可滚动的区域,拖放可以引起区域滚动
scrollFn:function(offsetX, offsetY, originalEvent, touchEvt, hoverTargetEl) { … } 用于自定义滚动条的适配
scrollSensitivity: number 就是鼠标靠近边缘多远开始滚动默认30
scrollSpeed: number 滚动速度复制代码
函数配置

函数配置
setData: 设置值时的回调函数
onChoose: 选择单元时的回调函数
onStart: 开始拖动时的回调函数
onEnd: 拖动结束时的回调函数
onAdd: 添加单元时的回调函数
onUpdate: 排序发生变化时的回调函数
onRemove: 单元被移动到另一个列表时的回调函数
onFilter: 尝试选择一个被filter过滤的单元的回调函数
onMove: 移动单元时的回调函数
onClone: clone时的回调函数
以上函数对象的属性: 
to: 移动到的列表的容器
from:来源列表容器
item: 被移动的单元
clone: 副本的单元
oldIndex:移动前的序号
newIndex:移动后的序号复制代码


7.参考

这篇文章中有更详细的draggable参数配置,需要的可以参考下:


转载于:https://juejin.im/post/5cb59293e51d456e336cd48d

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值