ボタンの二度押しをwait画面でガードしてみた。

2022年4月19日

以前フォームの二重送信をガードする方法について書いた記事があります。

これは、ブラウザの更新ボタン(F5ボタン)連打をガードする方法です。

ただこの方法でもガードできない事象があります。

それは「送信ボタン連打」です。

画面が切り替わる前に送信ボタンを連打すると、重複起動が発生し誤動作することがあります。
しかもページが重いと余計にボタン連打されやすくなります。

利用される方の身になって考えれば、ボタンを押しても画面が切り替わらなかったら、失敗したのかと思って再度ボタンを押すものです。

今回はこのボタン連打を、どうすればガードできるかについて考え実践しました。
またご参考になれば幸いです。

ひらめいたのは「お待ちください画面表示」でボタンを押せなくする方法

やり方はいろいろ考えられます。
例えばボタンを1回押したらJqueryで無効化して押せなくする、1回押したら非表示にするなどです。

でもこれだと、aタグ(リンクタグ)での対応が難しいです。

そこで思いついたのが、「お待ちください画面」を最前面に表示して強制的にボタンが押せなくする方法です。

表示ページの最前面に、強制的に別の内容で覆いかぶせれば操作ができなくなります。
スマートホンでホームページを見ている際に、メニューボタンを押した後に表示されるメニューボタンのイメージです。(メニューは押せるけれどもともとのリンク等は押せなくなる)

これなら上手くいくのではないかと思い、実践しました。

実際にできたものがこちらです

ボタンの二度押しをガードするサンプル

サンプルは、ボタンを押すと「お待ちください」画面が表示されます。
その間はもともとのボタンが押せなくなります。

切り替わったページ表示時に「お待ちください画面」を出す手法がありますが、今回はページ切り替え前に先に「お待ちください画面」を出すという方法です。

※サンプルは効果がわかりやすいように、2秒間のwait処理が入っています。

ボタンを押したらお待ちくださいを表示する仕組み

今回の仕掛けについて解説いたします。
まずは原理について解説します。

今回の方法は以下の2つの仕掛けがあります

  • CSSで「お待ちください」画面を「非表示状態」で作っておく
  • Jqueryでボタンが押されたら「お待ちください画面」を表示状態にする

これだけです。

Jqueryには.show()関数があります。
この関数は「非表示状態」のものを「表示状態」にします。

ボタンが押されたタイミングで.show()をコールするだけです。
Jqueryの処理としては、基本的な処理だけでできます。

ソースはこちらです

<!doctype html><html><head><metacharset="shift_jis"><title></title><styletype="text/css">#wait
{
position: fixed;
	z-index: 999999;
	top: 0px;
	left: 0px;
	width: 100%;
	height: 100%;

display: none;

/** 全画面の背景色 */background-color: rgba(0, 0, 0, 0.8);
	padding-top: 70px;
	text-align: center;
}

#wait.wak
{
	font-size: 24px;
	font-weight: normal;
	line-height: 140%;
	color: #FFF;
	display: inline-block;
	text-align: center;

	padding-top: 20px;
	padding-right: 40px;
	padding-bottom: 20px;
	padding-left: 40px;

	border: 1px solid #999;
	border-radius: 6px;
	-webkit-border-radius: 6px;
	-moz-border-radius: 6px;
}

body
{
	text-align: center;
}

a
{
	background: #ffffff; /* Old browsers */background: -moz-linear-gradient(top,  #ffffff 0%, #f1f1f1 50%, #e1e1e1 51%, #f6f6f6 100%); /* FF3.6-15 */background: -webkit-linear-gradient(top,  #ffffff 0%,#f1f1f1 50%,#e1e1e1 51%,#f6f6f6 100%); /* Chrome10-25,Safari5.1-6 */background: linear-gradient(to bottom,  #ffffff 0%,#f1f1f1 50%,#e1e1e1 51%,#f6f6f6 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#f6f6f6',GradientType=0 ); /* IE6-9 */display: inline-block;
	padding-top: 20px;
	padding-right: 30px;
	padding-bottom: 20px;
	padding-left: 30px;
	border: 1px solid #333;
	color: #333;
	text-decoration: none;
	border-radius: 6px;
	-webkit-border-radius: 6px;
	-moz-border-radius: 6px;
}

