仿照vant4的FloatingBubble组件实现一个简单的FloatingBubble组件。

417 阅读1分钟

1.仿照vant4的FloatingBubble组件实现一个简单的FloatingBubble组件。 可以在指定范围内拖动,目前做的是不超出屏幕范围,做了边界处理。

<template>
  <div
    class="floating-bubble"
    :style="{
      top: snappedTop + 'px',
      left: snappedLeft + 'px',

    }"
    @touchstart="handleTouchStart"
    @touchmove="handleTouchMove"
    @touchend="handleTouchEnd"
  >
    <slot />
  </div>
</template>

<script>
export default {
  data() {
    return {
      windowWidth: 0,
      windowHeight: 0,
      isDragging: false, // 拖动状态
      startX: 0, // 拖动起始点的X坐标
      startY: 0, // 拖动起始点的Y坐标
      left: 0, // 悬浮气泡的left位置
      top: 0, // 悬浮气泡的top位置
    }
  },
  methods: {
    handleTouchStart(event) {
      this.isDragging = true
      this.startX = event.touches[0].clientX - this.left
      this.startY = event.touches[0].clientY - this.top
    },
    handleTouchMove(event) {
      if (!this.isDragging) return
      event.preventDefault()

      const touchX = event.touches[0].clientX
      const touchY = event.touches[0].clientY

      this.left = touchX - this.startX
      this.top = touchY - this.startY

      this.handleBoundary() // 处理边界
    },
    handleTouchEnd() {
      this.isDragging = false
    },
    handleBoundary() {
      const threshold = 60 // 边缘阈值

      // 处理左边界
      if (this.left < threshold) {
        this.left = 0
      }
      // 处理上边界
      if (this.top < threshold) {
        this.top = 0
      }
      // 处理右边界
      const windowWidth =
        window.innerWidth ||
        document.documentElement.clientWidth ||
        document.body.clientWidth
      if (windowWidth - this.left < threshold) {
        this.left = windowWidth - 50
      }
      // 处理下边界
      const windowHeight =
        window.innerHeight ||
        document.documentElement.clientHeight ||
        document.body.clientHeight
      if (windowHeight - this.top < threshold) {
        this.top = windowHeight - 130
      }
    },
  },
  computed: {
    snappedLeft() {
      return this.left
    },
    snappedTop() {
      return this.top
    },
    snappedRight() {
      const windowWidth = this.windowWidth
      const elementWidth = 50 // 元素的宽度
      const threshold = 20 // 边缘阈值
      const maxRight = windowWidth - elementWidth - threshold

      if (this.left > maxRight) {
        return maxRight
      } else if (this.left < threshold) {
        return threshold
      }
      return this.left

    },
    snappedBottom() {
      const windowHeight = this.windowHeight
      const elementHeight = 100 // 元素的高度
      const threshold = 20 // 边缘阈值
      const maxBottom = windowHeight - elementHeight - threshold

      if (this.top > maxBottom) {
        return maxBottom
      } else if (this.top < threshold) {
        return threshold
      }
      return this.top

    },
  },
  mounted() {
    //计算初始位置
    this.windowWidth =
    window.innerWidth ||
    document.documentElement.clientWidth ||
    document.body.clientWidth

    this.windowHeight =
        window.innerHeight ||
        document.documentElement.clientHeight ||
        document.body.clientHeight
    this.left = this.windowWidth - 50
    this.top = this.windowHeight / 2
  },
}
</script>

<style scoped>
.floating-bubble {
  position: fixed;
  /* border-radius: 50%; */
  width: fit-content;
  height: fit-content;
  /* background-color: #333; */
  color: #fff;
  text-align: center;
  /* line-height: 100px; */
  font-size: 20px;
  cursor: move;
  transition: background-color 0.3s;
}

.floating-bubble:hover {
  /* background-color: #555; */
}

.floating-bubble:active {
  /* background-color: #777; */
}
</style>