Vue移动端悬浮框显示,支持拖拽及点击传递

前言

最近产品提了一个需求,让移动端项目的所有页面(除了登录、个人中心不展示),新增一个悬浮框,并且支持在可视区域随意拖拽,点击可以跳转到指定页面。

最终效果

在这里插入图片描述

组件封装的参数配置

1、代码示例:

<t-floating-box :visible="visible" @click="jumpPage"/>

2、配置参数(t-floating-box Attributes)

参数说明类型默认值
visible是否显示悬浮框Booleantrue
width悬浮框宽number40 px
height悬浮框宽高number40 px
name悬浮框文案String-
zIndex悬浮框z-indexnumber999

3、events 事件

事件名称说明回调参数
click点击悬浮框事件-

源码

<template>
  <div
      v-show="visible"
      class="t_floating_box"
      @click="handleClick"
      :style="{top: typeof top === 'number' ? `${top}px` : top, left: typeof left === 'number' ? `${left}px` : left, width: `${width}px`, height: `${height}px`, zIndex: zIndex}"
      ref="move_div"
      @touchstart="down"
      @touchmove="move"
      @touchend="end"
    >{{name}}</div>
</template>

<script>
export default {
  name: "TFloatingBox",
  props: {
     visible: {
      type: Boolean,
      default: true
    },
    width: {
      type: [String, Number],
      default: 40
    },
    height: {
      type: [String, Number],
      default: 40
    },
    name: {
      type: String,
      default: ''
    },
    zIndex: {
      type: Number,
      default: 999
    }
  },
  data() {
    return {
      flags: false, // 鼠标按下标志
      position: { x: 0, y: 0, left: 320, top: 630 },
      top: 630,
      left: 320,
      width: window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth,
      height: window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight,     
    }
  },

  mounted() {
    // 初始化
    // this.top = window.innerHeight - 80
    // this.left = window.innerWidth - 50
    this.top = '85%'
    this.left = '86%'
    this.position.top = this.top
    this.position.left = this.left
  },
  methods: {
    handleClick() {
      this.$emit('click')
    },
    // 拖动开始的操作
    down() {
      this.flags = true
      const refs = this.$refs.move_div?.getBoundingClientRect()
      let touch = event
      if (event.touches) {
        touch = event.touches[0]
      }
      this.position.x = touch.clientX
      this.position.y = touch.clientY
      this.position.left = refs.left
      this.position.top = refs.top
    },
    // 拖动中的操作
    move() {
      if (this.flags) {
        let touch = event
        if (event.touches) {
          touch = event.touches[0]
        }
        const xPum = this.position.left + touch.clientX - this.position.x
        const yPum = this.position.top + touch.clientY - this.position.y
        this.left = xPum
        this.top = yPum
        this.banOut()
        // 阻止页面的滑动默认事件
        // document.addEventListener('touchmove', function () {
        //   event.preventDefault()
        // }, { passive: false })
      }
    },
    // 拖动结束的操作
    end() {
      this.flags = false
      this.banOut()
    },
    // 避免拖动出界的限制
    banOut() {
      const refs = this.$refs.move_div?.getBoundingClientRect()
      if (this.left < 0) {
        this.left = 0
      } else if (this.left > this.width - refs.width) {
        this.left = this.width - refs.width
      }
      if (this.top < 0) {
        this.top = 0
      } else if (this.top > this.height - refs.height) {
        this.top = this.height - refs.height
      }
    },
  }
}
</script>

<style lang="scss">
  .t_floating_box {
    position: fixed;
    font-size: 12px;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: #2072ed;
    color: #ffffff;
    border-radius: 50%;
    white-space: nowrap;
    cursor: pointer;
    box-shadow: -1px 0px 4px -1px #f7f8fa;
  }
</style>

移动端项目的所有页面(除了登录、个人中心不展示)显示悬浮框

在App.vue文件中这样引入

前提是TFloatingBox组件已全局注册,或者自己import引入单独注册

<template>
  <div id="app">
    <transition :name="transitionName">
      <router-view class="Router"></router-view>
    </transition>
    <t-floating-box :visible="visible" />
  </div>
</template>

<script>
export default {
  name: "app",
  data() {
    return {
      transitionName: "slide-right", // 默认动态路由变化为slide-right
      visible: true,
    };
  },
  watch: {
    $route(to) {
      // console.log('to---app', to)
      const hiddenPaths = ['/scrapQuotation', '/login', '/orderStatistics', '/deliveryStatistics'];
      this.visible = !hiddenPaths.includes(to.path);
    },
  },
};
</script>

相关文章

基于ElementUi再次封装基础组件文档


vue3+ts基于Element-plus再次封装基础组件文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wocwin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值