index.vue 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. <template>
  2. <view
  3. :class="classes"
  4. ref="myDrag"
  5. @touchstart="touchStart($event)"
  6. @touchmove="touchMove($event)"
  7. @touchend="touchEnd($event)"
  8. >
  9. <slot></slot>
  10. </view>
  11. </template>
  12. <script lang="ts">
  13. import {
  14. onMounted,
  15. onDeactivated,
  16. onActivated,
  17. reactive,
  18. ref,
  19. computed
  20. } from 'vue';
  21. import { createComponent } from '@/utils/create';
  22. import requestAniFrame from '@/utils/raf';
  23. const { componentName, create } = createComponent('drag');
  24. export default create({
  25. props: {
  26. attract: {
  27. type: Boolean,
  28. default: false
  29. },
  30. direction: {
  31. type: String,
  32. default: 'all'
  33. },
  34. boundary: {
  35. type: Object,
  36. default: () => {
  37. return {
  38. top: 0,
  39. left: 0,
  40. right: 0,
  41. bottom: 0
  42. };
  43. }
  44. }
  45. },
  46. setup(props, { emit }) {
  47. const myDrag = ref();
  48. const state = reactive({
  49. keepAlive: false,
  50. elWidth: 0,
  51. elHeight: 0,
  52. screenWidth: 0,
  53. screenHeight: 0,
  54. startTop: 0,
  55. startLeft: 0,
  56. nx: 0,
  57. ny: 0,
  58. xPum: 0,
  59. yPum: 0,
  60. position: { x: 0, y: 0 },
  61. boundary: {
  62. top: 0,
  63. left: 0,
  64. right: 0,
  65. bottom: 0
  66. } as Record<string, any>
  67. });
  68. const classes = computed(() => {
  69. const prefixCls = componentName;
  70. return {
  71. [prefixCls]: true
  72. };
  73. });
  74. function getInfo() {
  75. const domElem = document.documentElement;
  76. state.elWidth = myDrag.value.offsetWidth;
  77. state.elHeight = myDrag.value.offsetHeight;
  78. state.screenWidth = domElem.clientWidth;
  79. state.screenHeight = domElem.clientHeight;
  80. }
  81. function goLeft(target: HTMLElement) {
  82. if (state.boundary.left) {
  83. if (+target.style.left.split('px')[0] > state.boundary.left) {
  84. target.style.left = +target.style.left.split('px')[0] - 10 + 'px';
  85. requestAniFrame(() => {
  86. goLeft(target);
  87. });
  88. } else {
  89. target.style.left = `${state.boundary.left}px`;
  90. }
  91. } else {
  92. if (+target.style.left.split('px')[0] > 10) {
  93. target.style.left = +target.style.left.split('px')[0] - 10 + 'px';
  94. requestAniFrame(() => {
  95. goLeft(target);
  96. });
  97. } else {
  98. target.style.left = '0px';
  99. }
  100. }
  101. }
  102. function goRight(target: HTMLElement, rightLocation: number) {
  103. if (rightLocation - parseInt(target.style.left.split('px')[0]) > 10) {
  104. target.style.left =
  105. parseInt(target.style.left.split('px')[0]) + 10 + 'px';
  106. requestAniFrame(() => {
  107. goRight(target, rightLocation);
  108. });
  109. } else {
  110. target.style.left = rightLocation + 'px';
  111. }
  112. }
  113. function touchMove(e: TouchEvent) {
  114. e.preventDefault();
  115. const target = e.currentTarget as HTMLElement;
  116. if (e.targetTouches.length === 1) {
  117. const touch = e.targetTouches[0];
  118. state.nx = touch.clientX - state.position.x;
  119. state.ny = touch.clientY - state.position.y;
  120. state.xPum = state.startLeft + state.nx;
  121. state.yPum = state.startTop + state.ny;
  122. const rightLocation =
  123. state.screenWidth - state.elWidth - state.boundary.right;
  124. if (Math.abs(state.xPum) > rightLocation) {
  125. state.xPum = rightLocation;
  126. } else if (state.xPum <= state.boundary.left) {
  127. state.xPum = state.boundary.left;
  128. }
  129. if (state.yPum < state.boundary.top) {
  130. state.yPum = state.boundary.top;
  131. } else if (
  132. state.yPum >
  133. state.screenHeight - state.elHeight - state.boundary.bottom
  134. ) {
  135. state.yPum =
  136. state.screenHeight - state.elHeight - state.boundary.bottom;
  137. }
  138. if (props.direction != 'y') {
  139. target.style.left = state.xPum + 'px';
  140. }
  141. if (props.direction != 'x') {
  142. target.style.top = state.yPum + 'px';
  143. }
  144. }
  145. }
  146. function touchEnd(e: TouchEvent) {
  147. const target = e.currentTarget as HTMLElement;
  148. const touch = e.changedTouches[0];
  149. let currX = touch.clientX;
  150. const rightLocation =
  151. state.screenWidth - state.elWidth - state.boundary.right;
  152. if (currX > rightLocation) {
  153. currX = rightLocation;
  154. } else if (currX < state.boundary.left) {
  155. currX = state.boundary.left;
  156. } else {
  157. currX =
  158. currX < state.screenWidth / 2 ? state.boundary.left : rightLocation;
  159. }
  160. if (props.direction !== 'y' && props.attract) {
  161. if (currX < state.screenWidth / 2) {
  162. requestAniFrame(() => {
  163. goLeft(target);
  164. });
  165. } else {
  166. requestAniFrame(() => {
  167. goRight(target, rightLocation);
  168. });
  169. }
  170. }
  171. if (props.direction !== 'x') {
  172. target.style.top = state.yPum + 'px';
  173. }
  174. }
  175. function touchStart(e: TouchEvent) {
  176. const target = e.currentTarget as HTMLElement;
  177. const touches = e.touches[0];
  178. state.startTop = target.offsetTop;
  179. state.startLeft = target.offsetLeft;
  180. state.position.x = touches.clientX;
  181. state.position.y = touches.clientY;
  182. }
  183. onMounted(() => {
  184. getInfo();
  185. state.boundary = props.boundary;
  186. });
  187. onActivated(() => {
  188. if (state.keepAlive) {
  189. state.keepAlive = false;
  190. }
  191. });
  192. onDeactivated(() => {
  193. state.keepAlive = true;
  194. (myDrag as any).removeEventListener('touchstart', touchStart);
  195. (myDrag as any).removeEventListener('touchmove', touchMove);
  196. (myDrag as any).removeEventListener('touchend', touchEnd);
  197. });
  198. return {
  199. classes,
  200. myDrag,
  201. touchStart,
  202. touchMove,
  203. touchEnd
  204. };
  205. }
  206. });
  207. </script>
  208. <style lang="scss">
  209. @import 'index.scss';
  210. </style>