vue实现移动端悬浮可拖拽按钮

需求:

  1. 按钮在页面侧边悬浮显示;
  2. 点击按钮可展开多个快捷方式按钮,从下向上展开。
  3. 长按按钮,则允许拖拽来改变按钮位置,按钮为非展开状态;
  4. 按钮移动结束,手指松开,计算距离左右两侧距离并自动移动至侧边显示;
  5. 移动至侧边后,根据具体左右两次位置判断改变展开样式;
  6. 处理移动到非可视区域时特殊情况。

效果展示:
在这里插入图片描述

具体实现:

<template><div class="shortcut" @touchstart="touchstart($event)" @touchmove="touchMove($event)" @touchend="touchEnd($event)" v-if="isMobile"><div class="shortcut__container"><transition name="fade"><div class="shadow" v-if="showPopover" @click.stop="showPopover = false"></div></transition><transition name="sub-fade"><div :class="['shortcut__list', `${type}`]" v-if="showPopover"><div class="shortcut__list_item"><div class="icon-box"><img src="@/images/common/ic_question.png" alt=""></div>投资理财</div><div class="shortcut__list_item"><div class="icon-box"><img src="@/images/common/ic_question.png" alt=""></div>我的资产</div><div class="shortcut__list_item"><div class="icon-box"><img src="@/images/common/ic_question.png" alt=""></div>咨询我们</div></div></transition><div class="shortcut__btn" :class="{ anim: showPopover }" @click.stop="handleBtn()">+</div></div></div>
</template><script>
const TIME = 50
export default {data () {return {isMobile: /Mobi|Android|iPhone/i.test(navigator.userAgent),showPopover: false,timeOutEvent: 0,longClick: 0,// 手指原始位置oldMousePos: {},// 元素原始位置oldNodePos: {},type: 'right',}},methods: {touchstart (ev) {// 定时器控制长按时间,超过{TIME}毫秒开始进行拖拽this.timeOutEvent = setTimeout(() => {this.longClick = 1}, TIME)const selectDom = ev.currentTargetconst { pageX, pageY } = ev.touches[0] // 手指位置const { offsetLeft, offsetTop } = selectDom // 元素位置// 手指原始位置this.oldMousePos = {x: pageX,y: pageY,}// 元素原始位置this.oldNodePos = {x: offsetLeft,y: offsetTop,}this.handleMoving()selectDom.style.left = `${offsetLeft}px`selectDom.style.top = `${offsetTop}px`},touchMove (ev) {// 未达到{TIME}毫秒就移动则不触发长按,清空定时器clearTimeout(this.timeOutEvent)if (this.longClick === 1) {this.handleMoving()this.showPopover = falseconst selectDom = ev.currentTarget// x轴偏移量const lefts = this.oldMousePos.x - this.oldNodePos.x// y轴偏移量const tops = this.oldMousePos.y - this.oldNodePos.yconst { pageX, pageY } = ev.touches[0] // 手指位置selectDom.style.left = `${pageX - lefts}px`selectDom.style.top = `${pageY - tops}px`}},touchEnd (ev) {// 清空定时器clearTimeout(this.timeOutEvent)if (this.longClick === 1) {this.longClick = 0const selectDom = ev.currentTargetconst { innerWidth, innerHeight } = windowconst { offsetLeft, offsetTop } = selectDomselectDom.style.left = offsetLeft + 50 > innerWidth / 2 ? 'calc(100% - 55px)' : '15px'if (offsetTop < 150) {selectDom.style.top = '150px'} else if (offsetTop + 150 > innerHeight) {selectDom.style.top = `${innerHeight - 150}px`}this.type = offsetLeft + 50 > innerWidth / 2 ? 'right' : 'left'setTimeout(() => {document.body.style.overflow = 'auto'document.body.style.userSelect = 'auto'}, 1000)}},handleMoving () {// 禁止body滚动document.body.style.overflow = 'hidden'// 禁止body文本选中document.body.style.userSelect = 'none'},handleBtn () {this.showPopover = !this.showPopover}},
}
</script><style scoped lang="less">
.icon-box {background: #fff;width: .8rem;height: .8rem;border-radius: 50%;display: flex;align-items: center;justify-content: center;
}.shortcut {position: fixed;z-index: 9999;left: calc(100% - 55px);top: calc(100% - 150px);user-select: none;&__container {position: relative;}&__list {position: absolute;bottom: .8rem;z-index: 8;&_item {color: #fff;display: flex;flex-direction: row;align-items: center;white-space: nowrap;margin-bottom: .15rem;.icon-box {margin: 0 .1rem 0 0;img {width: 0.36rem;height: 0.36rem;}}}&.left {left: 0;}&.right {right: 0;.shortcut__list_item {flex-direction: row-reverse;.icon-box {margin: 0 0 0 .1rem;}}}}&__btn {background: #fff;width: .8rem;height: .8rem;border-radius: 50%;text-align: center;line-height: .7rem;color: #3356D9;font-size: .5rem;position: relative;z-index: 8;border: 1px solid #3356D9;transition: all .3s linear;&.anim {transform: rotate(135deg);}}
}
.shadow {width: 100%;max-width: 1024px;position: fixed;top: 0;left: 0;right: 0;bottom: 0;background-color: rgba(0, 0, 0, 0.5);z-index: 1;margin: 0 auto;
}
.sub-fade-leave-active,.sub-fade-enter-active {transition: max-height 0.3s linear;
}
.sub-fade-enter,.sub-fade-leave-to {max-height: 0;overflow: hidden;
}
.sub-fade-enter-to,.sub-fade-leave {max-height: 2.56rem;overflow: hidden;
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/142650.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

python回文素数

这能有1和本身整除的整数叫素数&#xff1b;如一个素数从左向右和从右向左是相同的数&#xff0c;则该素数为回文素数。编程求出2-1000内的所有回文素数。 源代码&#xff1a; def sushu(n): for i in range(2,n//21): if n%i 0: return False r…

1.算法——数据结构学习

算法是解决特定问题求解步骤的描述。 从1加到100的结果 # include <stdio.h> int main(){ int i, sum 0, n 100; // 执行1次for(i 1; i < n; i){ // 执行n 1次sum sum i; // 执行n次} printf("%d", sum); // 执行1次return 0; }高斯求和…

复杂SQL解析

文章目录 背景表SQL关键字分析具体Sql注意点补充&#xff1a;select的字段&#xff0c;也可以带有计算逻辑 背景表 1、sale_log as result: 主表&#xff0c;大部分字段都是取自这个表 2、sale_num as sale&#xff1a;需要从这个表获取真实销量sale_num字段 3、schedule as…

京东获得JD商品详情 API 返回值说明

京东商品详情API接口可以获得JD商品详情原数据。 这个API接口有两种参数&#xff0c;公共参数和请求参数。 公共参数有以下几个&#xff1a; apikey&#xff1a;这是您自己的API密钥&#xff0c;可以在京东开发者中心获取。 请求参数有以下几个&#xff1a; num_iid&#…

怎样设置每个月的10号提醒?可每月触发提醒的软件是哪个

在每个月当中总是会有一些需要按时提醒的事情&#xff0c;如每月10号提醒换房贷、每月10号提醒还信用卡、每月10号提醒续交车贷等&#xff0c;当然每月像这样的事情是比较多的&#xff0c;怎样设置每个月的10号提醒自己呢&#xff1f; 可以用来设定定时提醒的工具是比较多的&a…

缓冲区溢出漏洞分析

一、实验目的 熟悉软件安全需求分析方法&#xff0c;掌握软件安全分析技术。 二、实验软硬件要求 1、操作系统&#xff1a;windows 7/8/10等 2、开发环境&#xff1a;VS 6.0&#xff08;C&#xff09;、OllyDbg 三、实验预习 《软件安全技术》教材第3章 四、实验内容&#…

paddle2.3-基于联邦学习实现FedAVg算法

目录 1. 联邦学习介绍 2. 实验流程 3. 数据加载 4. 模型构建 5. 数据采样函数 6. 模型训练 1. 联邦学习介绍 联邦学习是一种分布式机器学习方法&#xff0c;中心节点为server&#xff08;服务器&#xff09;&#xff0c;各分支节点为本地的client&#xff08;设备&#…

【操作系统笔记四】高速缓存

CPU 高速缓存 存储器的分层结构&#xff1a; 问题&#xff1a;为什么这种存储器层次结构行之有效呢&#xff1f; 衡量 CPU 性能的两个指标&#xff1a; 响应时间&#xff08;或执行时间&#xff09;&#xff1a;执行一条指令平均时间 吞吐量&#xff0c;就是 1 秒内 CPU 可以…

Kafka的消息存储机制

前面咱们简单讲了K啊开发入门相关的概念、架构、特点以及安装启动。 今天咱们来说一下它的消息存储机制。 前言&#xff1a; Kafka通过将消息持久化到磁盘上的日志文件来实现高吞吐量的消息传递。 这种存储机制使得Kafka能够处理大量的消息&#xff0c;并保证消息的可靠性。 1…

Vue+ElementUI实现动态树和表格数据的查询

目录 前言 一、动态树的实现 1.数据表 2.编写后端controller层 3.定义前端发送请求路径 4.前端左侧动态树的编写 4.1.发送请求获取数据 4.2.遍历左侧菜单 5.实现左侧菜单点击展示右边内容 5.1.定义组件 5.2.定义组件与路由的对应关系 5.3.渲染组件内容 5.4.通过动态…

OpenAI 更新 ChatGPT:支持图片和语音输入【附点评】

一、消息正文 9月25日消息,近日OpenAI宣布其对话AI系统ChatGPT进行升级,添加了语音输入和图像处理两个新功能。据OpenAI透露,这些新功能将在未来两周内面向ChatGPT Plus付费用户推出,免费用户也将很快可以使用这些新功能。这标志着ChatGPT继续朝着多模态交互的方向发展,为用户提…

Cpp/Qt-day040920Qt

目录 时钟 头文件&#xff1a;Widget.h: 源文件:Widget.c: 效果图&#xff1a; 思维导图 时钟 头文件&#xff1a;Widget.h: #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QPaintEvent> #include <QPainter> #include <QTime>…

无需求文档,保障测试质量的可行性做法

001 没有需求文档3种可能情况 &#xff1a; 1、公司都没产品经理&#xff0c;开发人员的意识不足&#xff0c;收到的客户需求&#xff0c;直接开干&#xff08;写需求文档 &#xff1f;不可能的&#xff09; 。 2、项目进度紧张&#xff0c;需求变动大&#xff0c;一直在变&…

如何在.NET电子表格应用程序中创建流程图

前言 流程图是一种常用的图形化工具&#xff0c;用于展示过程中事件、决策和操作的顺序和关系。它通过使用不同形状的图标和箭头线条&#xff0c;将任务和步骤按照特定的顺序连接起来&#xff0c;以便清晰地表示一个过程的执行流程。 在企业环境中&#xff0c;高管和经理利用…

【C语言】模拟实现内存函数

本篇文章目录 相关文章1. 模拟 memcpy 内存拷贝2. 模拟 memmove 内存移动 相关文章 【C语言】数据在内存中是以什么顺序存储的&#xff1f;【C语言】整数在内存中如何存储&#xff1f;又是如何进行计算使用的&#xff1f;【C语言】利用void*进行泛型编程【C语言】4.指针类型部…

关于MATLAB R2022b中MATLAB function没有edit data选项的解决办法

问题描述 在MATLAB 2022b的simulink中双击MATLAB function&#xff0c;出来的是这个界面&#xff0c;而不是跳转到MATLAB的编辑窗口。因此就找不到edit data选项&#xff0c;没法完成新建data store memory 全局变量。 解决办法&#xff1a; 点击 编辑数据 按钮 在弹出的窗…

孟晚舟最新发声!华为吹响人工智能的号角,发布“全面智能化”战略部署

原创 | 文 BFT机器人 1、华为孟晚舟新发声&#xff0c;华为发布“全面智能化”战略 上周三&#xff08;9月30号&#xff09;上午&#xff0c;华为全联接大会2023正式在上海举行&#xff0c;作为华为副董事长、轮值董事长、CFO的孟晚舟代表华为再次发声&#xff01;在演讲上&am…

力扣刷题-链表-链表相交

02.07. 链表相交 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 题目数据 保证 整个链式结构中不存在环。 注意&#xff0c;函数返…

基于springboot+vue的大学生科创项目在线管理系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

海大校园学习《乡村振兴战略下传统村落文化旅游设计》许少辉八一新著

海大校园学习《乡村振兴战略下传统村落文化旅游设计》许少辉八一新著