一、鼠标事件模拟拖拽
需要移动元素的父元素上监听键盘按下、弹起的事件,当鼠按下的时候监听鼠标移动事件并记录当前拖拽元素的位置,在mousemove中移动拖拽元素到目标位置,当鼠标弹起的时候清除mousemove事件
ps: 无动画
<template>
<v-sheet class="d-flex flex-column justify-center align-center my-drag-list">
<div v-for="item in list" :key="item.id" class="my-drag-item">
{{item.title}}
</div>
</v-sheet>
</template>
<script>
// 导入数据
import list from '../../common/data.json';
export default {
data() {
return {
list,
domList: null,
draging: null,
dragIndex: null,
mounted() {
this.domList = document.querySelector(".my-drag-list");
// 在拖拽元素的父元素上监听鼠标事件
this.domList.onmousedown = this.draDown;
this.domList.onmouseup = this.dragUp;
methods: {
// 鼠标按下
draDown(e) {
if ((!e.type === 'mousedown' && e.buttons === 1)) return; // 鼠标左键按下
let target = e.path.find((item) => {
return item.className ? item.className.includes("my-drag-item") : "";
if (!target) return;
this.draging = e.target;
this.dragIndex = Array.prototype.indexOf.call(this.domList.children, this.draging);
// 监听鼠标移动
this.domList.onmousemove = this.dragMove;
// 鼠标移动
dragMove(e) {
// 鼠标移动过的元素是需要拖拽元素
let target = e.path.find((item) => {
return item.className ? item.className.includes("my-drag-item") : "";
if (!target) return;
let index = Array.prototype.indexOf.call(this.domList.children, target);
// 插入拖拽元素到目标位置
if (this.dragIndex > index) {
target.parentNode.insertBefore(this.draging, target);
} else {
target.parentNode.insertBefore(this.draging, target.nextSibling);
// 鼠标弹起
dragUp() {
this.domList.onmousemove = null;
</script>
<style scoped>
.my-drag-item {
height: 40px;
width: 400px;
margin: 10px;
line-height: 40px;
text-align: center;
border-radius: 10px;
border: 1px solid rgb(242, 194, 79);
background: rgba(242, 194, 79, 0.1);
cursor: move;
</style>
二、原生拖拽api
原理和之前的鼠标模拟差不多,现在dragstart里获取到拖拽的元素,然后在dragover中判断移动过的元素是否在需要拖拽的元素中,如果在的话就比较拖拽元素和目标元素的下标位置然后插入到目标位置
<template>
<div class="container">
<ul id="box" @dragstart="dragstart" @dragover="dragover">
<li draggable="true" v-for="(item,index) in 20" :key="index">
{{item}}
</div>
</template>
<script>
export default {
data() {
return {
domList: null,
draging: null,
mounted() {
this.domList = document.querySelector("#box");
methods: {
dragstart(event) {
this.draging = event.target;
dragover(event) {
var target = event.target;
if (target !== this.draging && Array.prototype.indexOf.call(this.domList.children, target) > -1) {
if (this.index(this.draging) < this.index(target)) {
target.parentNode.insertBefore(
this.draging,
target.nextSibling
} else {
target.parentNode.insertBefore(this.draging, target);
</script>
<style>
.container {
display: flex;
justify-content: center;
align-items: center;
list-style: none;
width: 400px;
height: 40px;
margin: 10px;
line-height: 40px;
text-align: center;
border-radius: 10px;
border: 1px solid rgba(154, 129, 203, .6);
background: rgba(154, 129, 203, .2);
cursor: move;
</style>
三、Vue.Draggable
1.安装Vue.Draggable
npm install vuedraggable
直接在需要使用的页面通过import引入即可,然后注册组件,通过组件的方式使用。Vue.Draggable提供了一些可配置的选项,可通过绑定配置的方式使用,会在后面介绍
<template>
<v-sheet class="d-flex flex-column justify-center align-center">
<draggable v-model="list" v-bind="dragOptions" class="drag-box" @end="onEnd">
<v-sheet v-for="item in list" :key="item.id" class="drag-item">
{{item.title}}
</v-sheet>
</draggable>
</v-sheet>
</template>
<script>
import draggable from 'vuedraggable';
import list from '../../common/data.json';
export default {
components:{
draggable
data() {
return {
list,
computed: {
dragOptions() {
return {
animation: 200,
methods: {
onEnd() {
// 可在此函数中直接拿到了改变顺序后的list列表
this.list.map(item => console.log(item.title));
</script>
<style scoped>
.drag-box {
display: flex;
flex-direction: column;
align-content: center;
justify-content: center;
.drag-item {
height: 50px;
width: 400px;
margin: 10px;
line-height: 40px;
text-align: center;
border-radius: 10px;
border: 1px solid skyblue;
background: rgba(135, 206, 235, 0.1);
cursor: move;
</style>
四、sortable.js
1.安装sortablejs
npm install sortablejs
首先获取拖拽元素列表的父元素,new一个Sortable并将dom元素传入,第二个参数是可选项的配置(和之前的Vue.Draggable差不多,Vue.Draggable就是基于Sortable实现的)
<template>
<v-container class="pa-2 drag-list d-flex flex-column justify-center align-center" rounded>
<v-sheet v-for="item in list" :key="item.id" class="drag-item">
{{item.title}}
</v-sheet>
</v-container>
</template>
<script>
import { Sortable } from "sortablejs";
import list from '../../common/data.json';
export default {
name: "SSortable",
components: {},
data: () => ({
mounted() {
let options = {
animation: 100,
onEnd: ({ newIndex, oldIndex }) => {
const val = this.list[oldIndex];
this.list.splice(oldIndex, 1);
this.list.splice(newIndex, 0, val);
// 此时的list是改变后的列表
console.log(this.list);
let el = document.querySelector(".drag-list");
new Sortable(el, options);
methods: {
</script>
<style scoped>
.drag-item {
height: 50px;
width: 400px;
margin: 10px;
line-height: 40px;
text-align: center;
border-radius: 10px;
border: 1px solid rgb(113, 114, 114);
background: rgba(113, 114, 114, 0.1);
cursor: move;
</style>
1.鼠标模拟拖拽-批量拖拽排序
2.sortable.js-批量拖拽排序