感谢本文参考地址,原文解析更加清晰如有需要请移步:https://blog.csdn.net/weixin_40400844/article/details/114849253

怕原链接失效,将代码拷贝(如有侵权,请联系删除,感谢!!)

  1 <template>
2 <div>
3 <ul>
4 <li
5 class="libox"
6 v-for="(item, index) in list"
7 :key="index"
8 :id="'card' + (index + 1)"
9 >
10 <div
11 @touchstart="touchstart($event, item)"
12 @touchmove="touchMove($event, item)"
13 @touchend="touchEnd($event, item)"
14 v-show="item.name !== selectItem.name"
15 >
16 {{item.name}}
17 <svg class="icon svg-icon" aria-hidden="true">
18 <use :xlink:href="item.icon" rel="external nofollow" ></use>
19 </svg>
20 </div>
21 </li>
22 <li v-show="selectItem.name" class="selectBox" ref="selectBox">
23 {{selectItem.name}}
24 <svg class="icon svg-icon" aria-hidden="true">
25 <use :xlink:href="selectItem.icon" rel="external nofollow" ></use>
26 </svg>
27 </li>
28 </ul>
29 </div>
30 </template>
31
32 <script>
33
34 export default {
35 data() {
36 return {
37 // 列表数据
38 list: [
39 { name: '1', selected: true, icon: '#icon-mianxingbenzivg' },
40 { name: '2', selected: true, icon: '#icon-mianxingchizi' },
41 { name: '3', selected: true, icon: '#icon-mianxingdiannao' },
42 { name: '4', selected: true, icon: '#icon-mianxingdayinji' },
43 { name: '5', selected: true, icon: '#icon-mianxingdingshuqi' },
44 { name: '6', selected: true, icon: '#icon-mianxingheiban' },
45 { name: '7', selected: true, icon: '#icon-mianxinggangbi' },
46 { name: '8', selected: true, icon: '#icon-mianxingboshimao' },
47 { name: '9', selected: true, icon: '#icon-mianxingjisuanqi' },
48 { name: '10', selected: true, icon: '#icon-mianxinghuaxue' },
49 { name: '11', selected: true, icon: '#icon-mianxingqianbi' },
50 { name: '12', selected: true, icon: '#icon-mianxingshubao' },
51 { name: '13', selected: true, icon: '#icon-mianxingshuicaibi' },
52 { name: '14', selected: true, icon: '#icon-mianxingtushu' },
53 ],
54 // 选中元素内容
55 selectItem: {},
56 timeOutEvent: 0,
57 oldNodePos: {
58 x: 0,
59 y: 0,
60 },
61 oldMousePos: {
62 x: 0,
63 y: 0
64 },
65 oldIndex: 0,
66 // 长按标识
67 longClick: 0
68 };
69 },
70 watch: {
71 oldIndex(newVal) {
72 const oldIndex = this.list.findIndex(r=> r.name === this.selectItem.name);
73 this.list.splice(oldIndex, 1);
74 this.list.splice(newVal, 0, this.selectItem);
75 }
76 },
77 methods: {
78 touchstart(ev, item) {
79 this.longClick = 0;
80 const that = this;
81 const selectDom = ev.currentTarget; // div元素
82 this.timeOutEvent = setTimeout(() => {
83 that.longClick = 1;
84 that.selectItem = item;
85 // 元素初始位置
86 that.oldNodePos = {
87 x: selectDom.offsetLeft,
88 y: selectDom.offsetTop
89 };
90 // 鼠标原始位置
91 that.oldMousePos = {
92 x: ev.touches[0].pageX,
93 y: ev.touches[0].pageY
94 };
95 const lefts = that.oldMousePos.x - that.oldNodePos.x; // x轴偏移量
96 const tops = that.oldMousePos.y - that.oldNodePos.y; // y轴偏移量
97 const { pageX, pageY } = ev.touches[0]; // 手指位置
98 that.$refs.selectBox.style.left = `${pageX - lefts}px`;
99 that.$refs.selectBox.style.top = `${pageY - tops}px`;
100 }, 500);
101 },
102 touchMove(ev) {
103 clearTimeout(this.timeOutEvent);
104 const selectDom = ev.currentTarget.parentNode; // li元素
105 if (this.longClick === 1) {
106 const lefts = this.oldMousePos.x - this.oldNodePos.x; // x轴偏移量
107 const tops = this.oldMousePos.y - this.oldNodePos.y; // y轴偏移量
108 const { pageX, pageY } = ev.touches[0]; // 手指位置
109 this.$refs.selectBox.style.left = `${pageX - lefts}px`;
110 this.$refs.selectBox.style.top = `${pageY - tops}px`;
111 this.cardIndex(selectDom, pageX, pageY);
112 }
113 },
114 touchEnd() {
115 clearTimeout(this.timeOutEvent);
116 this.selectItem = {};
117 },
118 /**
119 * 计算当前移动卡片位于卡片的哪一行哪一列
120 */
121 cardIndex(selDom, moveleft, movetop) {
122 const liWid = selDom.clientWidth;
123 const liHei = selDom.clientHeight;
124 const newWidthNum = Math.ceil((moveleft / liWid)); // 哪一列
125 const newHeightNum = Math.ceil((movetop / liHei)); // 哪一行
126 const newPositionNum = (newHeightNum - 1) * 4 + newWidthNum;
127 if (this.oldIndex !== newPositionNum - 1) {
128 if (newPositionNum <= this.list.length) {
129 this.oldIndex = newPositionNum - 1;
130 } else {
131 this.oldIndex = this.list.length - 1;
132 }
133 }
134 }
135 }
136 }
137 </script>
138
139 <style lang="scss" scoped>
140 @mixin myFlexCenter{
141 display: flex;
142 justify-content: center;
143 align-items: center;
144 }
145 ul {
146 width: 100%;
147 height: 100%;
148 display: flex;
149 flex-wrap: wrap;
150 position: relative;
151 overflow: hidden;
152 .libox {
153 width: 25%;
154 height: 100px;
155 border-right: 1px dashed #cccccc;
156 border-bottom: 1px dashed #cccccc;
157 box-sizing: border-box;
158 @include myFlexCenter;
159 >div {
160 width: calc(100% - 10px);
161 height: 75px;
162 border-radius: 18px;
163 @include myFlexCenter;
164 position: relative;
165 &::after {
166 content: '';
167 width: 100%;
168 height: 100%;
169 background: rgba(255, 177, 177, 0.3);
170 position: absolute;
171 top: 0;
172 left: 0;
173 }
174 >svg {
175 width: 75px;
176 height: 75px;
177 }
178 }
179 }
180 .selectBox{
181 position: absolute;
182 width: calc(25% - 10px);
183 height: 75px;
184 border-radius: 18px;
185 >svg {
186 width: 75px;
187 height: 75px;
188 }
189 background-color: rgba(0, 0, 0, 0.1);
190 color:white;
191 @include myFlexCenter;
192 -moz-user-select:none; /*火狐*/
193 -webkit-user-select:none; /*webkit浏览器*/
194 -ms-user-select:none; /*IE10*/
195 -khtml-user-select:none; /*早期浏览器*/
196 user-select:none;
197 }
198 }
199 </style>

