dragBox.vue 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. <template>
  2. <div ref="dragBoxRef" class="tvb-drag-box" :class="{ disabled: disabled }" :style="disabled ? '' : `right: ${dragBoxPos.x}px; bottom: ${dragBoxPos.y}px;`
  3. " @touchstart="onTouchStart" @touchend="onTouchEnd" @touchmove="onTouchMove">
  4. <slot></slot>
  5. </div>
  6. </template>
  7. <script setup>
  8. import { ref } from "vue";
  9. const props = defineProps({
  10. disabled: { type: Boolean, default: false }
  11. });
  12. const dragPos = {
  13. hasMoved: false, // 排除click事件
  14. x: 20, // right
  15. y: 100, // bottom
  16. startX: 0,
  17. startY: 0,
  18. endX: 0,
  19. endY: 0
  20. };
  21. const dragBoxPos = ref({ x: null, y: null });
  22. const dragBoxRef = ref();
  23. const setPosition = (dragX, dragY) => {
  24. [dragX, dragY] = _getSafeAreaXY(dragX, dragY);
  25. dragPos.x = dragX;
  26. dragPos.y = dragY;
  27. dragBoxPos.value.x = dragX;
  28. dragBoxPos.value.y = dragY;
  29. };
  30. const _getSafeAreaXY = (x, y) => {
  31. const docWidth = Math.max(
  32. document.documentElement.offsetWidth,
  33. window.innerWidth
  34. );
  35. const docHeight = Math.max(
  36. document.documentElement.offsetHeight,
  37. window.innerHeight
  38. );
  39. // 检查屏幕边缘
  40. if (x + dragBoxRef.value.offsetWidth > docWidth) {
  41. x = docWidth - dragBoxRef.value.offsetWidth;
  42. }
  43. if (y + dragBoxRef.value.offsetHeight > docHeight) {
  44. y = docHeight - dragBoxRef.value.offsetHeight;
  45. }
  46. if (x < 0) {
  47. x = 0;
  48. }
  49. // iOS底部的安全区域
  50. if (y < 20) {
  51. y = 20;
  52. }
  53. return [x, y];
  54. };
  55. const onTouchStart = (e) => {
  56. if (props.disabled) return;
  57. dragPos.startX = e.touches[0].pageX;
  58. dragPos.startY = e.touches[0].pageY;
  59. dragPos.hasMoved = false;
  60. };
  61. const onTouchEnd = (e) => {
  62. if (props.disabled) return;
  63. if (!dragPos.hasMoved) return;
  64. dragPos.startX = 0;
  65. dragPos.startY = 0;
  66. dragPos.hasMoved = false;
  67. setPosition(dragPos.endX, dragPos.endY);
  68. };
  69. const onTouchMove = (e) => {
  70. if (props.disabled) return;
  71. if (e.touches.length <= 0) return;
  72. const offsetX = e.touches[0].pageX - dragPos.startX,
  73. offsetY = e.touches[0].pageY - dragPos.startY;
  74. let x = Math.floor(dragPos.x - offsetX),
  75. y = Math.floor(dragPos.y - offsetY);
  76. [x, y] = _getSafeAreaXY(x, y);
  77. dragBoxPos.value.x = x;
  78. dragBoxPos.value.y = y;
  79. dragPos.endX = x;
  80. dragPos.endY = y;
  81. dragPos.hasMoved = true;
  82. e.preventDefault();
  83. };
  84. </script>
  85. <style lang='scss' scoped>
  86. .tvb-drag-box {
  87. &:not(.disabled) {
  88. position: fixed;
  89. bottom: 100px;
  90. right: 20px;
  91. overflow: hidden;
  92. z-index: 99;
  93. }
  94. }
  95. </style>