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

 更新时间:2022年07月14日 10:40:28   作者:iatkotworld  
这篇文章主要为大家详细介绍了vue实现移动端拖拽悬浮按钮,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了vue实现移动端拖拽悬浮按钮的具体代码,供大家参考,具体内容如下

功能介绍:

在移动端开发中,实现悬浮按钮在侧边显示,为不遮挡页面内容,允许手指拖拽换位。

大致需求:

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>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • Vue 事件处理操作实例详解

    Vue 事件处理操作实例详解

    这篇文章主要介绍了Vue 事件处理操作,结合实例形式较为详细的分析了vue.js事件处理相关的事件监听、处理、修饰符等相关概念、用法及操作注意事项,需要的朋友可以参考下
    2019-03-03
  • vue使用v-model进行跨组件绑定的基本实现方法

    vue使用v-model进行跨组件绑定的基本实现方法

    这篇文章主要给大家介绍了关于vue使用v-model进行跨组件绑定的基本实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • vue项目中使用lib-flexible解决移动端适配的问题解决

    vue项目中使用lib-flexible解决移动端适配的问题解决

    这篇文章主要介绍了vue项目中使用lib-flexible解决移动端适配的问题解决,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-08-08
  • Vue进阶之CodeMirror的应用小结

    Vue进阶之CodeMirror的应用小结

    CodeMirror支持在线编辑代码,风格包括js, java, php, c++等等100多种语言,下面这篇文章主要来和大家讲讲CodeMirror的应用,感兴趣的可以了解一下
    2023-06-06
  • 超详细动手搭建一个VuePress 站点及开启PWA与自动部署的方法

    超详细动手搭建一个VuePress 站点及开启PWA与自动部署的方法

    这篇文章主要介绍了超详细动手搭建一个VuePress 站点及开启PWA与自动部署的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-01-01
  • 前端Vue学习之购物车项目实战记录

    前端Vue学习之购物车项目实战记录

    购物车是电商必备的功能,可以让用户一次性购买多个商品,下面这篇文章主要给大家介绍了关于前端Vue学习之购物车项目的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-07-07
  • vue 修改 data 数据问题并实时显示的方法

    vue 修改 data 数据问题并实时显示的方法

    今天小编就为大家分享一篇vue 修改 data 数据问题并实时显示的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-08-08
  • vue项目中导入swiper插件的方法

    vue项目中导入swiper插件的方法

    这篇文章主要介绍了vue项目中导入swiper插件的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-01-01
  • vue返回上一页面时回到原先滚动的位置的方法

    vue返回上一页面时回到原先滚动的位置的方法

    这篇文章主要介绍了vue返回上一页面时回到原先滚动的位置的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-12-12
  • element-ui vue input输入框自动获取焦点聚焦方式

    element-ui vue input输入框自动获取焦点聚焦方式

    这篇文章主要介绍了element-ui vue input输入框自动获取焦点聚焦方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04

最新评论