存在问题:只能放在卡片上方才能挪动其他卡片位置,未达到需要效果,所以进行了修改。

经实际测试后修改以下部分:

①将下方图片代码修改为(只做了减1的操作):

1 const newHeightNum = Math.ceil((movetop / liHei)) - 1; // 哪一行

②因为项目未使用scss,所以将css改成如下:

 1 <style  scoped>
2 ul {
3 width: 100%;
4 height: 100%;
5 display: flex;
6 flex-wrap: wrap;
7 position: relative;
8 overflow: hidden;
9 }
10 .libox {
11 width: 25%;
12 height: 100px;
13 box-sizing: border-box;
14 display: flex;
15 justify-content: center;
16 align-items: center;
17 }
18 .libox div {
19 width: calc(100% - 10px);
20 height: 75px;
21 border-radius: 18px;
22 display: flex;
23 justify-content: center;
24 align-items: center;
25 flex-direction: column;
26 position: relative;
27 }
28 .selectBox{
29 position: absolute;
30 width: calc(25% - 10px);
31 height: 75px;
32 border-radius: 18px;
33 background-color: inherit;
34 /* color:white; */
35 display: flex;
36 flex-direction: column;
37 justify-content: center;
38 align-items: center;
39 user-select:none;
40 }
41 </style>

效果:

