jQueryでフォーム入力中に誤ってページを移動(離脱)するのを防止する方法


  • 公開:
  • 更新:
  • 編集:
概要 ▶ jQueryでbeforeunloadイベントを使用することでページ移動の前に処理をさせることができます。これを使ってフォームから意図しないページ移動を防ぐことができます。

今回もフォームの最適化について書いていこうと思います。


先日の「【Web制作】フォームの最適化しようと、いくつか表現を変えてみたテスト【初心者向け】(画像あり)」という記事の引用の中で紹介した「こんなにあった!シニア対応を本気で進める『皇潤』の入力フォームが使いやすい理由」(マミオン有限会社)のページで以下のアドバイスが書かれていました。

シニアのフォーム入力操作を観察していると、誤ってページから離脱してしまい、再びフォームのページに戻ったら最初から全部やりなおし…という悲しいシーンによく遭遇します。フォームからフォーカスが外れた状態なのに気付かず、文字を修正しようとしてbackspaceキーを押してしまうのです。

こうした悲劇を防ぐためには、上記のHOME’S介護のように確認メッセージを出す方法がよいでしょう。実装方法も簡単なので、費用対効果が高い対策ですね。

[jQuery] ページを離れる際に確認メッセージを出す方法(18th Tech Note)

こんなにあった!シニア対応を本気で進める『皇潤』の入力フォームが使いやすい理由 | マミオン有限会社-シニアマーケティング、ウェブユーザビリティ評価

なるほど。Backspaceキーが「前のページに戻る」のショートカットキーになっていることに気がつかずに、または、意図せずショートカットキーの機能が有効になってページを移動してしまうというわけですね。


これは確かにストレスになります。


早速紹介されていたページを見て、jQueryのスクリプトを見てみました。

これはこのままでも使えるので、皆さん使ってみると良いと思います。

ページを移動しようとすると、以下の様な「このページから移動しますか? 入力したデータは保存されません。[このページから移動する][このページに留まる]」という確認用のダイアログが出てきます(画面はFirefox)。

20141218-jQueryでフォームページを移動する時に確認する-01


ですが、個人的な見地から、もう少し修正すると更に良くなると考えたので、修正版を公開します。

●「入力を始めたけどやっぱりやめた!はスルーする」を追加

フォームに入力をし始めたけど、やっぱりや~めた!とちょっと書いたフォームの内容をを消してページを移動しようとしたら、先程の確認用のダイアログが出てきたら、ちょっとイラッとしませんか?

確認用のダイアログが出て足止めをしたとしても、「せっかくだから書くか!」とはならないと思います。


というわけで「入力を始めたけどやっぱりやめた!はスルーする」を追加したスクリプトです。要jQuery 1.7以上です。

$(function(){
    // via [jQuery] ページを離れる際に確認メッセージを出す方法 http://www.18th-technote.com/?p
=1447 を修正
    // フォームの入力欄が更新されたかどうかを表すフラグです。
    var isChanged = false;

    $(window).on("beforeunload", function() {
        if (isChanged) {
            // isChangedフラグがtrueの場合、つまり入力内容が変更されていた
            // 場合のみ文字列を返すようにします。
            return "このページを離れようとしています。";
        }
    });

    $("input, select, textarea").on("keyup change",function() {
        // 入力内容が更新されている場合は、isChangedフラグをtrueにします。
        // ただし、DEL・BSキーで文字を削除して、
        // またはチェックボックスを外して全て空欄の場合もあるので、
        // フォームにある文字数をチェックします。
        // keypress keydownではDEL・BSキーを押した後の状態を判定できないのでkeyupを使います。
        // keyupだけだとチェックボックスをマウスでクリックした時に判定できないのでchangeも追加
します。
        var text_num = 0;
        for (var i=0; i< $("input[typ
e='text']").length; i++) {
            text_num +=  $("input[type='text']").eq(i).val().length;
        }
        for (var i=0; i< $("input[typ
e='email']").length; i++) {
            text_num += $("input[type='email']").eq(i).val().length;
        }
        for (var i=0; i< $("input[typ
e='number']").length; i++) {
            text_num += $("input[type='number']").eq(i).val().length;
        }
        for (var i=0; i< $("input[typ
e='tel']").length; i++) {
            text_num += $("input[type='tel']").eq(i).val().length;
        }
        for (var i=0; i< $("input[typ
e='checkbox']:checked").length; i++) {
            text_num += $("input[type='checkbox']:checked").eq(i).val().length;
        }
        for (var i=0; i< $("textarea"
).length; i++) {
            text_num += $("textarea").eq(i).val().length;
        }

        if (text_num > 0 ) {
            isChanged = true;
        } else {
            isChanged = false;
        }
    });

    $("[type=submit]").on("click",functio
n() {
        // フォームをサブミットする前にフラグを落とします。
        // ※ これをやらないと、サブミット時に確認メッセージが表示されてしまいます。
        isChanged = false;
    });
});


