vue2 实现可拖拽悬浮球

  • 实现效果

  • 相关代码

点击查看代码

<template>
  <div class="float-box">
    <div
      class="button-box"
      @mousedown="mousedown"
      @mousemove="mousemove"
      @touchmove="mousemove"
      @mouseup="mouseup"
      @touchstart="mousedown"
      @touchend="mouseup"
      @click="onClick"
      ref="flbutton"
    >
      <span class="title">{{ title }}</span>
    </div>
    <div
      :style="{ left: left + 'px', top: top + 'px' }"
      v-if="menuFlag"
      :class="menuPosition === 'right' ? 'menu-item-right':'menu-item-left'"
    >
      <div :class="tabBackImg(index)" class="box-title-box-item" v-for="(item,index) in circleList"
           @click="circleClick(item,index)">
        <span :class="'text'+index">{{ item }}</span>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "FloatButton",
  props: {
    circleList: {
      type: Array,
      default: () => []
    },
  },
  data() {
    return {
      title: '',
      left: 0,
      top: 40,
      menuFlag: false,//菜单显隐
      mouseDownflag: false, // 鼠标点击状态
      position: {
        x: 0,
        y: 0,
      },
      nx: "",
      ny: "",
      dx: "",
      dy: "",
      xPum: "",
      yPum: "",
      movb: 1,//区分拖拽还是点击
      menuPosition: 'right',
    };
  },
  mounted() {
    this.left = this.$refs.flbutton.offsetLeft + 20;
    this.top = this.$refs.flbutton.offsetTop;
    this.title = this.circleList[0];
  },
  computed: {
    tabBackImg() {
      return (index) => {
        if (index === 0) {
          return 'tab-item-1'
        } else if (index === 1) {
          return 'tab-item-2'
        } else if (index === 2) {
          return 'tab-item-3'
        } else if (index === 3) {
          return 'tab-item-4'
        }
      }
    }
  },
  methods: {
    circleClick(item, index) {
      this.title = item
      this.$emit('circleClick', item, index)
    },
    //鼠标摁下
    mousedown() {
      this.mouseDownflag = true;
      /*此处判断pc 或移动端得到event 事件*/
      var touch;
      if (event.touches) {
        touch = event.touches[0];
      } else {
        touch = event;
      }
      //鼠标点击面向页面的x坐标y坐标
      this.position.x = touch.clientX;
      this.position.y = touch.clientY;
      //鼠标x坐标-拖拽按钮x坐标得到鼠标距离拖拽按钮的间距
      this.dx = this.$refs.flbutton.offsetLeft;
      //鼠标y坐标-拖拽按钮y坐标得到鼠标距离拖拽按钮的间距
      this.dy = this.$refs.flbutton.offsetTop;
    },
    //鼠标拖拽移动
    mousemove() {
      if (this.mouseDownflag) {
        this.movb = 2;
        this.menuFlag = false;
        /*此处判断得到event事件*/
        var touch;
        if (event.touches) {
          touch = event.touches[0];
        } else {
          touch = event;
        }
        //鼠标坐标-鼠标与拖拽按钮的间距坐标得到拖拽按钮的左上角x轴y轴坐标
        this.nx = touch.clientX - this.position.x;
        this.ny = touch.clientY - this.position.y;

        this.xPum = this.dx + this.nx;
        this.yPum = this.dy + this.ny;
        let width = window.innerWidth - this.$refs.flbutton.offsetWidth; //屏幕宽度减去自身控件宽度
        let height = window.innerHeight - this.$refs.flbutton.offsetHeight; //屏幕高度减去自身控件高度
        /* 此处判断
          拖拽按钮 如果超出屏幕宽高或者小于
          设置屏幕最大 x=全局容器x y=全局容器y
          否则 设置 为 x=0 y=0
        */
        this.xPum < 0 && (this.xPum = 0);
        this.yPum < 0 && (this.yPum = 0);
        this.xPum > width && (this.xPum = width);
        this.yPum > height && (this.yPum = height);
        if (this.xPum > 900) {
          this.menuPosition = 'left'
        } else {
          this.menuPosition = 'right'
        }
        // 计算后坐标  设置 按钮位置
        this.$refs.flbutton.style.left = this.xPum + "px";
        this.$refs.flbutton.style.top = this.yPum + "px";
        this.left = this.xPum + 20;
        this.top = this.yPum;

        //阻止页面的滑动默认事件
        document.addEventListener("touchmove", function () {
          event.preventDefault();
        }, false);
      }
    },
    //鼠标抬起
    mouseup() {
      this.mouseDownflag = false;
    },
    onClick() {
      if (this.movb === 2) {
        this.movb = 1;
      } else {
        this.menuFlag = !this.menuFlag;
      }
    },
  },
};
</script>
<style scoped lang="scss">
.float-box {
  position: relative;

  .button-box {
    width: 110px;
    height: 110px;
    position: fixed;
    top: 100px;
    left: 500px;
    touch-action: none;
    text-align: center;
    color: white;
    background-image: url("~@/assets/images/screen/float-button/button.png");
    background-repeat: no-repeat;
    background-size: 100% 100%;
    line-height: 100px;
    font-size: 14px;
    cursor: pointer;
    z-index: 99;

    .title {
      background: linear-gradient(rgba(255, 255, 255, 1) 25%, rgba(69, 177, 254, 1) 100%);;
      -webkit-background-clip: text;
      color: transparent;
      font-weight: bolder;
    }
  }

  .menu-item-left {
    position: absolute;
    z-index: 99;

    .box-title-box-item {
      color: #FFFFFF;
      cursor: pointer;
      font-size: 13px;
      cursor: pointer;
      display: flex;
      justify-content: center;
      align-items: center;
    }

    .tab-item-1 {
      height: 53px;
      width: 43px;
      position: absolute;
      top: -8px;
      left: -42px;
      background: url("~@/assets/images/screen/float-button/button-l1.png") no-repeat;
      background-size: 100% 100%;
      line-height: 43px;
      padding-top: 10px;
    }

    .tab-item-2 {
      height: 53px;
      width: 44px;
      background: url("~@/assets/images/screen/float-button/button-l2.png") no-repeat;
      background-size: 100% 100%;
      position: absolute;
      top: 46px;
      left: -42px;
      line-height: 43px;
    }

    .tab-item-3 {
      height: 43px;
      width: 53px;
      background: url("~@/assets/images/screen/float-button/button-r3.png") no-repeat;
      background-size: 100% 100%;
      position: absolute;
      top: 80px;
      left: 37px;
      line-height: 43px;
    }

    .tab-item-4 {
      height: 43px;
      width: 53px;
      background: url("~@/assets/images/screen/float-button/button-r4.png") no-repeat;
      background-size: 100% 100%;
      position: absolute;
      top: 80px;
      left: -17px;
      line-height: 40px;
    }

    .tab-item-1:hover, .tab-item-2:hover, .tab-item-3:hover, .tab-item-4:hover {
      transform: scale(1.2);
    }

    .text0, .text1, .text2, .text3 {
      display: inline-block;
    }

    .text0 {
      writing-mode: vertical-rl;
      letter-spacing: 1px;
      transform: rotate(17deg);
    }

    .text1 {
      writing-mode: vertical-rl;
      letter-spacing: 1px;
      transform: rotate(335deg);
    }

    .text2 {
      transform: rotate(340deg);
    }

    .text3 {
      transform: rotate(20deg);
    }
  }

  .menu-item-right {
    position: absolute;
    z-index: 99;

    .box-title-box-item {
      color: #FFFFFF;
      cursor: pointer;
      font-size: 13px;
      cursor: pointer;
      display: flex;
      justify-content: center;
      align-items: center;
    }

    .tab-item-1 {
      height: 53px;
      width: 43px;
      position: absolute;
      top: -10px;
      left: 67px;
      background: url("~@/assets/images/screen/float-button/button-r1.png") no-repeat;
      background-size: 100% 100%;
      line-height: 43px;
      padding-top: 10px;
    }

    .tab-item-2 {
      height: 53px;
      width: 43px;
      background: url("~@/assets/images/screen/float-button/button-r2.png") no-repeat;
      background-size: 100% 100%;
      position: absolute;
      top: 45px;
      left: 69px;
      line-height: 43px;
    }

    .tab-item-3 {
      height: 43px;
      width: 53px;
      background: url("~@/assets/images/screen/float-button/button-r3.png") no-repeat;
      background-size: 100% 100%;
      position: absolute;
      top: 80px;
      left: 35px;
      line-height: 43px;
    }

    .tab-item-4 {
      height: 43px;
      width: 53px;
      background: url("~@/assets/images/screen/float-button/button-r4.png") no-repeat;
      background-size: 100% 100%;
      position: absolute;
      top: 80px;
      left: -20px;
      line-height: 40px;
    }

    .tab-item-1:hover, .tab-item-2:hover, .tab-item-3:hover, .tab-item-4:hover {
      transform: scale(1.2);
    }

    .text0, .text1, .text2, .text3 {
      display: inline-block;
    }

    .text0 {
      writing-mode: vertical-rl;
      letter-spacing: 1px;
      transform: rotate(345deg);
    }

    .text1 {
      writing-mode: vertical-rl;
      letter-spacing: 1px;
      transform: rotate(21deg);
      margin-bottom: 5px;
    }

    .text2 {
      transform: rotate(337deg);
      margin-right: 10px;
    }

    .text3 {
      transform: rotate(20deg);
      margin-left: 5px;
    }
  }
}
</style>
相关推荐
cs_dn_Jie3 小时前
钉钉 H5 微应用 手机端调试
前端·javascript·vue.js·vue·钉钉
Yaml45 小时前
智能化健身房管理:Spring Boot与Vue的创新解决方案
前端·spring boot·后端·mysql·vue·健身房管理
计算机-秋大田15 小时前
基于Spring Boot的船舶监造系统的设计与实现,LW+源码+讲解
java·论文阅读·spring boot·后端·vue
Yaml41 天前
Spring Boot 与 Vue 共筑二手书籍交易卓越平台
java·spring boot·后端·mysql·spring·vue·二手书籍
清灵xmf1 天前
在 Vue 中实现与优化轮询技术
前端·javascript·vue·轮询
琴~~2 天前
前端根据后端返回的文本流逐个展示文本内容
前端·javascript·vue
程序员徐师兄3 天前
基于 JavaWeb 的宠物商城系统(附源码,文档)
java·vue·springboot·宠物·宠物商城
shareloke3 天前
让Erupt框架支持.vue文件做自定义页面模版
vue
你白勺男孩TT3 天前
Vue项目中点击按钮后浏览器屏幕变黑,再次点击恢复的解决方法
vue.js·vue·springboot
虞泽3 天前
鸢尾博客项目开源
java·spring boot·vue·vue3·博客