vue移动端拖拽悬浮按钮
iatkotworld 人气:0功能介绍:
在移动端开发中,实现悬浮按钮在侧边显示,为不遮挡页面内容,允许手指拖拽换位。
大致需求:
1、按钮在页面侧边悬浮显示;
2、手指长按按钮,按钮改变样式,允许拖拽改变位置;
3、按钮移动结束,手指松开,计算距离左右两侧距离并自动移动至侧边显示;
4、移动至侧边后,按钮根据具体左右两次位置判断改变现实样式;
整体思路:
1、按钮实行position:fixed布局,在页面两侧最上层悬浮显示;
2、手指长按可使用定时器来判断,若手指松开,则关闭定时器,等待下次操作再启用;
3、跟随手指移动计算按钮与页面两侧的距离,判断手指松开时停留的位置;
简单效果展示:
具体实现:
一、position:fixed布局:
使用定位实现
<!-- 外层ul控制卡片范围 --> <div> <div class="floatBtn" :class="[{moveBtn: longClick}, `${btnType}Btn`]"> <span>悬浮按钮</span> </div> </div>
<style lang="scss" scoped> @mixin notSelect{ -moz-user-select:none; /*火狐*/ -webkit-user-select:none; /*webkit浏览器*/ -ms-user-select:none; /*IE10*/ -khtml-user-select:none; /*早期浏览器*/ user-select:none; } @mixin not-touch { -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } .floatBtn { @include notSelect; @include not-touch(); position: fixed; z-index: 1; overflow: hidden; width: 100px; left: calc(100% - 100px); top: calc(100% - 100px); color: #E0933A; background: #FCEBD0; font-size: 14px; height: 36px; line-height: 36px; text-align: center; box-sizing: border-box; display: flex; justify-content: center; align-items: center; padding: 10px; &.rightBtn { border-radius: 20px 0 0 20px; } &.leftBtn { border-radius: 0 20px 20px 0; } &.moveBtn { border-radius: 20px; } } </style>
二、touch事件绑定:
应用到touchstart,touchmove,touchend事件,使用定时器实现长按效果:
<div class="floatBtn" :class="[{moveBtn: longClick}, `${btnType}Btn`]" @touchstart="touchstart($event)" @touchmove="touchMove($event)" @touchend="touchEnd($event)" > <span>悬浮按钮</span> </div>
<script> export default { data() { return { timeOutEvent: 0, longClick: 0, // 手指原始位置 oldMousePos: {}, // 元素原始位置 oldNodePos: {}, btnType: 'right' }; }, touchstart(ev) { // 定时器控制长按时间,超过500毫秒开始进行拖拽 this.timeOutEvent = setTimeout(() => { this.longClick = 1; }, 500); const selectDom = ev.currentTarget; const { pageX, pageY } = ev.touches[0]; // 手指位置 const { offsetLeft, offsetTop } = selectDom; // 元素位置 // 手指原始位置 this.oldMousePos = { x: pageX, y: pageY }; // 元素原始位置 this.oldNodePos = { x: offsetLeft, y: offsetTop }; selectDom.style.left = `${offsetLeft}px`; selectDom.style.top = `${offsetTop}px`; }, touchMove(ev) { // 未达到500毫秒就移动则不触发长按,清空定时器 clearTimeout(this.timeOutEvent); if (this.longClick === 1) { const selectDom = ev.currentTarget; // x轴偏移量 const lefts = this.oldMousePos.x - this.oldNodePos.x; // y轴偏移量 const tops = this.oldMousePos.y - this.oldNodePos.y; const { 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 = 0; const selectDom = ev.currentTarget; const {clientWidth, clientHeight} = document.body; const {offsetLeft, offsetTop} = selectDom; selectDom.style.left = (offsetLeft + 50) > (clientWidth / 2) ? 'calc(100% - 100px)' : 0; if (offsetTop < 90) { selectDom.style.top = '90px'; } else if (offsetTop + 36 > clientHeight) { selectDom.style.top = `${clientHeight - 36}px`; } this.btnType = (offsetLeft + 50) > (clientWidth / 2) ? 'right' : 'left'; } }, }; </script>
三、页面引入:
单个页面引入
<template> <floatBtn/> </template>
<script> import floatBtn from './floatBtn'; export default { components: { floatBtn }, }; </script>
加载全部内容