●変更点についての解説

変更した点は以下の通りです。

  • 「.bind」「.change」「.click」を「.on」の記述に変更
  • イベントの発生を「change」から「keyup」と「change」に変更
  • input・textareaの要素それぞれの文字数を調べて入力を判定
  • submit用の要素がbuttonになっていたので、限定しないように削除


.bind・.change・.clickでも全然構わないのですが、jQuery 1.7以降で実装された.on・.offを使うことで、「keyup」「change」のいずれのイベントにも付けたい場合の処理も「.on("keyup change",function() {..})」と簡単に書くことができました。


イベントの発生ですが、今回はBackspaceやDeleteキーで文字を削除した場合のことを考えています。「change」のイベントはあくまで「フォームからフォーカスが外れた瞬間(blur)に発生するイベント」ですので、フォームの要素内で文字を書いている時にはイベントが発生しません。

キー入力を監視してイベントを発生させなければ今回の目的は達成できません。

キー入力のイベントには「keyup」以外に「keydown」「keypress」がありますが、BackspaceやDeleteキーで文字を削除した後の状態を判定できません。keydown・keypressでは削除される前の状態が取得されてしまうので、文字が削除されたかわからないのです。このためkeyupを使用しています。

changeのイベントを残しているのはチェックボックスを操作した時のイベントを拾うためです。


文字入力されているかどうかは各要素の文字数を合計して、0文字の場合はスルー(入力動作なしとみなす)して、0文字より多いの場合(1文字でも入力されている場合、またはcheckboxにチェックが付いている場合)は入力動作がなされたと判定して、beforeunloadのイベント発生時にページ移動の確認のダイアログを表示するようにします。


元のスクリプトではsubmitする場合の要素が「button[type='submit']」となっており、input要素で作ったsubmitのボタンが対象外だったので、buttonを外しました。



●Firefox・Chrome・Internet Explorerの確認用ダイアログの違いについて

Firefox・Chrome・Internet Explorerの確認用ダイアログの表示のされ方が違ったので、スクリーンショットを貼っておきます。


まずはFirefox。画面全体が暗くなり、画面のセンターに表示されます。

「このページから移動しますか? 入力したデータは保存されません。[このページから移動する][このページに留まる]」とダイアログに表示されます。

beforeunloadイベントに付けた「return "このページを離れようとしています。";」は無視されます。

20141218-jQueryでフォームページを移動する時に確認する-01


そしてChrome。画面は暗転せず、アドレスバー近くに表示されます(画面上部)。

「ナビゲーションの確認 このページを離れようとしています。 このページから移動してもよろしいですか?[このページを離れる][このページにとどまる]」とダイアログに表示されます。

20141218-jQueryでフォームページを移動する時に確認する-03



そしてInternet Explorer。

「このページから移動しますか? Webページからのメッセージ:このページを離れようとしています。[このページから移動][ページに留まる]」とダイアログに表示されます。

なんと完全なモーダルダイアログで、このダイアログを処理しない限り(どちらかの選択肢をクリックしない限り)、Internet Explorerの操作ができなくなります(笑)。

いや、まぁ強制力があるのはいいんだけどね。

20141218-jQueryでフォームページを移動する時に確認する-02


こんな感じで三者三様の表現のされ方をするので注意が必要です。



●まとめ

フォーム入力はスクリプトによって、ユーザーの意図していなかった離脱を防ぐことができます。

特に記入欄の多いフォームでは、精神的ダメージが大きいので、上手に活用してストレスのないフォーム入力をしてもらいましょう!


それでは。



●補足

スクリプトの中でcheckboxの値の文字数も判定していますが、最初からチェックを付ける「checked」「checked="checked"」を使用していると、初期状態から文字数が0より大きくなるので誤判定します。

カテゴリー:

このページをぜひシェアしてください