zoukankan      html  css  js  c++  java
  • REMOVE ONCLICK DELAY ON WEBKIT FOR IPHONE

    Developing on the webkit for iPhone I encountered a curious delay ononClick events. It seems that the click is triggered with about 300 milliseconds delay. While this is unnoticeable on a standard web page, it can be annoying on a web application. Fortunately the click event can be overridden thus eliminating the delay.

    I assume that 300ms is the time frame Apple guesses an user needed to perform gestures, but there are situations where this delay can be really annoying. Think to a calculator application with 300ms delay each time you press a button. Unacceptable.

    The simplest solution is to use onTouchStart instead of onClick events. Something like <div ontouchstart="doSomething()"> is perfectly logical and overrides the onClick delay. But the action is triggered as soon as you touch the screen and may end up to undesirable results, so I tried to recreate the mouseDown/mouseUp events sequence with touchStart/touchMove/touchEnd.

    Point your iPhone or simulator to my demo page. Clicking on the first button the standard click event is fired (with infamous 300ms delay), the second button instead overrides the onClick event and the action is actually cast on touchEnd with no delay.

    The code I use is the following:

    function NoClickDelay(el) {
    	this.element = el;
    	if( window.Touch ) this.element.addEventListener('touchstart', this, false);
    }
    
    NoClickDelay.prototype = {
    	handleEvent: function(e) {
    		switch(e.type) {
    			case 'touchstart': this.onTouchStart(e); break;
    			case 'touchmove': this.onTouchMove(e); break;
    			case 'touchend': this.onTouchEnd(e); break;
    		}
    	},
    
    	onTouchStart: function(e) {
    		e.preventDefault();
    		this.moved = false;
    
    		this.element.addEventListener('touchmove', this, false);
    		this.element.addEventListener('touchend', this, false);
    	},
    
    	onTouchMove: function(e) {
    		this.moved = true;
    	},
    
    	onTouchEnd: function(e) {
    		this.element.removeEventListener('touchmove', this, false);
    		this.element.removeEventListener('touchend', this, false);
    
    		if( !this.moved ) {
    			// Place your code here or use the click simulation below
    			var theTarget = document.elementFromPoint(e.changedTouches[0].clientX, e.changedTouches[0].clientY);
    			if(theTarget.nodeType == 3) theTarget = theTarget.parentNode;
    
    			var theEvent = document.createEvent('MouseEvents');
    			theEvent.initEvent('click', true, true);
    			theTarget.dispatchEvent(theEvent);
    		}
    	}
    };

    The script creates a touchStart event and performs the click action on touchEnd which occurs 300ms before the standard click event. This is just an example to get you started, my function triggers the click event on touchEnd so you still need to add an onClick event (or an Anchor) somewhere if you want something to happen. You could better place directly your code on touchEnd but if you use my method your application will be compatible with both touch (the iphone) and non-touch enabled devices (the standard browser).

    To activate the script all you need to do is: new NoClickDelay(document.getElementById('element'));. From now on all your clicks inside the element will be performed with no delay.

    Note that you don’t need to apply the NoClickDelay() function to all the objects in the page, but just to a container. If for instance you have an unordered list, you don’t need to add the script to each <li>elements, but just to the <ul>. This has been done to reduce the number of event listeners so less resources are needed.

    To closely mimic the standard UI you could add a hover class on touchStart to highlight the pressed object in someway and remove it on touchMove. (Apple places a gray rectangle over pressed elements).

    Update 2009/02/27: By popular demand here follows the code that assigns the “pressed” CSS class to the clicked element.

    function NoClickDelay(el) {
    	this.element = typeof el == 'object' ? el : document.getElementById(el);
    	if( window.Touch ) this.element.addEventListener('touchstart', this, false);
    }
    
    NoClickDelay.prototype = {
    	handleEvent: function(e) {
    		switch(e.type) {
    			case 'touchstart': this.onTouchStart(e); break;
    			case 'touchmove': this.onTouchMove(e); break;
    			case 'touchend': this.onTouchEnd(e); break;
    		}
    	},
    
    	onTouchStart: function(e) {
    		e.preventDefault();
    		this.moved = false;
    
    		this.theTarget = document.elementFromPoint(e.targetTouches[0].clientX, e.targetTouches[0].clientY);
    		if(this.theTarget.nodeType == 3) this.theTarget = theTarget.parentNode;
    		this.theTarget.className+= ' pressed';
    
    		this.element.addEventListener('touchmove', this, false);
    		this.element.addEventListener('touchend', this, false);
    	},
    
    	onTouchMove: function(e) {
    		this.moved = true;
    		this.theTarget.className = this.theTarget.className.replace(/ ?pressed/gi, '');
    	},
    
    	onTouchEnd: function(e) {
    		this.element.removeEventListener('touchmove', this, false);
    		this.element.removeEventListener('touchend', this, false);
    
    		if( !this.moved && this.theTarget ) {
    			this.theTarget.className = this.theTarget.className.replace(/ ?pressed/gi, '');
    			var theEvent = document.createEvent('MouseEvents');
    			theEvent.initEvent('click', true, true);
    			this.theTarget.dispatchEvent(theEvent);
    		}
    
    		this.theTarget = undefined;
    	}
    };

    Are you aware of any simpler solution?

    /SHARE THE JOY

    /REACTIONS

        • AUTHOR: CONSTANTINE MUREEV
        • POSTED ON: 2012/08/20
        • AT: 08:25
        • AUTHOR: LUIS
        • POSTED ON: 2012/08/26
        • AT: 15:06

        hi,

        I’ve tried your code to improve the behavior of the JQM events and the delay which they have after clicking a button element, but I have a problem: after clicking the class ui-btn-active is still on the element and it isn’t removed. I’m not a totally newbie on JQ but, but I’m learning about the events handler, so, I’ll appreciate a little help.

        Thanks in advance!
        Luis Miguel.

        REPLY
      • Great bit of code.

        I modified it a bit to allow the finger to move up to 50 pixels before canceling the click.

        I am confused with .prototype. It seems that somehow handleEvent gets called. How?


        function NoClickDelay(el) {
        this.element = typeof el == 'object' ? el : document.getElementById(el);
        if( window.Touch ) this.element.addEventListener('touchstart', this, false);
        }

        NoClickDelay.prototype = {
        handleEvent: function(e) {
        switch(e.type) {
        case 'touchstart': this.onTouchStart(e); break;
        case 'touchmove': this.onTouchMove(e); break;
        case 'touchend': this.onTouchEnd(e); break;
        }
        },
        onTouchStart: function(e) {
        e.preventDefault();
        this.moved = false;
        this.x = e.targetTouches[0].clientX;
        this.y = e.targetTouches[0].clientY;
        this.theTarget = document.elementFromPoint(e.targetTouches[0].clientX, e.targetTouches[0].clientY);
        if(this.theTarget.nodeType == 3) this.theTarget = theTarget.parentNode;
        this.theTarget.className+= ' pressed';
        this.element.addEventListener('touchmove', this, false);
        this.element.addEventListener('touchend', this, false);
        },
        onTouchMove: function(e) {
        var x = e.targetTouches[0].clientX;
        var y = e.targetTouches[0].clientY;
        if( Math.sqrt(Math.pow(x-this.x,2)+Math.pow(y-this.y,2))>50){
        this.moved = true;
        this.theTarget.className = this.theTarget.className.replace(/ ?pressed/gi, '');
        this.theTarget.className = this.theTarget.className.replace(/ ?active/gi, '');
        } else {
        if(this.moved==true){
        this.moved=false;
        this.theTarget.className+= ' pressed';
        }
        }
        },
        onTouchEnd: function(e) {
        this.element.removeEventListener('touchmove', this, false);
        this.element.removeEventListener('touchend', this, false);
        if( !this.moved && this.theTarget ) {
        this.theTarget.className = this.theTarget.className.replace(/ ?pressed/gi, '');
        this.theTarget.className+= ' active';
        var theEvent = document.createEvent('MouseEvents');
        theEvent.initEvent('click', true, true);
        this.theTarget.dispatchEvent(theEvent);
        }
        this.theTarget = undefined;
        }
        };

        REPLY
        • AUTHOR: NIK LINDERS
        • POSTED ON: 2013/01/04
        • AT: 09:32

        Nice script! I made it into a jQuery plug-in and added a function to make the script set focus on the element selected after firing the click event. I found this fixes an issue where input fields are not properly selected on an iPhone if they are within the NoClickDelay element.

        Code:

        (function( $ ) {
        $.fn.noClickDelay = function() {

        var $wrapper = this;
        var $target = this;
        var moved = false;

        $wrapper.bind('touchstart mousedown',function(e) {
        e.preventDefault();
        moved = false;
        $target = $(e.target);
        if($target.nodeType == 3) {
        $target = $($target.parent());
        }
        $target.addClass('pressed');

        $wrapper.bind('touchmove mousemove',function(e) {
        moved = true;
        $target.removeClass('pressed');
        });

        $wrapper.bind('touchend mouseup',function(e) {
        $wrapper.unbind('mousemove touchmove');
        $wrapper.unbind('mouseup touchend');
        if(!moved && $target.length) {
        $target.removeClass('pressed');
        $target.trigger('click');
        $target.focus();
        }
        });
        });

        };
        })( jQuery );

        Use as such:
        $('#wrapperElement').noClickDelay();

        REPLY
        • AUTHOR: MUNDI
        • POSTED ON: 2013/01/26
        • AT: 22:55

        I my iphone4 I get a click delay of 560ms!!

        What are apple smoking?

        Even with your improvement its still 153ms seconds… better than 560.

        REPLY
         
         
        http://cubiq.org/remove-onclick-delay-on-webkit-for-iphone
  • 相关阅读:
    域名解析速度好快了。
    ASP生成图形(数字验证码)
    PHP过滤字符
    “树人杯”暨第三届辽宁科技大学校园程序设计竞赛正赛F 最后一个是谁?(紫)
    “树人杯”暨第三届辽宁科技大学校园程序设计竞赛正赛G 又是一个小游戏(蓝)
    面试题06 判断二叉树后序遍历的结果 [树]
    [acm] 动态规划相关的题目 [ 个人 ]
    [面试备] 暴搜 or 二分图的经典升级 : hdu 1045 Fire Net 示例 [ 二分图 ]
    面试题02 从上往下打印二叉树 【树】[ water ]
    面试题05 树的子结构 [树]
  • 原文地址:https://www.cnblogs.com/canphp/p/5006273.html
Copyright © 2011-2022 走看看