[Javascript] Quickly.js : Touch Device에서 Click Delay를 없애는 Library.
실제로 테스트를 해보면 약 300~500ms 정도의 Delay가 존재한다.
버튼에 클릭 효과가 발생할 때까지 300~500ms 정도의 Delay가 발생한다면 사용자가 답답하다고 느낄 수 있기 때문에 터치가 시작되는 시점에 클릭 효과를 추가하고 터치가 끝나는 시점에 클릭 효과를 제거하는 방법으로 Delay를 제거할 수 있다.
이러한 작업을 위해 iScroll의 개발자로 유명한 Matteo Spinell씨가 NoClickDelay라는 Object를 만들어놨다. (http://cubiq.org/remove-onclick-delay-on-webkit-for-iphone)
하지만 실제로 사용해보니 약간의 버그?(터치가 시작되는 Element와 터치가 끝나는 Element가 서로 다를 경우 추가된 css class가 제대로 제거되지 않는 문제)가 있고 PC 환경은 지원하지 않기 때문에 모바일/PC 환경에서 동일하게 사용할 수 있도록 Quickly라는 이름으로 Custom 하였다.
PS) touchend/mouseup 이벤트 리스너를 클릭된 element가 아닌 window object에 등록하였기 때문에 터치가 시작되는 Element와 터치가 끝나는 Element가 달라도 정상 동작한다.
- Source Code -
https://github.com/RegularMotion/Quickly/
- Demo -
- 사용법 -
1. new Quickly(‘element_id’);
Element의 ID 또는 Element Object를 이용하여 Quickly Object를 생성한다.
- 내부동작 -
1. 터치/클릭 이벤트가 시작되는 시점에 element에 clicked Class를 추가.
2. 터치/클릭 이벤트가 끝나는 시점에 element에서 clicked Class 제거.
- clicked CSS Class 정의 -
div#element_id {
position: relative;
margin: 0 auto;
top: 25px;
width: 150px;
height: 150px;
background: #548937;
}
div#element_id.clicked {
opacity: .5;
}
- Javascript 구현부 -
function Quickly(el, callback) {
this.callback = callback;
this.clicked = (typeof el === 'object')? el : document.getElementById(el);
this.clicked.addEventListener(Quickly.EVT_START, this, false);
}
Quickly.isTouch = ('ontouchstart' in window)? true : false;
Quickly.EVT_START = Quickly.isTouch? 'touchstart' : 'mousedown';
Quickly.EVT_END = Quickly.isTouch? 'touchend' : 'mouseup';
Quickly.prototype = {
handleEvent: function(e) {
switch (e.type) {
case Quickly.EVT_START: this.onTouchStart(e); break;
case Quickly.EVT_END: this.onTouchEnd(e); break;
}
e.stopPropagation();
e.preventDefault();
},
onTouchStart: function(e) {
this.clicked.className += (this.clicked.className === '')? 'clicked':' clicked';
document.documentElement.addEventListener(Quickly.EVT_END, this, false);
},
onTouchEnd: function(e) {
document.documentElement.removeEventListener(Quickly.EVT_END, this, false);
if ( this.clicked ) this.clicked.className = this.clicked.className.replace(/ ?clicked/gi, '');
if ( typeof this.callback === 'function' ) this.callback(e);
}
};
new Quickly('element_id || dom element', function(e) {
});
- Hover Effect까지 처리해주는 Version -
function Quickly(el, callback) {
this.callback = callback;
this.clicked = (typeof el === 'object')? el : document.getElementById(el);
this.subscribe(Quickly.EVT_START, this.clicked);
if ( !Quickly.isTouch ) {
this.hovered = this.clicked;
this.subscribe(Quickly.EVT_HOVER, this.hovered);
}
}
Quickly.isTouch = ('ontouchstart' in window)? true : false;
Quickly.EVT_START = Quickly.isTouch? 'touchstart' : 'mousedown';
Quickly.EVT_END = Quickly.isTouch? 'touchend' : 'mouseup';
Quickly.EVT_HOVER = Quickly.isTouch? null : 'mouseover';
Quickly.EVT_LEAVE = Quickly.isTouch? null : 'mouseout';
Quickly.prototype = {
handleEvent: function(e) {
switch (e.type) {
case Quickly.EVT_START: this.onTouchStart(e); break;
case Quickly.EVT_END : this.onTouchEnd(e); break;
case Quickly.EVT_HOVER: this.onHovered(e); break;
case Quickly.EVT_LEAVE: this.onLeaved(e); break;
}
e.stopPropagation();
e.preventDefault();
},
onTouchStart: function(e) {
this.clicked.className += (this.clicked.className === '')? 'clicked':' clicked';
this.subscribe(Quickly.EVT_END);
},
onTouchEnd: function(e) {
this.unsubscribe(Quickly.EVT_END);
if ( this.clicked ) this.clicked.className = this.clicked.className.replace(/ ?clicked/gi, '');
if ( typeof this.callback === 'function' ) this.callback(e);
},
onHovered: function(e) {
this.hovered.className += (this.hovered.className === '')? 'hovered':' hovered';
this.subscribe(Quickly.EVT_LEAVE, this.hovered);
},
onLeaved: function(e) {
this.unsubscribe(Quickly.EVT_LEAVE, this.hovered);
this.hovered.className = this.hovered.className.replace(/ ?hovered/gi, '');
},
subscribe: function(event, el) {
var element = el || document.documentElement;
element.addEventListener(event, this, false);
},
unsubscribe: function(event, el) {
var element = el || document.documentElement;
element.removeEventListener(event, this, false);
}
};