a:hover
{
	background: #ffffff; /* Old browsers */background: -moz-linear-gradient(top,  #ffffff 0%, #f3f3f3 50%, #ededed 51%, #ffffff 100%); /* FF3.6-15 */background: -webkit-linear-gradient(top,  #ffffff 0%,#f3f3f3 50%,#ededed 51%,#ffffff 100%); /* Chrome10-25,Safari5.1-6 */background: linear-gradient(to bottom,  #ffffff 0%,#f3f3f3 50%,#ededed 51%,#ffffff 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#ffffff',GradientType=0 ); /* IE6-9 */
}

</style><scriptsrc="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script><script>
$(document).ready(function()
{
	$("a").click(function()
	{
		$("#wait").show();
	});
});
</script></head><body><h1>1ページ目</h1><p></p><ahref="02.html"></a><!-- お待ちください画面 --><divid="wait"><divclass="wak"><divclass="icon"><imgsrc="default.svg"width="100"height="100"></div><p><br></p></div></div><!-- お待ちください画面ここまで --></body></html>Code language:HTML, XML(xml)

部分的に解説いたします

ソースは全体を見るとよくわかりませんが、部分的にみるとわかりやすくなります。
部分的に解説いたします。

(1)お待ちください画面

お待ちください画面は、CSSだけで作ります。
fixedにすることで、強制的に前面に表示させています。

■HTML部分

<!-- お待ちください画面 --><divid="wait"><divclass="wak"><divclass="icon"><imgsrc="default.svg"width="100"height="100"></div><p><br></p></div></div><!-- お待ちください画面ここまで -->Code language:HTML, XML(xml)

■CSS部分

#wait
{
position: fixed;
	z-index: 999999;
	top: 0px;
	left: 0px;
	width: 100%;
	height: 100%;

display: none;

/** 全画面の背景色 */background-color: rgba(0, 0, 0, 0.8);
	padding-top: 70px;
	text-align: center;
}

#wait.wak
{
	font-size: 24px;
	font-weight: normal;
	line-height: 140%;
	color: #FFF;
	display: inline-block;
	text-align: center;

	padding-top: 20px;
	padding-right: 40px;
	padding-bottom: 20px;
	padding-left: 40px;

	border: 1px solid #999;
	border-radius: 6px;
	-webkit-border-radius: 6px;
	-moz-border-radius: 6px;
}Code language:CSS(css)

お待ちください画面で重要なのは以下の7行のcssです。

position: fixed;
z-index: 999999;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
display: none;

これを記述しておけばOKです。
あとは好みの装飾をするだけです。
最初は「非表示」にしておくことも肝要です。

(2)Jquery部分

$(document).ready(function()
{
	$("a").click(function()
	{
		$("#wait").show();
	});
});Code language:JavaScript(javascript)

aタグがクリックされたら「お待ちください画面」を表示に切り替えています。

この2つの仕掛けでボタン連打をガードできるようになります。
なぜならば、1回押したあとに「お待ちください画面」が最前面に表示されるため、ボタンが強制的に押せなくなるためです。

疑問:_blankリンクをクリックした場合wait画面が表示中のままになりませんか?

今回の方法は、ボタンクリックで強制的に「お待ちください画面」を表示します。
これは、ページが切り替わることが前提のため「お待ちください画面」を消す必要がないからです。

ところが、target="_blank" (別ウィンドウで表示)にしてしまうと、元画面は「お待ちください画面」表示中のまま固まってしまいます。

_blankを使わなければそれでよいのですが、それでも具合の悪い現象です。
これを何とかする方法はないものでしょうか?

今回、二度押しガード処理を作っていく中で、_blankで「お待ちください画面」で固まる現象についても確認しました。

これに関しても、うまい対処方法があります。
そのやり方については、次回解説いたします。

今回のレポートは以上です。
読んでいただいてありがとうございました。


ホームページに関するお悩み事やご相談事がございましたら私どもまでご連絡ください。 鋭意ご対応申し上げます。
ホームページのご提案もさせていただいております