Fighting touch events on mobile devices, high normal scrolling

I looked through the code several times, and I can not find the reason why it does not work on touch devices:

/** * Initialize touch event listener. * * @returns {Plugin} */ touch: function () { var self = this; this._$body.bind('touchstart', function (event) { var startEvent = event.originalEvent.touches[0]; event.preventDefault(); self._$body.bind('touchmove', function (event) { var moveEvent = event.originalEvent.touches[0]; var diff = { x: startEvent.clientX - moveEvent.clientX, y: startEvent.clientY - moveEvent.clientY }; var nextStep; event.preventDefault(); if ((diff.y <= -100 || diff.y >= 100) && Math.abs(diff.y) > Math.abs(diff.x)) { nextStep = diff.y < 0 ? self._currentStep - 1 : self._currentStep + 1; self.customScrollTo(nextStep); } return false; }); return false; }); return this; }, 

demo (self signed ssl, don't worry!): https://sandbox.idev.ge/roomshotel/html5_v3/

Problem: Scrolling occurs right down when touch mode is activated.

Expected Result: One touch interacts with scrolling in 1 section.

Any thoughts?

0
source share
4 answers

I also think that the touchmove event touchmove fires every time it is clicked. By returning false from this function, you cancel only one move event on the screen and not all subsequent touch move events.

You cannot use the touchend event since you want to call self.customScrollTo(nextStep); as soon as the pointer ran 100px.

You want to prevent the touchmove callback from being executed after the pointer has passed 100px, this can be done in different ways, that is.

  • Using a flag variable of type var trackPointer = true; , check the box every time touchmove starts and sets this flag to false when the pointer has passed 100px.
  • When the pointer moves 100 pixels, set startEvent to null and check this variable on touchmove .
  • Untie the touchmove event when the pointer has traveled 100px.

Note. The touchmove event touchmove attached every time a touchstart fired on this element, these events do not overwrite each other, but add up! Therefore, you may want to bind the event only once (i.e., on the DOM ready) or cancel the event when it is no longer needed.

The latter is probably the simplest and can be performed, i.e. on touchend (use namespaces to not unleash the same events associated with other scripts):

 // Unbind all touchmove.myNameSpace events on touchend.myNameSpace. self._$body.bind('touchend.myNameSpace').function (event) { self._$body.unbind('touchmove.myNameSpace'); }); 

and when the pointer passed 100px:

 self.customScrollTo(nextStep); // Unbind all touchmove.myNameSpace events. self._$body.unbind('touchmove.myNameSpace'); 

Since "touchhend" does not start when the pointer is outside the element (I'm not sure about touchmove ), you can also touchmove right before the binding:

 event.preventDefault(); // Unbind all touchmove.myNameSpace events and (re)bind touchmove.myNameSpace event. self._$body.unbind('touchmove.myNameSpace').bind('touchmove.myNameSpace', function (event) { var moveEvent = event.originalEvent.touches[0]; 

So you can try (I have not tested it):

 /** * Initialize touch event listener. * * @returns {Plugin} */ touch: function () { var self = this; this._$body.bind('touchstart', function (event) { var startEvent = event.originalEvent.touches[0]; event.preventDefault(); self._$body.unbind('touchmove.myNameSpace').bind('touchmove.myNameSpace', function (event) { var moveEvent = event.originalEvent.touches[0]; var diff = { x: startEvent.clientX - moveEvent.clientX, y: startEvent.clientY - moveEvent.clientY }; var nextStep; event.preventDefault(); // <- Not necessary since you completely cancel the event by returning false. if ((diff.y <= -100 || diff.y >= 100) && Math.abs(diff.y) > Math.abs(diff.x)) { nextStep = diff.y < 0 ? self._currentStep - 1 : self._currentStep + 1; self.customScrollTo(nextStep); // Unbind all touchmove.myNameSpace events. self._$body.unbind('touchmove.myNameSpace'); } return false; }); return false; }); // Unbind all touchmove.myNameSpace events on touchend.myNameSpace. self._$body.bind('touchend.myNameSpace').function (event) { self._$body.unbind('touchmove.myNameSpace'); }); return this; }, 

PS: You might want to use a library such as HammerJS ( https://github.com/hammerjs/hammer.js ) to make gestures work in a cross browser, as well as not touching the device.

0
source

First I suggest you use Modernizr to detect touch

 if (Modernizr.touch) { $("body").swipe({ //Generic swipe handler for all directions swipe: function (event, direction, distance, duration, fingerCount, fingerData) { if(distance >= 100) //Check the units in px or unit { if (direction === "up") { self.customScrollTo(nextStep); } else if (direction === "down") { self.customScrollTo(prevStep); } } } }); } 

I just put the logic above. "I" is only your object.

to use the swipe event you need to enable the jquery plugin https://github.com/mattbryson/TouchSwipe-Jquery-Plugin

+1
source

I think the touchmove event fires several times, try using touchhend instead.

Regarding: http://css-tricks.com/the-javascript-behind-touch-friendly-sliders/ I checked your code using google chrome live javascript editing. and he worked with the following modification of the touchmove event.

 setTimeout(function(){ self.customScrollTo(nextStep); }, 250); 
0
source
 /** * Initialize touch event listener. * * @returns {Plugin} */ touch: function () { var self = this; var flag = false; this._$body.bind('touchstart', function (event) { var startEvent = event.originalEvent.touches[0]; self._$body.bind('touchmove', function (event) { var moveEvent = event.originalEvent.touches[0]; var diff = { x: startEvent.clientX - moveEvent.clientX, y: startEvent.clientY - moveEvent.clientY }; var nextStep; if (((diff.y <= -100 || diff.y >= 100) && Math.abs(diff.y) > Math.abs(diff.x)) && flag == true) { nextStep = diff.y < 0 ? self._currentStep - 1 : self._currentStep + 1; self.customScrollTo(nextStep); startEvent = event.originalEvent.touches[0]; // Just added this line here. } event.preventDefault(); return false; }); return false; }); return this; }, 

I assume simple editing is required. After you have exceeded diff by 100 or -100, just update the value of the startEvent variable. So I added a statement

  startEvent = event.originalEvent.touches[0]; 

So, when the event is fired for "self.customScrollTo (nextStep)", the value of "startEvent" is the new value, which is the current position of the affected point. And therefore, when the touchmove event is raised again. It will again receive a new set of values ​​for calculation. Please check this code and tell me if it works or not. Even if it is not.

0
source

Source: https://habr.com/ru/post/976638/


All Articles