「onclick」イベントを設定すると持続する
JavaScriptで「onclick」イベントは良く使われます。 例えば指定した要素をクリックしたら背景色が付くといったイベントを設定すると、スクリプト終了までその機能が持続します。 関数やメソッドは、呼んだ時に1度だけ実行されるものが多いですが、イベントの指定をすると何度でも実行されます。
あたりまえと思って扱っているイベントの設定ですが、これをキャンセルする必要が出て来ると、どうしたものかと迷います。 これはけっこう嵌る問題です。
キャンセルするには「何もしないイベント」を設定する
ある要素「element」として、これをクリックしたら背景色を赤にするコードは、以下の様なものです。
element.onclick=function(){ element.style.background='red'; }
このイベントがもう実行されない様にキャンセルしたい場合、「何もしないイベント」を、もう一度設定します。
element.onclick=function(){ ; }
「element」に「onclick」イベントは1個しか設定できません。 従って、新たにイベントを設定するとそれに上書きされて、それまでのイベントは実行されなくなります。 これがイベントのキャンセル方法です。
Google検索のページを使ったサンプル
以下のコードは Google検索のページで、検索結果の項目(ページに10件程度)をクリックすると、それに背景色が付くスクリプトです。 クリックの度に何度でも実行が可能な事を示すために、背景色は1sec後に消える様にしています。
サンプルコード(1)
// ==UserScript==
// @name Test in Google Search Page
// @namespace http://tampermonkey.net/
// @version 0.1
// @description イベントをキャンセルする
// @author You
// @match https://www.google.com/search*
// @grant none
// ==/UserScript==
( function() {
let k;
let search_item=document.querySelectorAll('#rso .g');
if(search_item.length !=0){
for(k=0; k<search_item.length; k++){
set_event(k); }}
function set_event(n){
search_item[n].onclick=function(e){
e.preventDefault();
search_item[n].style.background='#b2ebf2';
setTimeout( function(){
search_item[n].style.background=''; }, 1000); }}
})();
下は、実際に「Tampermonkey」にコードをコピーして試してみた所です。 一度何かを適当に検索をして、検索された項目をクリックします。
![](https://stat.ameba.jp/user_images/20190812/16/personwritep/3c/dc/p/o0620034614532358628.png?caw=800)
この時、本来ならクリックするとページが飛ぶリンクをクリックしても、ページの遷移が生じません。 これは「.preventDefault();」を設定しているためです。
検索ページの項目は、何度クリックしても背景色が付いて消えます。 イベントを設定すると、半永久的に実行される事に注目してください。
スクリプト全体を ON/OFF する
この単純なスクリプトを、スイッチで ON/OFF させるコードを作ってみました。 スイッチには検索窓を利用し、これをクリックするごとにサンプルコード(1)のスクリプトがON/OFFする様にします。
サンプルコード(2)
// ==UserScript==
// @name Test in Google Search Page
// @namespace http://tampermonkey.net/
// @version 0.2
// @description イベントをキャンセルする
// @author You
// @match https://www.google.com/search*
// @grant none
// ==/UserScript==
( function() {
let k;
let mode=0;
let sw=document.querySelector(".SDkEP");
sw.onclick=function(){
if(mode==0){
mode=1;
do_color();
sw.style.background='#b2ebf2'; }
else if(mode==1){
mode=0;
undo_color();
sw.style.background=''; }}
function do_color(){
let search_item=document.querySelectorAll('#rso .g');
if(search_item.length !=0){
for(k=0; k<search_item.length; k++){
set_event(k); }}
function set_event(n){
search_item[n].onclick=function(e){
e.preventDefault();
search_item[n].style.background='#b2ebf2';
setTimeout( function(){
search_item[n].style.background=''; }, 1000); }}}
function undo_color(){
let search_item=document.querySelectorAll('#rso .g');
if(search_item.length !=0){
for(k=0; k<search_item.length; k++){
reset_event(k); }}
function reset_event(n){
search_item[n].onclick=function(e){ ; }}}
})();
コードは3つの部分に別れます。 最初の1/3は、検索窓をスイッチとするコードです。
やはり「onclick」を使い、「sw」がクリックされるたびに「mode」が「0」「1」と入れ替わるトグル動作としています。
この切換えを可視化するために、「mode=1」(ON)なら、検索窓に背景色が付き、同時に、次の関数「do_color()」を実行します。 この関数の中身は、先のサンプルコード(1) そのものです。
そして、「mode=0」(OFF)なら、最後の関数「undo_color()」を実行します。 これが問題の「イベントをキャンセル」する関数です。 上の「do_color()」と見比べると多くの部分が相似です。 そして、イベント内容だけが赤文字の「何もしない関数」の形になっています。
この関数は背景色を付けるコードのキャンセルだけでなく、リンクをクリックさせない様にする「preventDefault()」もキャンセルしています。 不適切なキャンセルの方法では、「mode=0」(OFF)にしてもリンクに飛ばない状態が残ってしまいます。
纏め
イベント設定をして、後でイベントをキャンセルする場合は、何もしないイベントを設定するのが正解です。