sortablejs(前端拖拽排序的实现)

源文档:sortablejs - npm

安装

javascript 复制代码
npm install sortablejs --save

引入项目

javascript 复制代码
import Sortable from 'sortablejs';

使用示例

javascript 复制代码
<template>
    <ul id="items">
	   <li>item 1</li>
	   <li>item 2</li>
	   <li>item 3</li>
    </ul>
</template>

<script setup>
import Sortable from 'sortablejs';

const el = document.getElementById('items');
const sortable = Sortable.create(el);

</script>


<style scoped lang="scss">

</style>

sortablejs的配置项

javascript 复制代码
const sortable = new Sortable(el, {
	group: "name",  // or { name: "...", pull: [true, false, 'clone', array], put: [true, false, array] }
	sort: true,  //是否可以在列表内排序,默认开启
	delay: 0, //拖拽延迟时间(通常用于移动端实现长按拖拽)
	delayOnTouchOnly: false, //只有当用户使用触摸时才会延迟
	touchStartThreshold: 0, // 在取消延迟拖动事件之前,应该移动多少像素(px)
	disabled: false, //如果设置为true,则禁用可排序。
	store: null,  // @see Store
	animation: 150,  // ms,排序时移动项目的动画速度,设置0则无过渡动画
	easing: "cubic-bezier(1, 0, 0, 1)", //渐变动画,默认为null,可访问https://easings.net/查看示例
	handle: ".my-handle",  // 需要绑定的元素(比如我们想长按某个盒子来拖拽其父元素,那么此时我们仅需要给这个盒子添加这里配置的类型即可)
	filter: ".ignore-elements",  //不需要进行拖动的元素(给元素添加这个选项配置的类名后,该元素将不会被拖动)
	preventOnFilter: true, // 当触发filter时调用event.preventDefault()
	draggable: ".item",  // 指定元素内的哪些项可以被拖动
	dataIdAttr: 'data-id', // HTML attribute that is used by the `toArray()` method
	ghostClass: "sortable-ghost",  //占位元素类名,可以对此类名进行配置以实现特定效果(拖拽时,sortablejs会生成一个占位元素占据元素的位置,此类名主要用于控制这个元素的样式)
	chosenClass: "sortable-chosen",  //所选项目的类名
	dragClass: "sortable-drag",  //拖动项的类名
	swapThreshold: 1, //交换区阈值
	invertSwap: false, //如果设置为true,将始终使用反向交换区
	invertedSwapThreshold: 1, //反转交换区的阈值(默认设置为swapThreshold值)
	direction: 'horizontal', // 可分拣方向(如果没有给出,将自动检测)
	forceFallback: false,  //忽略HTML5 行为并强制回退
	fallbackClass: "sortable-fallback",  //使用forceFallback时克隆的DOM元素的类名
	fallbackOnBody: false,  //将克隆的DOM元素附加到文档正文中
	fallbackTolerance: 0, //以像素为单位指定鼠标在被视为拖动之前应该移动多远。
	dragoverBubble: false,//拖拽经过时是否冒泡
	removeCloneOnHide: true, //当clone元素未显示时将其删除,而不是将其隐藏
	emptyInsertThreshold: 5, //px,鼠标距离必须为空可排序,才能将拖动元素插入其中


	setData: function (/** DataTransfer */dataTransfer, /** HTMLElement*/dragEl) {
		dataTransfer.setData('Text', dragEl.textContent); //HTML5 DragEvent的DataTransfer对象
	},

	//元素被选中时触发
	onChoose: function (/**Event*/evt) {
		evt.oldIndex;  //当前元素在父元素中的索引
	},

	//元素未被选中时(与onEnd事件相似)
	onUnchoose: function(/**Event*/evt) {
		// same properties as onEnd
	},

	//开始拖拽时
	onStart: function (/**Event*/evt) {
		evt.oldIndex;  //当前元素在父元素中的索引
	},

	//拖拽完成时
	onEnd: function (/**Event*/evt) {
		var itemEl = evt.item;  //被拖拽的元素
		evt.to;    //目标列表
		evt.from;  //初始列表
		evt.oldIndex;  //初始列表的初始索引(即拖拽改变之前的列表索引)
		evt.newIndex;  //元素在新父级中的新索引(即拖拽之后形成的列表的索引)
		evt.oldDraggableIndex; //元素在旧父元素内的旧索引,仅计算可拖动元素		 
        evt.newDraggableIndex; //元素在新父级中的新索引,仅计算可拖动元素
		evt.clone //克隆元素		
        evt.pullMode;  //当项目位于另一个可排序的位置时:如果是克隆,则为"clone";如果是移 
        动,则为true

	//元素从另一个列表中删除到列表中
	onAdd: function (/**Event*/evt) {
		//与onEnd具有相同的属性
	},

	//更改列表中的排序
	onUpdate: function (/**Event*/evt) {
		//与onEnd具有相同的属性
	},

	//由列表的任何更改调用(添加/更新/删除)
	onSort: function (/**Event*/evt) {
		//与onEnd具有相同的属性
	},

	//元素从列表中删除到另一个列表中
	onRemove: function (/**Event*/evt) {
		//与onEnd具有相同的属性
	},

	//尝试拖动已过滤的元素
	onFilter: function (/**Event*/evt) {
		var itemEl = evt.item;  //HTMLElement接收到"mousedown"、"tapstart"事件。
	},

	//在列表中或列表之间移动项目的事件
	onMove: function (/**Event*/evt, /**Event*/originalEvent) {
		// Example: https://jsbin.com/nawahef/edit?js,output
		evt.dragged; // 被拖动元素
		evt.draggedRect; // DOMRect {left, top, right, bottom}
		evt.related; // HTMLElement on which have guided
		evt.relatedRect; // DOMRect
		evt.willInsertAfter; //布尔值,默认为真。为真的情况下Sortable将在目标后插入拖动元素
		originalEvent.clientY; //鼠标位置
		// return false; --- for cancel
		// return -1; --- 在目标之前插入
		// return 1; --- 在目标之后插入
		// return true; ---根据方向保留默认插入点
		// return void; ---根据方向保留默认插入点
	},

	//创建元素克隆时调用
	onClone: function (/**Event*/evt) {
		var origEl = evt.item;
		var cloneEl = evt.clone;
	},

	//当拖动元素改变位置时调用
	onChange: function(/**Event*/evt) {
		evt.newIndex //使用此事件的最可能原因是获取拖动元素的当前索引
		// same properties as onEnd
	}
});

vue3中的使用演示

javascript 复制代码
<template>
  <div class="home">
     <ul ref="boxRef" >
         <li v-for="item in list"  :key="item.id" >
            <div class="bread">
                <van-icon name="wap-nav" size="30px"  ></van-icon>
            </div>  
            <span> {{ item.text }}</span>
         </li>
     </ul>
  </div>
</template>

<script setup>
import { ref,onMounted } from 'vue';
import Sortable from 'sortablejs';

//sortable实例
const instance = ref(null)

const list = ref([
  {
    text: '张三',
    id: 1,
  },
  {
    text: '李四',
    id: 2,
  },
  {
    text: '王五',
    id: 3,
  },
  {
    text: '赵四',
    id: 4,
  },
  {
    text: '王大麻子',
    id: 5,
  },
]);

//获取容器dom元素
const boxRef = ref(null)

onMounted(()=>{
  instance.value = Sortable.create(boxRef.value,{
         handle:'.bread', //设置了此类名,只有长按有这个类名的元素才能拖动(注意这里要带上选择器符号)
         delay:600, //延迟600毫秒才能拖动
         chosenClass:"move" //可以拖动时,被拖动项的类名
  }) 
})
</script>

<style scoped lang="less">
.move{
  background: orange;
}
.box {
  margin: 20px auto;
  width: 600px;
  height: 600px;
  box-shadow: 0 0 3px 5px #ccc;
}
ul{
  margin:10px auto;
  width:600px;
  li{
    margin:10px 0;
    display: flex;
    align-items: center;
    height:80px;
    line-height: 80px;
    text-align: center;
    background:#ccc; 
    .bread{
      margin: 0 20px;
      display: flex;
      align-items: center;
      width:50px;
      height:50px;
    }
  }
}
</style>

在实际的使用中我们通常使用sortablejs做拖拽排序,这就会涉及到异步请求及请求发送失败的情况。那么就会发现一个问题,当我们的请求发送失败后按照常理应该还原排序但是sortablejs似乎并没有给予相应的方法来实现这个功能。我们可以如下操作:

javascript 复制代码
<template>
  <div class="home">
    <ul ref="boxRef" @sort="onSort">
      <li v-for="item in list" :key="item.id">
        <div class="bread">
          <van-icon name="wap-nav" size="30px"></van-icon>
        </div>
        <span> {{ item.text }}</span>
      </li>
    </ul>
  </div>
</template>

<script setup >
import { ref, onMounted } from 'vue';
import Sortable from 'sortablejs';

//获取容器dom元素
const boxRef = ref(null);

const list = ref([
  {
    text: '张三',
    id: 1,
  },
  {
    text: '李四',
    id: 2,
  },
  {
    text: '王五',
    id: 3,
  },
  {
    text: '赵四',
    id: 4,
  },
  {
    text: '王大麻子',
    id: 5,
  },
]);


//sortable实例
const instance = ref(null);


//排序时触发的回调函数
const onSort = async (value) => {
  const { oldIndex, newIndex, from } = value;
  try {
    //模拟的异步请求失败情况
    await new Promise((resolve, reject) => {
      reject(new Error('发送错误'));
    });
  } catch (error) {
    //请求失败时还原排序
    const List = Array.from(from.children);
    const item = List.splice(newIndex, 1)[0];
    if (oldIndex > newIndex) {
      from.insertBefore(item, List[oldIndex + 1]);
    } else {
      from.insertBefore(item, List[oldIndex]);
    }
  }
};


onMounted(() => {
  //初始化sortablejs实例
  instance.value = Sortable.create(boxRef.value, {
    handle: '.bread', //设置了此类名,只有长按有这个类名的元素才能拖动(注意这里要带上选择器符号)
    //  delay:600, //延迟600毫秒才能拖动
    chosenClass: 'move', //可以拖动时,被拖动项的类名(可以自定义样式)
  });
});
</script>

<style scoped lang="less">
.move {
  background: orange;
}
.box {
  margin: 20px auto;
  width: 600px;
  height: 600px;
  box-shadow: 0 0 3px 5px #ccc;
}
ul {
  margin: 10px auto;
  width: 600px;
  li {
    margin: 10px 0;
    display: flex;
    align-items: center;
    height: 80px;
    line-height: 80px;
    text-align: center;
    background: #ccc;
    .bread {
      margin: 0 20px;
      display: flex;
      align-items: center;
      width: 50px;
      height: 50px;
    }
  }
}
</style>

这样就可以实现日常的工作需求,考虑到每次写这么多东西会很麻烦,我们可以使用vue的自定义指令将它封装成一个指令。目前已经有插件完成了这一步骤,大家也可以尝试一下这个插件。

传送门:vue3-sortablejs - npm

相关推荐
学传打活7 天前
【边打字.边学昆仑正义文化】_进阶篇5 宇宙星系的运转(续3)
微信公众平台·1024程序员节·汉字·昆仑正义文化
学传打活12 天前
【边打字.边学昆仑正义文化】_进阶篇5 宇宙星系的运转(续1)
微信公众平台·1024程序员节·汉字·昆仑正义文化
fangzhanpeng16820 天前
快速掌握C#语言基础知识点(1.基础数据类型)
开发语言·c#·1024程序员节
无己心22 天前
面向多平台 AI 搜索引擎的适配层架构设计
前端·人工智能·搜索引擎·ai·1024程序员节
u0103055271 个月前
AI驱动的安卓UI自动生成功能实现
人工智能·1024程序员节
u0103055271 个月前
长株潭智能体赋能腾讯元器链接共享
1024程序员节
云贝贝贝1 个月前
OceanBase认证体系介绍与备考指南
运维·服务器·oceanbase·1024程序员节
u0103055271 个月前
Java图像处理实战指南
人工智能·1024程序员节
u0103055271 个月前
Java AWT鼠标事件全解析
人工智能·1024程序员节
u0103055271 个月前
Java实用类应用精讲
人工智能·1024程序员节