9

I read about touchenter and touchleave events, at mozilla website and w3 website, but can not find any browser to support it or any javascript library that mimics that effect.

Please suggest what could be done as there workaround, as I am working for some mouseover like effect , event gets triggered when fingers enter the element, not when user lifts and touches elements again.

Thanks :)

Ajit Kumar Singh
  • 105
  • 1
  • 2
  • 5

6 Answers6

22

I suggest that you use

document.elementFromPoint(touch.x, touch.y);

on touchmove event.

10

You're referencing an old draft, the latest one removed the touchenter and touchleave events.

Knu
  • 14,806
  • 5
  • 56
  • 89
rvignacio
  • 1,710
  • 1
  • 18
  • 33
1

There is a list here stating the version-wise compatibility. Currently Chrome, Opera, iOS Safari, Android Browser, Blackberry Browser, Opera Mobile, Chrome for Android, Firefox for android support this feature

Daksh Shah
  • 2,997
  • 6
  • 37
  • 71
1

W3C removed ontouchenter and ontouchleave, so that we can only do these(with zepto.js, touch.js, ontouchmove, elementFromPoint):

var last_touched_button='';
$('#container,#button1,#button2').on('touchmove',function(e){
      var ele=document.elementFromPoint(e.touches[0].clientX, e.touches[0].clientY);
      if (ele==document.getElementById('button1'))
      {last_touched_button='button1';
      }
      else if (ele==document.getElementById('button2'))
      {last_touched_button='button2';
      }
});
$('#container,#button1,#button2').on('swipeLeft',function(e){
      console.log('the button '+last_touched_button+' triggered swipe_into_left_side event or swipe_out_from_left_side event!');
});
diyism
  • 12,477
  • 5
  • 46
  • 46
0

Currently, there is no support for such events at core, however it is possible to simulate them.

I Created a small script to make onTouchEnter and onTouchLeave methods available. Very simple use (To test the snippet activate the mobile version of this website, or use it at a smartphone browser)

onTouchEnter('.some-selector', function(element,event){/*DO ANYTHING*/})
onTouchLeave('.some-selector', function(element,event){/*DO ANYTHING*/})

The script bellow uses document.elementFromPoint to make the magic.

let onTouchLeaveEvents = [];
let onTouchEnterEvents = [];
const onTouchEnter = function (selector, fn) {
    onTouchEnterEvents.push([selector, fn]);
    return function () {
        onTouchEnterEvents.slice().map(function (e, i) {
            if (e[0] === selector && e[1] === fn) {
                onTouchEnterEvents.splice(1, i);
            }
        });
    };
};

const onTouchLeave = function (selector, fn) {
    onTouchLeaveEvents.push([selector, fn]);
    return function () {
        onTouchLeaveEvents.slice().map(function (e, i) {
            if (e[0] === selector && e[1] === fn) {
                onTouchLeaveEvents.splice(1, i);
            }
        });
    };
};

let lastTouchLeave;
let lastTouchEnter;
document.addEventListener('touchmove', function (e) {
    var el = document.elementFromPoint(e.touches[0].clientX, e.touches[0].clientY);
    if (!el) return;
  
  onTouchLeaveEvents.map((event) => {
    if (el!=lastTouchEnter && lastTouchEnter && lastTouchEnter.matches(event[0])) {
      
        
            if (lastTouchEnter !== lastTouchLeave ) {
                event[1](lastTouchEnter, e);
        lastTouchLeave = lastTouchEnter;
        lastTouchEnter = null
            }
            
        }
    });
  
    onTouchEnterEvents.map((event) => {
        if (el.matches(event[0]) && el!==lastTouchEnter) {
            lastTouchEnter = el;
      lastTouchLeave = null;
      event[1](el, e);
     }
    });

});

onTouchEnter('.area',function(el,e){
  el.classList.add('hover')
})
onTouchLeave('.area',function(el,e){
  el.classList.remove('hover')
})
.area {
  width:100px;
  height:100px;
  margin:2px ;
  font-size:12px;
  display:flex;
  align-items:center;
  justify-content:center;
  float:left;
}
.area.hover{
  background-color:#333 !important;
  color:#fff;
}
#div-1{background-color:#f00;}
#div-2{background-color:#0f0;}
#div-3{background-color:#00f;}
body{
overflow:hidden
}
<div id="div-1" class="area">DIV 1</div>
<div id="div-2" class="area">DIV 2</div>
<div id="div-3" class="area">DIV 3</div>

This GIST contains the same code as above, for improvements, please create comments there.

Guilherme Ferreira
  • 2,209
  • 21
  • 23
0

This works for me. In callbacks I just need the element; not the mouse/touch event and not the context (don't use 'this' in callback).

pointer.ts

/**
 *  Simulate touchenter and touchleave by tracking touchmove. See https://stackoverflow.com/questions/23111671/touchenter-and-touchleave-events-support
 */
const touchEventSimulator = {

    // enterElementCallback stores element as key and callback as value
    enterElementCallback: new Map(),
    leaveElementCallback: new Map(),
    previousElement: null,

    init: function() {
        window.addEventListener('touchmove', event => {
            var currentElement = document.elementFromPoint(event.touches[0].clientX, event.touches[0].clientY)
            if (currentElement !== this.previousElement) {

                // touch leave
                const leaveCallback = this.leaveElementCallback.get(this.previousElement)
                if (leaveCallback) {
                    leaveCallback.call(null, this.previousElement)
                }

                // touch enter
                const enterCallback = this.enterElementCallback.get(currentElement)
                if (enterCallback) {
                    enterCallback.call(null, currentElement)
                }

                // Current element will be the previous one, next time we check.
                this.previousElement = currentElement;
            }
        });
    },
    onEnter(element, callback) {
        this.enterElementCallback.set(element, callback);
    },
    onLeave(element, callback) {
        this.leaveElementCallback.set(element, callback);
    }
}

const mouseAvailable = matchMedia('(pointer:fine)').matches;

/**
 * Pointer is a wrapper for mouse and (simulated) touch events
 */
export const pointer = {
    mouseAvailable,

    init() {
        if (!mouseAvailable) {
            touchEventSimulator.init()
        }
    },

    onEnter: (element, callback) => {
        if (mouseAvailable) {
            element.addEventListener('mouseenter', ()=>callback.call(null, element))
        } else {
            touchEventSimulator.onEnter(element, callback)
        }
    },

    onLeave: (element, callback) => {
        if (mouseAvailable) {
            element.addEventListener('mouseleave', ()=>callback.call(null, element))
        } else {
            touchEventSimulator.onLeave(element, callback)
        }
    }
}

example.ts

import {pointer} from './pointer';

pointer.init();
const element = document.getElementById('test');
pointer.onEnter(anchor, element=>{
    console.log('enter', element)
})

pointer.onLeave(anchor, element=>{
    console.log('leave', element)
})