VUE-使用touchstart、touchmove、touchend实现拖拽卡片列表,实现更新排序功能的更多相关文章

  1. 获取touchstart,touchmove,touchend 坐标

    简单说下如何用jQuery 和 js原生代码获取touchstart,touchmove,touchend 坐标值: jQuery 代码: $('#id').on('touchstart',funct ...

  2. 移动端的touchstart,touchmove,touchend事件中的获取当前touch位置

    前提:touchstart,touchmove,touchend这三个事件可以通过原生和jq绑定. 原生:document.querySelector("#aa").addEven ...

  3. touchstart,touchmove,touchend触摸事件的小小实践心得

    近段时间使用html5开发一个公司内部应用,而触摸事件必然是移动应用中所必须的,刚开始以为移动设备上或许也会支持鼠标事件,原来是不支持的,好在webkit内核的移动浏览器支持touch事件,并且打包成 ...

  4. 移动端touchstart,touchmove,touchend

    近段时间使用html5开发一个公司内部应用,而触摸事件必然是移动应用中所必须的,刚开始以为移动设备上或许也会支持鼠标事件,原来是不支持的,好在webkit内核的移动浏览器支持touch事件,并且打包成 ...

  5. Vue 结合 echarts 原生 html5 实现拖拽排版报表系统

    前言 不知道各位 coder 有没有碰到过许多重复的业务需求,比如排版相类似的报表,只不过是顺序稍微换了一下,就是一个新的页面,虽然基于模板思想来写的话也能减少不少代码,但是相对的不那么方便,笔者最近 ...

  6. Vue拖拽组件列表实现动态页面配置

    需求描述 最近在做一个后台系统,有一个功能产品需求是页面分为左右两部分,通过右边的组件列表来动态配置左边的页面视图,并且左边由组件拼装起来的视图,可以实现上下拖拽改变顺序,也可以删除. 根据这个需求我 ...

  7. Vue富文本编辑器(图片拖拽缩放)

    富文本编辑器(图片拖拽缩放) 需求: 根据业务要求,需要能够上传图片,且上传的图片能在移动端中占满屏幕宽度,故需要能等比缩放上传的图片,还需要能拖拽.缩放.改变图片大小.尝试多个第三方富文本编辑器,很 ...

  8. 【UWP】拖拽列表项的排序功能实现

    在一些允许用户自定义栏目顺序的app(如:凤凰新闻.网易云音乐等),我们可以方便地拖拽列表项来完成列表的重新排序,进而完成对栏目顺序的重排.这个功能很人性化,而实现起来其实很简单(甚至都不用写什么后台 ...

  9. C# 图片缩放,拖拽后保存成图片的功能

    窗体界面部分如下: 鼠标的缩放功能需要手动在 OpertaionImg.Designer.cs 文件里面添加一句代码,具体代码如下: //picturePhoto显示图片的控件 this.pictur ...

  10. touchstart,touchmove,touchend事件 写法

    jQuery写法: $('#id').on('touchstart',function(e) { var _touch = e.originalEvent.targetTouches[0]; var ...

随机推荐

  1. 学习高速PCB设计,这些走线方式你要知道! 高速射频百花潭 2022-01-21 08:53

    1.电源布局布线相关 数字电路很多时候需要的电流是不连续的,所以对一些高速器件就会产生浪涌电流. 如果电源走线很长,则由于浪涌电流的存在进而会导致高频噪声,而此高频噪声会引入到其他信号中去. 而在高速 ...

  2. QML调用C++程序

    QML调用C++程序 1. 添加C++,MouseMemory文件(.h,.cpp) 2. 在main.cpp文件添加, qmlRegisterType<MouseMemory>(&quo ...

  3. /usr/bin/install: cannot create regular file `/usr/local/jpeg6/include/jconfig.h'

    出现下列异常: /usr/bin/install -c -m 644 jconfig.h /usr/local/jpeg6/include/jconfig.h /usr/bin/install: ca ...

  4. MSDTC突然停用了,后台数据无法更新

    由于前台电脑停电突然关机,导致重启后发现MSDTC无法更新数据,重新添加了link,只能查询,更新失败,报错:无活动事务 1.修改host设置,在C:\Windows\System32\drivers ...

  5. Centos+django+uwsgi+python 环境搭建

    首先需要具备linux的基本操作. centos 6.x 版本默认安装的 python 版本为2.x 输入: [root@dev ~]# python -VPython 2.6.6 下面装一些用到的库 ...

  6. C# goto 语法

    test: Console.WriteLine("yest"); goto test;

  7. 摩托罗拉IP PBX9000配置指南

    400通话时,按数字键进行选择无效 打开IPB通信板界面,SIP终端参数--应用设置--点击RFC2833数值,默认禁用变更为101,(如有多个勾选批量,填写批量数值)--提交--保存修改 未完待续

  8. 2020ICPC上海I - Sky Garden

    思维 [I-Sky Garden_第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(上海)(重现赛)@hzy0227 (nowcoder.com)](https://codeforces.co ...

  9. idea热部署插件JRebel激活

    首先到github上去下载一个反向代理软件,我下载的是windows x64版本. https://github.com/ilanyu/ReverseProxy/releases/tag/v1.4 第 ...

  10. this.$refs 获取的值是undefined

    以下是父组件内的代码截图 如果想取子组件内的方法,参数,等可以试以下两种方法 1.在mounted内使用this.$nextTick(()=>{   }) 2.直接再undated() {} 内 ...