unnapp 小程序长按拖动排序
一、单列排序
1.组件 sort.vue
{{ item.name }} export default { props: { //列表 list: { type: Array, default: [], }, // 列表每行高度 lineHeight: { type: Number, default: 80, }, }, data() { return { listArray: [], // 所有元素定位位置 listPosition: [], // 记录拖动前元素定位位置 initListPosition: [], // 记录当前拖动元素的下标 curretnItemIndex: -1, // 记录拖动前的位置 recordPosition: { y: 0, }, // 记录拖动前的定位位置 recordCurrentPositionItem: { top: 0, }, // 是否正在交换位置 isChange: false, isDrag: false, isTouchMove: true, windowHeight: 0, }; }, created() { this.init(); let windowHeight = uni.getSystemInfoSync().windowHeight; // 状态栏高度 let statusBarHeight = uni.getSystemInfoSync().statusBarHeight; const custom = wx.getMenuButtonBoundingClientRect(); let navigationBarHeight = custom.height + (custom.top - statusBarHeight) * 2; let navHeight = navigationBarHeight + statusBarHeight; this.windowHeight = windowHeight - navHeight; }, methods: { init() { this.listArray = [...this.list]; const query = uni.createSelectorQuery().in(this); query.selectAll(".listItem").fields( { rect: true, size: true, }, (data) => { data.forEach((item, index) => { this.listPosition.push({ height: item.height, top: (item.height + 15) * index, }); }); this.initListPosition = [...this.listPosition]; } ); query.exec(); //执行所有请求 }, longtap(event, index) { this.isTouchMove = false; this.isDrag = true; const { pageY } = event.touches[0]; // 记录当前拖动元素的下标 this.curretnItemIndex = index; // 记录拖动前的位置 this.recordPosition = { y: pageY, }; // 记录拖动前的定位位置 this.recordCurrentPositionItem = this.listPosition[index]; }, onTouchstart(event, index) { // const { pageY } = event.touches[0]; // // 记录当前拖动元素的下标 // this.curretnItemIndex = index; // // 记录拖动前的位置 // this.recordPosition = { // y: pageY, // }; // // 记录拖动前的定位位置 // this.recordCurrentPositionItem = this.listPosition[index]; }, onTouchmove(event) { if (!this.isDrag) { return; } const { pageY } = event.touches[0]; // 获取移动的差 this.$set(this.listPosition, this.curretnItemIndex, { top: this.listPosition[this.curretnItemIndex].top + (pageY - this.recordPosition.y), }); // 记录位置 this.recordPosition = { y: pageY, }; // 向下 if ( this.listPosition[this.curretnItemIndex].top >= this.listPosition[this.curretnItemIndex + 1]?.top - this.initListPosition[0].height / 2 ) { if (this.isChange) return; this.isChange = true; let temp = this.listArray[this.curretnItemIndex]; console.log(temp); this.listArray[this.curretnItemIndex] = this.listArray[this.curretnItemIndex + 1]; this.listArray[this.curretnItemIndex + 1] = temp; this.listPosition[this.curretnItemIndex + 1] = this.listPosition[this.curretnItemIndex]; this.listPosition[this.curretnItemIndex] = this.recordCurrentPositionItem; this.curretnItemIndex = this.curretnItemIndex + 1; this.recordCurrentPositionItem = this.initListPosition[this.curretnItemIndex]; this.isChange = false; } // 向上 if ( this.listPosition[this.curretnItemIndex].top import sort from "./components/sort.vue"; export default { components: { sort, }, data() { return { sortList: [{ name: "1" }, { name: "2" }, { name: "3" }], lineHeight: 108, }; }, methods: { changeSort(e) { console.log(e, "修改后的新排序"); }, }, };
二、多列排序
1.sort.vue
{{ item[label] }} export default { data() { return { cloneList: [], //用来展示的数据列表 cacheList: [], //用来在点击“编辑”文字按钮的时候,将当前list的数据缓存,以便在取消的时候用到 positionList: [], //用来存储xy坐标定位的列表 columnWidth: 0, //列宽,单位px rowNum: 1, //行数 boxHeight: 10, //可拖动区域的高度,单位px windowWidth: 750, //系统获取到的窗口宽度,单位px curTouchPostionIndex: 0, //当前操作的移动块在positionList队列里的索引 xMoveUnit: 0, //沿x轴移动时的单位距离,单位px yMoveUnit: 0, //沿y轴移动时的单位距离,单位px clearT: "", //onChange事件中使用 clearF: "", //点击“完成”文字按钮时使用 isEdit: false, //是否在编辑状态 windowHeight: 0, }; }, props: { //props里属性Number的单位都为rpx,在操作的时候需要用rpxTopx进行转换 list: { type: Array, default() { return []; }, }, label: { //list队列中的对象中要用来展示的key名 type: String, default: "name", }, rowHeight: { //行高,单位rpx type: Number, default: 60, }, rowSpace: { //行间距,单位rpx type: Number, default: 15, }, columnSpace: { //列间距,单位rpx type: Number, default: 15, }, columnNum: { //列数 type: Number, default: 4, }, zIndex: { //可移动项的默认z-index type: Number, default: 1, }, }, created() { this.windowWidth = uni.getSystemInfoSync().windowWidth; let windowHeight = uni.getSystemInfoSync().windowHeight; // 状态栏高度 let statusBarHeight = uni.getSystemInfoSync().statusBarHeight; const custom = wx.getMenuButtonBoundingClientRect(); let navigationBarHeight = custom.height + (custom.top - statusBarHeight) * 2; let navHeight = navigationBarHeight + statusBarHeight; this.windowHeight = windowHeight - navHeight; }, mounted() { const query = uni.createSelectorQuery().in(this); query .select("#dragSortArea") .boundingClientRect((data) => { this.columnWidth = (data.width - (this.columnNum - 1) * this.rpxTopx(this.columnSpace)) / this.columnNum; this.handleListData(); this.toggleEdit("edit"); }) .exec(); }, methods: { /* 切换编辑状态 * [type] String 参数状态 */ toggleEdit(type) { if (type == "finish") { //点击“完成” this.isEdit = false; this.$emit("newDishList", this.getSortedIdArr()); } else if (type == "cancel") { //点击“取消”,将数据恢复到最近一次编辑时的状态 this.isEdit = false; this.updateList(this.cacheList); } else if (type == "edit") { //点击“编辑” this.isEdit = true; this.cacheList = JSON.parse(JSON.stringify(this.list)); } }, /* 更新父组件的list,并重新渲染布局 * 有改变数组长度的操作内才需要调用此方法进行重新渲染布局进行更新, * 否则直接$emit('update:list')进行更新,无须调用此方法 */ updateList(arr) { this.$emit("update:list", arr); setTimeout(() => { this.handleListData(); }, 100); }, /* 处理源数据列表,生成展示用的cloneList和positionList布局位置信息 */ handleListData() { this.cloneList = JSON.parse(JSON.stringify(this.list)); this.positionList = []; this.rowNum = Math.ceil(this.cloneList.length / this.columnNum); this.boxHeight = this.rowNum * this.rpxTopx(this.rowHeight) + (this.rowNum - 1) * this.rpxTopx(this.rowSpace); this.xMoveUnit = this.columnWidth + this.rpxTopx(this.columnSpace); this.yMoveUnit = this.rpxTopx(this.rowHeight) + this.rpxTopx(this.rowSpace); this.cloneList.forEach((item, index) => { item.sortNumber = index; item.zIndex = this.zIndex; item.x = this.xMoveUnit * (index % this.columnNum); //单位px item.y = Math.floor(index / this.columnNum) * this.yMoveUnit; //单位px this.positionList.push({ x: item.x, y: item.y, id: item.id, }); }); }, /* 找到id在位置队列positionList里对应的索引 */ findPositionIndex(id) { var resultIndex = 0; for (var i = 0, len = this.positionList.length; i { if (item.id == obj.id) { item.zIndex = item.zIndex + 50; item.isTouched = true; } else { item.zIndex = this.zIndex + index + 1; item.isTouched = false; } }); this.$set(this.cloneList, 0, this.cloneList[0]); }, /* 触摸结束 */ onTouchend(obj) { if (!this.isEdit) { return false; } this.startSort(this.curTouchPostionIndex, "onTouchend"); //再次调用并传参数‘onTouchend’,使拖动后且没有找到目标位置的滑块归位 }, /* 移动过程中触发的事件(所有移动块只要一有移动都会触发) */ onChange(e, obj) { if (!this.isEdit) { return false; } var theX = e.detail.x, theY = e.detail.y, curCenterX = theX + this.columnWidth / 2, curCenterY = theY + this.rpxTopx(this.rowHeight) / 2; if (e.detail.source === "touch") { //表示由“拖动”触发 var targetIndex = this.findTargetPostionIndex({ curCenterX, curCenterY, }); clearTimeout(this.clearT); this.clearT = setTimeout(() => { this.$nextTick(() => { this.startSort(targetIndex); //根据targetIndex将队列进行排序 }); }, 100); } }, longtap() { this.isEdit = true; }, /* 根据targetIndex将cloneList进行排序 * [targetIndex] Number 当前拖动的模块拖动到positionList队列里的目标位置的索引 * [type] String 值为onTouchend时,再次调用set方法 */ startSort(targetIndex, type) { var curTouchId = this.positionList[this.curTouchPostionIndex].id; if (this.curTouchPostionIndex = this.curTouchPostionIndex && i = targetIndex && i { item.x += 0.001; item.y += 0.001; }); if (type == "onTouchend") { this.$set(this.cloneList, 0, this.cloneList[0]); } this.$nextTick(() => { this.cloneList.forEach((item) => { for (var i = 0, len = this.positionList.length; i { for (var i = 0, len = this.list.length; i item.id); }, /* 找出拖动到positionList队列里的哪个目标索引 * [curObj.curCenterX], Number 当前拖动的模块的中心点x轴坐标 * [curObj.curCenterY], Number 当前拖动的模块的中心点y轴坐标 * return 返回拖动到的目标索引 */ findTargetPostionIndex(curObj) { var resultIndex = this.curTouchPostionIndex; for (var i = 0, len = this.positionList.length; i = item.x && curObj.curCenterX = item.y && curObj.curCenterY
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。