vue移动端touch事件,vue 拖动排序
本文主要详细介绍vue对移动触摸拖拽排序的实现。本文中的示例代码非常详细,具有一定的参考价值。感兴趣的朋友可以参考一下。
目录
功能介绍:总体要求:整体思路:简单效果展示:具体实现:1。显示:flex v-用于布局:2。触摸事件绑定:3。卡片运动:4。得到手指的位置:5。操作数组(删除或插入元素):6 .将手指留在屏幕上:7。备注:8。
功能介绍:
在移动端的开发中,我们希望实现类似支付宝应用管理页面的可拖动排序交互。
大致需求:
1.卡片按一定顺序排序,在水平范围之外的新一行显示;
2.用手指长按卡片,可以拖动控制,卡片随手指移动;
3.卡片移动到相应的位置,该位置的卡片向后或向前改变位置,当前位置变为空缺;
4.松开手指,卡片可以回到原来的位置或者新的位置显示;
整体思路:
1.卡片采用flex柔性布局,通过遍历数组可以自动显示在相应位置;
2.计时器可以用来判断手指是否长时间按下。如果手指松开,关闭计时器,等待下一次操作后再启用。
3.随手指移动的卡可以使用绝对定位控制,根据手指位置判断当前位置;
4.当位置发生变化时,控制数组增加或删除相应的元素,从而达到换位效果;
简单效果展示:
具体实现:
一、display:flex+v-for布局:
使用灵活布局实现
!-外部ul控制卡系列-
保险商实验所
li class=libox v-for=(item,ind) in list :key=ind
差异
!- div显示数组的内容-
{{item.name}}
/div
/李
/ul
data() {
返回{
列表:[
{name: 1 },//卡片内容
{姓名: 2 },
{姓名: 3 }
]
}
},
ul {
宽度:100%;
身高:100%;
显示器:flex//灵活布局
flex-wrap:缠绕;
溢出:隐藏;//超出部分隐藏,目的是防止水平滚动。libox {
宽度:25%;//这里以4列为例
高度:70px
部门{
背景色:# eee
宽度:calc(100%-10px);
高度:36px
边框半径:18px
}
}
}
二、touch事件绑定:
应用于touchstart、touchmove、touchend事件,使用定时器实现长按效果:
差异
@touchstart=touchstart($event,item)
@touchmove=touchMove($event,item)
@touchend=touchEnd($event,item)
{{item.name}}
/div
data() {
返回{
超时事件:0
};
},
方法:{
//手指触摸事件
touchstart(ev,item) {
//定时器控制长按时间,500ms后开始拖动。
this . time out event=settime out(()={
this . long click=1;
}, 500);
},
//手指在屏幕上移动
触摸移动(电动){
//如果在500ms之前移动,则不会触发长按,并清除计时器。
clear time out(this . time out event);
},
//手指离开屏幕
touchEnd() {
clear time out(this . time out event);
}
}
三、卡片移动:
给ul加一个不流通的独立li标签,改成绝对定位。通过动态修改li标签的top和left属性,可以实现跟随手指移动的效果。
保险商实验所
Li v-show= select item . name class= select box ref= select box
{{selectItem.name}}
/李
/ul
ul {
位置:相对;
//这个li标签的样式与循环li标签中的div样式一致。
//背景颜色较深,表示被手指选中。选择框{
位置:绝对;
宽度:calc(25%-10px);
高度:36px
边框半径:18px
背景色:# 6981c8
颜色:白色;
}
}
选中一张卡片,将卡片的内容赋给全局变量,判断卡片是显示还是隐藏(v-show判断,隐藏但被占用),实现选中元素位置的空置效果:
手指位置通过触摸移动获得:
差异
@touchstart=touchstart($event,item)
@touchmove=touchMove($event,item)
@touchend=touchEnd($event,item)
@ click= listlichandler(item)
v-show=item.name!==selectItem.name
{{item.name}}
/div
touchstart(ev,item) {
这个。超时事件=设置超时(()={
这个。长点击=1;
this.selectItem=item//将卡片内容赋值给全局变量
const selectDom=ev.target//李元素
//元素初始位置
this.oldNodePos={
x: selectDom.offsetLeft,
y: selectDom.offsetTop
};
//鼠标原始位置
this.oldMousePos={
x: ev.touches[0].pageX,
y: ev.touches[0].佩吉
};
const lefts=this。oldmousepos。这个。oldnodepos。x;//x轴偏移量
const tops=this。oldmousepos。这个。oldnodepos。y;//y轴偏移量
const { pageX,pageY }=ev。触摸[0];//手指位置
这个参考文献。选择框。风格。left=` $ { pageX-lefts } px `;
这个参考文献。选择框。风格。top=` $ { pageY-tops } px `;
}, 500);
},
触摸移动(电动){
清除超时(这。超时事件);
//this.longClick===1判断是否长按
if (this.longClick===1) {
const selectDom=ev。目标。父节点;//李元素
const lefts=this。oldmousepos。这个。oldnodepos。x;//x轴偏移量
const tops=this。oldmousepos。这个。oldnodepos。y;//y轴偏移量
const { pageX,pageY }=ev。触摸[0];//手指位置
这个参考文献。选择框。风格。left=` $ { pageX-lefts } px `;
这个参考文献。选择框。风格。top=` $ { pageY-tops } px `;
}
}
四、获取手指所在位置:
卡索引(很少,向左移动,向上移动){
const liWid=selDom.clientWidth//李宽度
const liHei=很少。客户身高;//李高度
const newWidNum=math。ceil((左移/liWid));//手指所在列
const newHeiNum=math。ceil((移顶/立黑));//手指所在行
const newPosNum=(newHeiNum-1)* 4 newWidNum;//手指所在位置
//判断是否是新位置并且没有超出列表数量范围
if (this.oldIndex!==newPosNum
newPosNum=this.list.length) {
//将新的位置赋值给全局变量奥尔德指数
this.oldIndex=newPosNum
}
}
五、操作数组(删除或插入元素):
监听奥尔德指数的值,若发生改变则执行操作数组函数
观察:{
oldIndex(newVal) {
const旧索引=this。列表。的索引。selectitem);
this.list.splice(oldIndex,1);
this.list.splice(newVal - 1,0,this。selectitem);
}
},
六、手指离开屏幕:
手指离开屏幕,清空选中的元素选择一个项目,跟随手指移动的卡片(李。选择框)自动隐藏,在循环中隐藏的卡片(李)则会显示,实现换位效果。
touchEnd() {
清除超时(这。超时事件);
这个。selectitem={ };
}
七、备注:
上面的代码是基于差异容器内只有文字没有其他数字正射影像图元素实现,后发现若差异中存在数字正射影像图元素例如svg,则【$事件】选中的值会变成其子元素,且拖拽排序出现问题,希望知道原因的小伙伴可以评论或私信告诉我一下,非常感谢。
粗暴的解决方式:
差异容器增加在.之后蒙版,可设置为透明色:
差异
位置:相对;
*在{
内容:"";
宽度:100%;
身高:100%;
背景:rgba(255,177,177,0.3);//背景色
位置:绝对;
top:0;
左:0;
}
}
八、完整代码:
模板
差异
保险商实验所
里
“libox”
列表中的v-for=(项目,索引
:key=index
:id= 卡片(索引1)
差异
@touchstart=touchstart($event,item)
@touchmove=touchMove($event,item)
@touchend=touchEnd($event,item)
v-show=item.name!==selectItem.name
{{item.name}}
SVG class= icon SVG-icon aria-hidden= true
use:xlink:href= item。图标 rel=外部无跟随/使用
/svg
/div
/李
Li v-show=选择项目。name class=选择框 ref=选择框
{{selectItem.name}}
SVG class= icon SVG-icon aria-hidden= true
用法:xlink:href=选择项目。图标 rel=外部无跟随/使用
/svg
/李
/ul
/div
/模板
脚本
导出默认值{
data() {
返回{
//列表数据
列表:[
{名称: 1 ,已选择:真,图标: #icon-mianxingbenzivg },
{ name: 2 ,selected: true,icon: #icon-mianxingchizi },
{ name: 3 ,selected: true,icon: #icon-mianxingdiannao },
{ name: 4 ,selected: true,icon: #icon-mianxingdayinji },
{ name: 5 ,selected: true,icon: # icon-mianxingdingshuqi },
{ name: 6 ,selected: true,icon: #icon-mianxingheiban },
{ name: 7 ,selected: true,icon: # icon-mianxingganbi },
{ name: 8 ,selected: true,icon: #icon-mianxingboshimao },
{ name: 9 ,selected: true,icon: #icon-mianxingjisuanqi },
{ name: 10 ,selected: true,icon: #icon-mianxinghuaxue },
{ name: 11 ,selected: true,icon: #icon-mianxingqianbi },
{ name: 12 ,selected: true,icon: #icon-mianxingshubao },
{ name: 13 ,selected: true,icon: # icon-mianxingshuicaibi },
{ name: 14 ,selected: true,icon: #icon-mianxingtushu },
],
//选中元素内容
选择项目:{},
超时事件:0,
旧节点位置:{
x: 0,
y: 0,
},
旧鼠标位置:{
x: 0,
y: 0
},
ol指数:0,
//长按标识
长时间点击:0
};
},
观察:{
oldIndex(newVal) {
const旧索引=this。列表。查找索引(r=r . name===this。选择项目。姓名);
this.list.splice(oldIndex,1);
this.list.splice(newVal,0,this。selectitem);
}
},
方法:{
touchstart(ev,item) {
这个。长点击=0;
const那个=这个
const selectDom=ev。当前目标;//div元素
这个。超时事件=设置超时(()={
那个。长点击=1;
that.selectItem=item
//元素初始位置
that.oldNodePos={
x: selectDom.offsetLeft,
y: selectDom.offsetTop
};
//鼠标原始位置
that.oldMousePos={
x: ev.touches[0].pageX,
y: ev.touches[0].佩吉
};
const lefts=that。oldmousepos。x-那个。oldnodepos。x;//x轴偏移量
const tops=that。oldmousepos。那个。oldnodepos。y;//y轴偏移量
const { pageX,pageY }=ev。触摸[0];//手指位置
那个参考文献。选择框。风格。left=` $ { pageX-lefts } px `;
那个参考文献。选择框。风格。top=` $ { pageY-tops } px `;
}, 500);
},
触摸移动(电动){
清除超时(这。超时事件);
const selectDom=ev。当前目标。父节点;//李元素
if (this.longClick===1) {
const lefts=this。oldmousepos。这个。oldnodepos。x;//x轴偏移量
const tops=this。oldmousepos。这个。oldnodepos。y;//y轴偏移量
const { pageX,pageY }=ev。触摸[0];//手指位置
这个参考文献。选择框。风格。left=` $ { pageX-lefts } px `;
这个参考文献。选择框。风格。top=` $ { pageY-tops } px `;
这个。汽车索引(选择DOM、pageX、pageY);
}
},
touchEnd() {
清除超时(这。超时事件);
这个。selectitem={ };
},
/**
* 计算当前移动卡片位于卡片的哪一行哪一列
*/
卡索引(很少,向左移动,向上移动){
const liWid=selDom.clientWidth
const liHei=很少。客户身高;
const newWidthNum=math。ceil((左移/liWid));//哪一列
const newHeightNum=math。ceil((移顶/立黑));//哪一行
const newPositionNum=(newHeightNum-1)* 4 newWidthNum;
if (this.oldIndex!==newPositionNum - 1) {
if(newPositionNum=this。列表。长度){
这个。old index=newPositionNum-1;
}否则{
这个。老指数=这个。列表。长度-1;
}
}
}
}
}
/脚本
样式lang=scss 范围
@mixin myFlexCenter{
显示器:flex
对齐-内容:居中;
对齐-项目:居中;
}
ul {
宽度:100%;
身高:100%;
显示器:flex
柔性包装:缠绕;
位置:相对;
溢出:隐藏;libox {
宽度:25%;
高度:100像素
右边框:1px虚线# cccccc
底部边框:1px虚线# cccccc
框大小:边框-框;
@包含myFlexCenter
部门{
宽度:calc(100%-10px);
身高:75像素
边框半径:18px
@包含myFlexCenter
位置:相对;
*在{
内容:"";
宽度:100%;
身高:100%;
背景:rgba(255,177,177,0.3);
位置:绝对;
top:0;
左:0;
}
svg {
宽度:75像素
身高:75像素
}
}
}。选择框{
位置:绝对;
宽度:calc(25%-10px);
身高:75像素
边框半径:18px
svg {
宽度:75像素
身高:75像素
}
背景色:rgba(0,0,0,0.1);
颜色:白色;
@包含myFlexCenter
-moz-用户-选择:无;/*火狐*/
-网络工具包-用户选择:无;/*webkit浏览器*/
-ms-用户-选择:无;/*IE10*/
-khtml-用户选择:无;/*早期浏览器*/
用户选择:无;
}
}
/风格
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。