Google で見つけた高速ボタン コードを実装しようとしています。
Google の Fast Button を実装しようとしている
現在、Uncaught TypeError: Cannot read property 'addEventListener' of null. が発生しています。この高速ボタン ロジックおよび/または addEventListener を実装する方法を教えてください。
回答: ページ要素がロードされた後に NewButton を定義します。
<html>
<head>
<title>Button</title>
<script src="/js/fastbutton.js"></script>
<script type="text/javascript">
new FastButton(document.getElementById('fastButton'), function() {
num = num + 1;
document.getElementById("outputText").value = num;
});
var num = 0;
function slowButton() {
num = num + 1;
document.getElementById("outputText").value = num;
}
</script>
</head>
<body>
Output: <input id="outputText" type="text"></input>
<button id="fastButton">Fast Button</button>
<button onclick="slowButton();">Slow Button</button>
</body>
</html>
JS コード:
(function() {
/**
* From: http://code.this.com/mobile/articles/fast_buttons.html
* Also see: https://stackoverflow.com/questions/6300136/trying-to-implement-googles-fast-button
*/
/** For IE8 and earlier compatibility: https://developer.mozilla.org/en/DOM/element.addEventListener */
function addListener(el, type, listener, useCapture) {
if (el.addEventListener) {
Uncaught TypeError: Cannot read property 'addEventListener' of null
el.addEventListener(type, listener, useCapture);
return {
destroy: function() { el.removeEventListener(type, listener, useCapture); }
};
} else {
// see: https://stackoverflow.com/questions/5198845/javascript-this-losing-context-in-ie
var handler = function(e) { listener.handleEvent(window.event, listener); }
el.attachEvent('on' + type, handler);
return {
destroy: function() { el.detachEvent('on' + type, handler); }
};
}
}
var isTouch = "ontouchstart" in window;
/* Construct the FastButton with a reference to the element and click handler. */
this.FastButton = function(element, handler, useCapture) {
// collect functions to call to cleanup events
this.events = [];
this.touchEvents = [];
this.element = element;
this.handler = handler;
this.useCapture = useCapture;
if (isTouch)
this.events.push(addListener(element, 'touchstart', this, this.useCapture));
this.events.push(addListener(element, 'click', this, this.useCapture));
};
/* Remove event handling when no longer needed for this button */
this.FastButton.prototype.destroy = function() {
for (i = this.events.length - 1; i >= 0; i -= 1)
this.events[i].destroy();
this.events = this.touchEvents = this.element = this.handler = this.fastButton = null;
};
/* acts as an event dispatcher */
this.FastButton.prototype.handleEvent = function(event) {
switch (event.type) {
case 'touchstart': this.onTouchStart(event); break;
case 'touchmove': this.onTouchMove(event); break;
case 'touchend': this.onClick(event); break;
case 'click': this.onClick(event); break;
}
};
/* Save a reference to the touchstart coordinate and start listening to touchmove and
touchend events. Calling stopPropagation guarantees that other behaviors don’t get a
chance to handle the same click event. This is executed at the beginning of touch. */
this.FastButton.prototype.onTouchStart = function(event) {
event.stopPropagation ? event.stopPropagation() : (event.cancelBubble=true);
this.touchEvents.push(addListener(this.element, 'touchend', this, this.useCapture));
this.touchEvents.push(addListener(document.body, 'touchmove', this, this.useCapture));
this.startX = event.touches[0].clientX;
this.startY = event.touches[0].clientY;
};
/* When /if touchmove event is invoked, check if the user has dragged past the threshold of 10px. */
this.FastButton.prototype.onTouchMove = function(event) {
if (Math.abs(event.touches[0].clientX - this.startX) > 10 || Math.abs(event.touches[0].clientY - this.startY) > 10) {
this.reset(); //if he did, then cancel the touch event
}
};
/* Invoke the actual click handler and prevent ghost clicks if this was a touchend event. */
this.FastButton.prototype.onClick = function(event) {
event.stopPropagation ? event.stopPropagation() : (event.cancelBubble=true);
this.reset();
// Use .call to call the method so that we have the correct "this": https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/call
var result = this.handler.call(this.element, event);
if (event.type == 'touchend')
clickbuster.preventGhostClick(this.startX, this.startY);
return result;
};
this.FastButton.prototype.reset = function() {
for (i = this.touchEvents.length - 1; i >= 0; i -= 1)
this.touchEvents[i].destroy();
this.touchEvents = [];
};
this.clickbuster = function() {}
/* Call preventGhostClick to bust all click events that happen within 25px of
the provided x, y coordinates in the next 2.5s. */
this.clickbuster.preventGhostClick = function(x, y) {
clickbuster.coordinates.push(x, y);
window.setTimeout(clickbuster.pop, 2500);
};
this.clickbuster.pop = function() {
clickbuster.coordinates.splice(0, 2);
};
/* If we catch a click event inside the given radius and time threshold then we call
stopPropagation and preventDefault. Calling preventDefault will stop links
from being activated. */
this.clickbuster.onClick = function(event) {
for (var i = 0; i < clickbuster.coordinates.length; i += 2) {
var x = clickbuster.coordinates[i];
var y = clickbuster.coordinates[i + 1];
if (Math.abs(event.clientX - x) < 25 && Math.abs(event.clientY - y) < 25) {
event.stopPropagation ? event.stopPropagation() : (event.cancelBubble=true);
event.preventDefault ? event.preventDefault() : (event.returnValue=false);
}
}
};
if (isTouch) {
// Don't need to use our custom addListener function since we only bust clicks on touch devices
document.addEventListener('click', clickbuster.onClick, true);
clickbuster.coordinates = [];
}
})(this);