以前フォームの二重送信をガードする方法について書いた記事があります。
これは、ブラウザの更新ボタン(F5ボタン)連打をガードする方法です。
ただこの方法でもガードできない事象があります。
それは「送信ボタン連打」です。
画面が切り替わる前に送信ボタンを連打すると、重複起動が発生し誤動作することがあります。
しかもページが重いと余計にボタン連打されやすくなります。
利用される方の身になって考えれば、ボタンを押しても画面が切り替わらなかったら、失敗したのかと思って再度ボタンを押すものです。
今回はこのボタン連打を、どうすればガードできるかについて考え実践しました。
またご参考になれば幸いです。
ひらめいたのは「お待ちください画面表示」でボタンを押せなくする方法
やり方はいろいろ考えられます。
例えばボタンを1回押したらJqueryで無効化して押せなくする、1回押したら非表示にするなどです。
でもこれだと、aタグ(リンクタグ)での対応が難しいです。
そこで思いついたのが、「お待ちください画面」を最前面に表示して強制的にボタンが押せなくする方法です。
表示ページの最前面に、強制的に別の内容で覆いかぶせれば操作ができなくなります。
スマートホンでホームページを見ている際に、メニューボタンを押した後に表示されるメニューボタンのイメージです。(メニューは押せるけれどもともとのリンク等は押せなくなる)
これなら上手くいくのではないかと思い、実践しました。
実際にできたものがこちらです
サンプルは、ボタンを押すと「お待ちください」画面が表示されます。
その間はもともとのボタンが押せなくなります。
切り替わったページ表示時に「お待ちください画面」を出す手法がありますが、今回はページ切り替え前に先に「お待ちください画面」を出すという方法です。
※サンプルは効果がわかりやすいように、2秒間のwait処理が入っています。
ボタンを押したらお待ちくださいを表示する仕組み
今回の仕掛けについて解説いたします。
まずは原理について解説します。
今回の方法は以下の2つの仕掛けがあります
- CSSで「お待ちください」画面を「非表示状態」で作っておく
- Jqueryでボタンが押されたら「お待ちください画面」を表示状態にする
これだけです。
Jqueryには.show()関数があります。
この関数は「非表示状態」のものを「表示状態」にします。
ボタンが押されたタイミングで.show()をコールするだけです。
Jqueryの処理としては、基本的な処理だけでできます。
ソースはこちらです
<!doctype html>
<html>
<head>
<meta charset="shift_jis">
<title>wait切り替え</title>
<style type="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>
<script src="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>下のボタンを押すと2秒後に次の画面へ移動します。</p>
<a href="02.html">次の画面へ移動</a>
<!-- お待ちください画面 -->
<div id="wait">
<div class="wak">
<div class="icon"><img src="default.svg" width="100" height="100"></div>
<p>処理しています<br>少々お待ちください</p>
</div></div>
<!-- お待ちください画面ここまで -->
</body>
</html>
部分的に解説いたします
ソースは全体を見るとよくわかりませんが、部分的にみるとわかりやすくなります。
部分的に解説いたします。
(1)お待ちください画面
お待ちください画面は、CSSだけで作ります。
fixedにすることで、強制的に前面に表示させています。
■HTML部分
<!-- お待ちください画面 -->
<div id="wait">
<div class="wak">
<div class="icon"><img src="default.svg" width="100" height="100"></div>
<p>処理しています<br>少々お待ちください</p>
</div></div>
<!-- お待ちください画面ここまで -->
■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;
}
お待ちください画面で重要なのは以下の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();
});
});
aタグがクリックされたら「お待ちください画面」を表示に切り替えています。
この2つの仕掛けでボタン連打をガードできるようになります。
なぜならば、1回押したあとに「お待ちください画面」が最前面に表示されるため、ボタンが強制的に押せなくなるためです。
疑問:_blankリンクをクリックした場合wait画面が表示中のままになりませんか?
今回の方法は、ボタンクリックで強制的に「お待ちください画面」を表示します。
これは、ページが切り替わることが前提のため「お待ちください画面」を消す必要がないからです。
ところが、target=”_blank” (別ウィンドウで表示)にしてしまうと、元画面は「お待ちください画面」表示中のまま固まってしまいます。
_blankを使わなければそれでよいのですが、それでも具合の悪い現象です。
これを何とかする方法はないものでしょうか?
今回、二度押しガード処理を作っていく中で、_blankで「お待ちください画面」で固まる現象についても確認しました。
これに関しても、うまい対処方法があります。
そのやり方については、次回解説いたします。