onTouchStart.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import { getWindow, getDocument } from 'ssr-window';
  2. import { now } from '../../shared/utils.js';
  3. // Modified from https://stackoverflow.com/questions/54520554/custom-element-getrootnode-closest-function-crossing-multiple-parent-shadowd
  4. function closestElement(selector, base = this) {
  5. function __closestFrom(el) {
  6. if (!el || el === getDocument() || el === getWindow()) return null;
  7. if (el.assignedSlot) el = el.assignedSlot;
  8. const found = el.closest(selector);
  9. if (!found && !el.getRootNode) {
  10. return null;
  11. }
  12. return found || __closestFrom(el.getRootNode().host);
  13. }
  14. return __closestFrom(base);
  15. }
  16. export default function onTouchStart(event) {
  17. const swiper = this;
  18. const document = getDocument();
  19. const window = getWindow();
  20. const data = swiper.touchEventsData;
  21. data.evCache.push(event);
  22. const {
  23. params,
  24. touches,
  25. enabled
  26. } = swiper;
  27. if (!enabled) return;
  28. if (!params.simulateTouch && event.pointerType === 'mouse') return;
  29. if (swiper.animating && params.preventInteractionOnTransition) {
  30. return;
  31. }
  32. if (!swiper.animating && params.cssMode && params.loop) {
  33. swiper.loopFix();
  34. }
  35. let e = event;
  36. if (e.originalEvent) e = e.originalEvent;
  37. let targetEl = e.target;
  38. if (params.touchEventsTarget === 'wrapper') {
  39. if (!swiper.wrapperEl.contains(targetEl)) return;
  40. }
  41. if ('which' in e && e.which === 3) return;
  42. if ('button' in e && e.button > 0) return;
  43. if (data.isTouched && data.isMoved) return;
  44. // change target el for shadow root component
  45. const swipingClassHasValue = !!params.noSwipingClass && params.noSwipingClass !== '';
  46. // eslint-disable-next-line
  47. const eventPath = event.composedPath ? event.composedPath() : event.path;
  48. if (swipingClassHasValue && e.target && e.target.shadowRoot && eventPath) {
  49. targetEl = eventPath[0];
  50. }
  51. const noSwipingSelector = params.noSwipingSelector ? params.noSwipingSelector : `.${params.noSwipingClass}`;
  52. const isTargetShadow = !!(e.target && e.target.shadowRoot);
  53. // use closestElement for shadow root element to get the actual closest for nested shadow root element
  54. if (params.noSwiping && (isTargetShadow ? closestElement(noSwipingSelector, targetEl) : targetEl.closest(noSwipingSelector))) {
  55. swiper.allowClick = true;
  56. return;
  57. }
  58. if (params.swipeHandler) {
  59. if (!targetEl.closest(params.swipeHandler)) return;
  60. }
  61. touches.currentX = e.pageX;
  62. touches.currentY = e.pageY;
  63. const startX = touches.currentX;
  64. const startY = touches.currentY;
  65. // Do NOT start if iOS edge swipe is detected. Otherwise iOS app cannot swipe-to-go-back anymore
  66. const edgeSwipeDetection = params.edgeSwipeDetection || params.iOSEdgeSwipeDetection;
  67. const edgeSwipeThreshold = params.edgeSwipeThreshold || params.iOSEdgeSwipeThreshold;
  68. if (edgeSwipeDetection && (startX <= edgeSwipeThreshold || startX >= window.innerWidth - edgeSwipeThreshold)) {
  69. if (edgeSwipeDetection === 'prevent') {
  70. event.preventDefault();
  71. } else {
  72. return;
  73. }
  74. }
  75. Object.assign(data, {
  76. isTouched: true,
  77. isMoved: false,
  78. allowTouchCallbacks: true,
  79. isScrolling: undefined,
  80. startMoving: undefined
  81. });
  82. touches.startX = startX;
  83. touches.startY = startY;
  84. data.touchStartTime = now();
  85. swiper.allowClick = true;
  86. swiper.updateSize();
  87. swiper.swipeDirection = undefined;
  88. if (params.threshold > 0) data.allowThresholdMove = false;
  89. let preventDefault = true;
  90. if (targetEl.matches(data.focusableElements)) {
  91. preventDefault = false;
  92. if (targetEl.nodeName === 'SELECT') {
  93. data.isTouched = false;
  94. }
  95. }
  96. if (document.activeElement && document.activeElement.matches(data.focusableElements) && document.activeElement !== targetEl) {
  97. document.activeElement.blur();
  98. }
  99. const shouldPreventDefault = preventDefault && swiper.allowTouchMove && params.touchStartPreventDefault;
  100. if ((params.touchStartForcePreventDefault || shouldPreventDefault) && !targetEl.isContentEditable) {
  101. e.preventDefault();
  102. }
  103. if (params.freeMode && params.freeMode.enabled && swiper.freeMode && swiper.animating && !params.cssMode) {
  104. swiper.freeMode.onTouchStart();
  105. }
  106. swiper.emit('touchStart', e);
  107. }