diff --git a/uni_modules/HM-dragSorts/changelog.md b/uni_modules/HM-dragSorts/changelog.md
new file mode 100644
index 0000000..dbf616d
--- /dev/null
+++ b/uni_modules/HM-dragSorts/changelog.md
@@ -0,0 +1,50 @@
+## 1.0.6(2023-12-19)
+* 修复vue3app环境下,拖动丢失行的问题
+* UVUE版本支持了多行多列,可以去看看[传送门](https://ext.dcloud.net.cn/plugin?id=15953)
+## 1.0.5(2023-01-09)
+* 修复拖动后,@onclick返回错误行下标
+* 增加push(),unshift(),splice()返回值,现在通过这三个函数修改后,会返回修改后的列表数组
+## 1.0.4(2022-11-17)
+* 新增push,unshift,splice函数,实现列表的删除插入
+* 重写了给wxs传递数据的逻辑
+## 1.0.3(2022-08-19)
+* [重写] 拖拽排序的算法,提升渲染性能
+* [修复] 修复删除行,排序出错的问题
+* [兼容] 触发长按时长属性(longTouchTime)增加兼容微信小程序(微信基础库2.14.2或以上)
+* [废弃] 因为微信循环插槽会无限警告,所以废弃插槽
+* [BUG] vue3下,只支持长按拖拽
+## 1.0.2(2022-08-19)
+* [重写] 拖拽排序的算法,提升渲染性能
+* [废弃] 因为微信循环插槽会无限警告,所以废弃插槽
+* [兼容] 触发长按时长属性(longTouchTime)增加兼容微信小程序(微信基础库2.14.2或以上)
+* [BUG] vue3下,只支持长按拖拽
+## 1.0.1(2022-08-19)
+* [重写] 拖拽排序的算法,提升渲染性能
+* [废弃] 因为微信循环插槽会无限警告,所以废弃插槽
+* [兼容] 触发长按时长属性(longTouchTime)增加兼容微信小程序(微信基础库2.14.2或以上)
+* [BUG] vue3下,只支持长按拖拽
+## 1.0.0(2022-08-19)
+* [重写] 拖拽排序的算法,提升渲染性能
+* [废弃] 因为微信循环插槽会无限警告,所以废弃插槽
+* [兼容] 触发长按时长属性(longTouchTime)增加兼容微信小程序(微信基础库2.14.2或以上)
+* [BUG] vue3下,只支持长按拖拽
+## 0.2.5(2021-09-09)
+* 修复 wxs使用了es6语法导致编译到微信小程序出错 感谢 @小小贝 反馈
+## 0.2.4(2021-09-01)
+* 修复 iOS在整行拖拽情况下,触感反馈与点击事件冲突的问题 感谢 @粲然 反馈
+## 0.2.3(2021-08-09)
+* 修复 修改list导致拖拽报错
+## 0.2.2(2021-07-06)
+更新confirm的bug问题,这是我手贱写出的bug。
+## 0.2.1(2021-07-02)
+* 修复 数据中传入id导致不触发回调事件的问题 感谢@layu反馈
+* 优化 拖拽和位置交换动画使用translate3d 感谢@pwiz反馈
+## 0.2.0(2021-06-23)
+* 修复 页面滚动后拖拽位置不正确问题
+* 修复 页面使用多个组件时,组件间互相影响问题
+* 修复 微信小程序设置列表高度不生效的问题
+## 0.1.2(2021-02-02)
+* 修复moveRow取值错误问题 感谢@诗人的咸鱼 反馈
+## 0.1.1(2021-02-02)
+* 增加开关触感反馈参数feedbackGeneratorState
+* 发布uni_modules版本(需HX3.1.0以上)
diff --git a/uni_modules/HM-dragSorts/components/HM-dragSorts/HM-dragSorts.vue b/uni_modules/HM-dragSorts/components/HM-dragSorts/HM-dragSorts.vue
new file mode 100644
index 0000000..f490dfe
--- /dev/null
+++ b/uni_modules/HM-dragSorts/components/HM-dragSorts/HM-dragSorts.vue
@@ -0,0 +1,823 @@
+
+
+
+
+
+
+
+
+
+
+ {{shadowRow.name}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{row.name}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 触发wxs跳板,请勿删除
+
+ 触发renderjs跳板,请勿删除
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/HM-dragSorts/components/HM-dragSorts/drag.wxs b/uni_modules/HM-dragSorts/components/HM-dragSorts/drag.wxs
new file mode 100644
index 0000000..de7591f
--- /dev/null
+++ b/uni_modules/HM-dragSorts/components/HM-dragSorts/drag.wxs
@@ -0,0 +1,371 @@
+
+
+var scrollTop = {}; //滚动条位置
+// 排序列表
+var sortList={};
+var isMove = false; //是否可拖动 长按事件控制切换这个状态
+var touchTimer = false; //长按事件定时器
+// 当页面有多个当前组件时,guid用来识别当前的列表的。因为一个页面内多个组件的wxs作用域相同。
+
+
+function setScrollTop(tmpGuid) {
+ if (typeof scrollTop[tmpGuid] == "undefined") {
+ scrollTop[tmpGuid] = 0;
+ }
+}
+
+function scroll(event, instance) {
+ var dataView = instance.selectComponent('#dataView');
+ var viewData = dataView.getDataset();
+ setScrollTop(viewData.guid)
+ scrollTop[viewData.guid] = event.detail.scrollTop;
+}
+
+function initVar(state, instance) {
+ var dataView = instance.selectComponent('#dataView');
+ var viewData = dataView.getDataset();
+ // 读取配置项
+ // 获取scroll-view id
+ config = All_Config[viewData.guid];
+
+ setScrollTop(config.guid);
+ state.initscrollTop = scrollTop[config.guid];
+
+}
+function getRowSort(findId,instance){
+ for (var i = 0; i < sortList[config.guid].length; i++) {
+ if(sortList[config.guid][i].id==findId){
+ currentRowView = sortList[config.guid][i].rowView;
+ return sortList[config.guid][i].lastSort;
+ }
+ }
+}
+var shadowRowBoxView=null;
+var shadowRowView = null;
+var currentRowView=null;
+var rowSort=0;
+var sorting = false;
+function touchstart(event, instance) {
+ if(sorting){
+ return ;
+ }
+ sorting = true;
+ // 兼容setTimeout
+ if(typeof setTimeout ==="undefined" && typeof instance.setTimeout !== 'undefined'){
+ setTimeout = instance.setTimeout;
+ clearTimeout = instance.clearTimeout;
+ }
+
+ isMove = false;
+ var rowData = event.instance.getDataset();
+ var state = instance.getState();
+ if (event.touches.length == 1) {
+ state.point = event.touches[0];
+
+ state.islongTap = true;
+ state.rowData = rowData;
+ //读取数据
+ initVar(state, instance);
+ }
+ var rowStyle = event.instance.getComputedStyle(['height']);
+ config.rowHeight = parseFloat(rowStyle.height); //获取行高
+ // 计算shadowRow.style.top
+
+ rowSort = getRowSort(rowData.id,instance);
+ var shadowRowTop = rowSort * config.rowHeight;
+ shadowRowTop = shadowRowTop - scrollTop[config.guid];
+ // 加载shadowRow数据
+ instance.callMethod("loadShadowRow", {
+ rowSort: rowSort
+ });
+ state.shadowRowTop = shadowRowTop;
+ // 设置shadowRow初始位置
+ shadowRowBoxView = instance.selectComponent('#shadowRowBox');
+ shadowRowBoxView.setStyle({
+ 'top': shadowRowTop + 'px'
+ })
+ shadowRowView = instance.selectComponent('#shadowRow')
+ //长按事件
+ if (config.longTouch) {
+ touchTimer && clearTimeout(touchTimer);
+ touchTimer = setTimeout(function() {
+ longpress(event, instance);
+ }, config.longTouchTime)
+ }
+}
+
+function longpress(event, instance) {
+ if (config.longTouch) {
+ isMove = true;
+ moveRow(instance, 0)
+ }
+}
+
+function touchmove(event, instance) {
+ var state = instance.getState();
+ var rowData = event.instance.getDataset();
+ var movePoint = event.touches[0];
+ var initPoint = state.point;
+ var moveY = movePoint.pageY - initPoint.pageY;
+ if (config.longTouch) {
+ if (Math.abs(moveY) > 10) {
+ clearTimeout(touchTimer);
+ }
+ if (!isMove) {
+ return;
+ }
+ }
+ moveRow(instance, moveY);
+ //阻止滚动页面
+ if (event.preventDefault) {
+ event.preventDefault();
+ }
+ return false;
+}
+function touchend(event, instance) {
+ if (config.longTouch) {
+ clearTimeout(touchTimer);
+ if (!isMove) {
+ oldOffset = null;
+ sorting = false;
+ return;
+ }
+ }
+ if (lastCommand != "stop") {
+ lastCommand = "stop";
+ config.autoScroll && instance.callMethod("pageScroll", {
+ 'guid': config.guid,
+ 'command': "stop"
+ });
+ }
+ var state = instance.getState();
+ // 把隐藏的行重新显示
+ resetRowStyle(instance,state.rowData.id)
+ // 隐藏ShadowRow
+ resetShadowRowStyle(instance,state.offset)
+ if (typeof state.offset !== "undefined" && rowSort != state.offset && state.offset != null) {
+ var sortArray=[];
+ for (var i = 0; i < sortList[config.guid].length; i++) {
+ sortList[config.guid][i].lastSort = sortList[config.guid][i].newSort;
+ sortArray.push(sortList[config.guid][i].newSort);
+ sortList[config.guid][i].rowView.removeClass('ani');
+ }
+ instance.callMethod("sort", {
+ index: rowSort,
+ offset: state.offset,
+ sortArray:sortArray
+ });
+ } else {
+ sorting = false;
+ triggerFeedbackGenerator(instance); //震动反馈
+ return false;
+ }
+ state.offset = null;
+ oldOffset = null;
+ sorting = false;
+ triggerFeedbackGenerator(instance); //震动反馈
+ return false;
+}
+// 重置列表行
+function resetRowStyle(instance,id) {
+ currentRowView.removeClass('hide');
+}
+// 重置拖拽行
+function resetShadowRowStyle(instance,offset) {
+ shadowRowBoxView.removeClass('show');
+ shadowRowBoxView.addClass('hide');
+ shadowRowBoxView.setStyle({});
+}
+var lastCommand = '';
+
+// move Row
+function moveRow(instance, moveY) {
+ var state = instance.getState();
+
+ // 显示shadowRowBox
+ shadowRowBoxView.removeClass('hide');
+ shadowRowBoxView.hasClass('show') || shadowRowBoxView.addClass('show');
+ // 移动shadowRowBox里面的shadowRow
+ shadowRowView.setStyle({
+ 'transform': 'translate3d(0,' + moveY + 'px,10px)',
+ '-webkit-transform': 'translate3d(0,' + moveY + 'px,10px)'
+ });
+ // 隐藏列表对应行
+ currentRowView.hasClass('hide') || currentRowView.addClass('hide');
+ currentRowView.removeClass('ani')
+ var listClientY = state.shadowRowTop + moveY + config.rowHeight/2;
+ var tmpscrollListTop = scrollTop[config.guid];
+
+ // 拖拽至边缘滚动视图 距离顶部距离1.5行高触发上滚动 下滚动同理
+ var callMethodData = {
+ guid: config.guid,
+ command: listClientY < config.ListHeight * 0.2 ? "up" : listClientY > config.ListHeight - (config.ListHeight * 0.2) ? "down" :
+ "stop",
+ scrollTop: tmpscrollListTop,
+ }
+ // 把滚动指令发给逻辑层
+ if (lastCommand != callMethodData.command) {
+ lastCommand = callMethodData.command;
+ config.autoScroll && instance.callMethod("pageScroll", callMethodData);
+ }
+
+ var moveOffset = moveY + scrollTop[config.guid] - state.initscrollTop;
+ var offset = calcOffset(rowSort, moveOffset);
+ if (offset <= 2 || offset >= config.listLength - 2) {
+ callMethodData.command = 'stop';
+ }
+ // 为减少卡顿,微信小程序端,在滚动视图期间不进行列表位置交换
+ if (config.autoScroll && (!config.isAppH5) && callMethodData.command != 'stop') {
+ return;
+ }
+ oldOffset = oldOffset == null ? rowSort : oldOffset;
+ if (offset < 0 || offset >= config.listLength) {
+ return;
+ }
+ if (offset == oldOffset) {
+ return;
+ }
+
+ oldOffset = offset;
+ state.offset = offset;
+ //触发change事件 并交换列表位置
+ instance.callMethod("change", {
+ index: rowSort,
+ moveTo: state.offset
+ });
+ for (var i = 0; i < sortList[config.guid].length; i++) {
+ var sort = sortList[config.guid][i].lastSort;
+ var newSort = sortList[config.guid][i].newSort;
+ if ((sort >= offset && sort <= rowSort) || (sort <= offset && sort >= rowSort)) {
+ if(sort == rowSort) {
+ newSort = offset;
+ }else{
+ newSort = sort < rowSort ? sort+1 : sort-1;
+ }
+ }else{
+ newSort = sort;
+ }
+ if(sortList[config.guid][i].newSort == newSort){
+ continue;
+ }
+ sortList[config.guid][i].newSort = newSort;
+ var translateY = (sortList[config.guid][i].newSort-sortList[config.guid][i].sort) * 100;
+ sortList[config.guid][i].rowView.hasClass('ani') || sortList[config.guid][i].rowView.addClass('ani');
+ sortList[config.guid][i].rowView.setStyle({
+ 'transform': 'translate3d(0,' + translateY + '%,0)',
+ '-webkit-transform': 'translate3d(0,' + translateY + '%,0)'
+ });
+ }
+ triggerFeedbackGenerator(instance); //震动反馈
+}
+//计算偏移index
+var oldOffset = null;
+function calcOffset(initSort, moveY) {
+ var offset = initSort + parseInt(moveY / config.rowHeight); //偏移 行高的倍数
+ var rest = moveY % config.rowHeight;
+ if (rest > 0) {
+ offset = offset + (rest / config.rowHeight >= 0.6 ? 1 : 0);
+ if (offset < oldOffset) {
+ offset = rest / config.rowHeight <= 0.4 ? offset : oldOffset;
+ }
+ } else
+ {
+ offset = offset + (rest / config.rowHeight <= -0.6 ? -1 : 0);
+ if (offset > oldOffset) {
+ offset = rest / config.rowHeight >= -0.4 ? offset : oldOffset;
+ }
+ }
+ return offset;
+}
+
+//触感反馈
+//wxs 不支持条件编译,所以用此方法判断
+var isiOSAPP = typeof plus != "undefined" && plus.os.name == 'iOS';
+var UISelectionFeedbackGenerator;
+var impact
+
+if (isiOSAPP) {
+ UISelectionFeedbackGenerator = plus.ios.importClass("UISelectionFeedbackGenerator");
+ impact = new UISelectionFeedbackGenerator();
+ impact.init();
+}
+function triggerFeedbackGenerator(instance) {
+ if (!config.feedbackGenerator) {
+ //关闭触感反馈
+ return;
+ }
+ if (isiOSAPP) {
+ //异步,避免与点击事件冲突
+ setTimeout(function(){
+ impact.selectionChanged();
+ },0)
+ } else {
+ if (typeof plus != "undefined") {
+ plus.device.vibrate(12)
+ } else {
+ instance.callMethod("vibrate");
+ }
+ }
+}
+var All_Config={};
+var config = {};
+function receiveData(e,state, instance){
+ var data = JSON.parse(e);
+ var tmp_config = {};
+ var hasGuid = false;
+ var sortArray=[];
+ for(var i=0;i0){
+ tmp_row.lastSort = sortArray[i];
+ tmp_row.newSort = tmp_row.lastSort;
+ }
+ sortList[guid].push(tmp_row);
+ var translateY = (tmp_row.lastSort-tmp_row.sort) * 100;
+ tmp_row.rowView.setStyle({
+ 'transform': 'translate3d(0,' + translateY + '%,0)',
+ '-webkit-transform': 'translate3d(0,' + translateY + '%,0)'
+ });
+ }
+
+}
+// 输出
+module.exports = {
+ receiveData:receiveData,
+ scroll: scroll,
+ longpress: longpress,
+ touchstart: touchstart,
+ touchmove: touchmove,
+ touchend: touchend
+}
\ No newline at end of file
diff --git a/uni_modules/HM-dragSorts/package.json b/uni_modules/HM-dragSorts/package.json
new file mode 100644
index 0000000..32e0a05
--- /dev/null
+++ b/uni_modules/HM-dragSorts/package.json
@@ -0,0 +1,81 @@
+{
+ "id": "HM-dragSorts",
+ "displayName": "拖动排序列表 HM-dragSorts",
+ "version": "1.0.6",
+ "description": "可拖动行,对列表进行排序,拖动触感反馈,兼容APP-VUE、H5、MP-WEIXIN",
+ "keywords": [
+ "拖拽",
+ "拖动",
+ "拖动排序",
+ "drag",
+ "触感反馈"
+],
+ "repository": "",
+ "engines": {
+ "HBuilderX": "^3.6.0"
+ },
+"dcloudext": {
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "震动"
+ },
+ "npmurl": "",
+ "type": "component-vue"
+ },
+ "uni_modules": {
+ "dependencies": [],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "n"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "n",
+ "IE": "n",
+ "Edge": "n",
+ "Firefox": "n",
+ "Safari": "n"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "n",
+ "百度": "n",
+ "字节跳动": "n",
+ "QQ": "n"
+ },
+ "快应用": {
+ "华为": "n",
+ "联盟": "n"
+ },
+ "Vue": {
+ "vue2": "y",
+ "vue3": "n"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/HM-dragSorts/readme.md b/uni_modules/HM-dragSorts/readme.md
new file mode 100644
index 0000000..1a50e98
--- /dev/null
+++ b/uni_modules/HM-dragSorts/readme.md
@@ -0,0 +1,117 @@
+
+
+##组件说明
+
+> * 这是一个传入列表数据会生成一个可拖动排序列表的组件
+> * 此组件只支持单列多行,UVUE版本支持了多行多列,可以去看看[传送门](https://ext.dcloud.net.cn/plugin?id=15953)
+> * 因为废弃了插槽,所以,行的样式需要自行到组件内部去修改
+> * 行内容可以自行到组件,组件只支持每行都相等高度的列表
+> * 拖动会有触感反馈,如果设备支持的话。
+> * 组件使用了wxs,兼容APP-VUE、H5、MP-WEIXIN,其他端未做兼容,不支持。
+> * [BUG] vue3下,只支持长按拖拽
+> * 下载示例并运行,你的很多疑问或得到答案。
+
+
+###属性说明
+
+|属性名 |类型 |说明 |
+|-- |-- |-- |
+|list|ObjectArray |必填,列表数据,数据格式请参考示例,
注意:数据非双向绑定,拖动并不会直接修改list数据,排序过的数据在confirm中获取 |
+|rowHeight|Int |选填,每一行的高度,单位:px,默认44px |
+|listHeight|Int |选填,整个列表的高度,默认等于窗口高度 |
+|listBackgroundColor|String |选填,列表底色,注意是列表的底色,不是行的底色,默认#FFFFFF |
+|feedbackGenerator|Boolean |选填,是否开启拖动触感反馈,可选值true/false,默认true 开启 |
+|longTouch|Boolean |选填,是否长按拖动,可选值true/false,默认false 关闭,如果是整行拖拽,请开启长按拖拽,不然页面不能滚动 |
+|autoScroll|Boolean |选填,是否拖拽至边缘自动滚动列表,可选值true/false,默认true 开启 |
+|longTouchTime|Int |选填,触发长按时长,单位:ms,默认350ms |
+|@onclick|EventHandle |点击事件,返回被点击行的数据,event = {index:被点击行的下标,row:被点击行的数据} |
+|@confirm|EventHandle |拖拽结束且行位置发生了改变,触发confirm事件,event = {index:'原始下标',moveTo:'被拖动到的下标',moveRow:'拖动行数据',list:'整个列表拖动后的数据'} |
+|@change|EventHandle |拖拽过程中,行位置发生交换时,触发change事件,event = {index:'原始下标',moveTo:'被拖动到的下标',moveRow:'拖动行数据'} |
+
+###内置函数说明
+ > ####push,unshift,splice函数
+内置了push,unshift,splice函数,组件设置ref属性,通过$refs调用,实现列表的删除插入,使用方法和数组的push,unshift,splice一致,push,unshift,splice函数修改后会返回修改后的值
+例如:
+ ```
+ let tmplist = this.$refs.dragSorts.splice(5,1,...rows);
+ ```
+
+
+##使用示例
+页面:
+```
+
+
+
+
+
+
+```
+script:
+
+```
+ import dragSorts from '@/uni_modules/components/HM-dragSorts/HM-dragSorts.vue' // 组件符合easycom规范,默认这个可以不写
+ export default {
+ components: {'HM-dragSorts':dragSorts},// 组件符合easycom规范,默认这个可以不写
+ data() {
+ return {
+ list:[
+ {"name": "花呗", "icon": "/static/img/1.png"},
+ {"name": "余额宝","icon": "/static/img/2.png"},
+ {"name": "账户余额","icon": "/static/img/3.png"},
+ {"name": "交通银行信用卡(0001)""icon": "/static/img/4.png"},
+ {"name": "中国建设银行信用卡(4401)","icon": "/static/img/5.png"},
+ {"name": "网商储蓄卡(7223)","icon": "/static/img/6.png"}
+ ]
+ }
+ },
+ methods: {
+ push(){
+ // 和数组的push使用方法一致,可以push单行,也可以push多行
+ this.$refs.dragSorts.push({
+ "name": "push行",
+ "icon": "/static/img/2.png"
+ });
+ },
+ unshift(){
+ // 和数组的unshift使用方法一致,可以unshift单行,也可以unshift多行
+ this.$refs.dragSorts.unshift({
+ "name": "unshift行",
+ "icon": "/static/img/2.png"
+ });
+ },
+ splice(){
+ // 和数组的unshift使用方法一致 下标1开始删除1个并在下标1位置插入行
+ this.$refs.dragSorts.splice(1,1,{
+ "name": "splice行",
+ "icon": "/static/img/2.png"
+ });
+ },
+ onclick(e){
+ console.log('=== onclick start ===');
+ console.log("被点击行: " + JSON.stringify(e.value));
+ console.log("被点击下标: " + JSON.stringify(e.index));
+ console.log('=== onclick end ===');
+ },
+ change(e){
+ console.log('=== change start ===');
+ console.log("被拖动行: " + JSON.stringify(e.moveRow));
+ console.log('原始下标:',e.index);
+ console.log('移动到:',e.moveTo);
+ console.log('=== change end ===');
+ },
+ confirm(e){
+ console.log('=== confirm start ===');
+ console.log("被拖动行: " + JSON.stringify(e.moveRow));
+ console.log('原始下标:',e.index);
+ console.log('移动到:',e.moveTo);
+ console.log('=== confirm end ===');
+ }
+ }
+ }
+```
+
+###更多的说明请下载示例运行查看,有示例对照注释更容易明白。