スマホ対応!ページ離脱はjQueryのアラートで防ぐ!

プロモーションが含まれています

スマホ対応!ページ離脱はjQueryのアラートで防ぐ!

CV率アップ!ユーザーの離脱は、jQueryのアラート(ポップアップ)で防ぐ!
PCだけならbeforeunloadでできますが、iOSなどのスマホのブラウザでは、popstateやhashchangeをトリガーにして発火しないので、スマホでも動作するよう対策も。

サンプルを用意しました。

メールフォームサンプル
ユーザビリティ向上のためのメールフォームサンプルです。

jQuery関連記事

関連記事をもっとみる

ページ移動しようとしたらアラートを出す

JavaScript

$(window).on('beforeunload', function() {
  return "ページを移動しようとしています。\n入力した内容が失われますがよろしいですか?";
});

beforeunloadのイベントを使って処理します。離脱しようとしたらreturnの内容とともにalertが出ます。
途中で改行したい場合は\nで改行できます。
beforeunload不適切に使われることが多かった結果、IE/Edgeを除いて固定メッセージしか出せないようになっています。

フォームに入力したときだけ、ページ移動しようとしたらアラートを出す

JavaScript

changeFlg = false;
$(window).on('beforeunload', function() {
  if (changeFlg) {
    return "ページを移動しようとしています。\n入力した内容が失われますがよろしいですか?";
  }
});

$("form input, form textarea, form select").change(function() {
  changeFlg = true;
});

changeFlgで入力の有無でフラグを立て、フラグがある時のみbeforeunloadの処理をします。
.changeでフォームの部品が変更されたらフラグを立てます。

送信ボタンは除外する

JavaScript

$(function(){
  changeFlg = false;
  $(window).on('beforeunload', function() {
    if (changeFlg) {
      return "ページを移動しようとしています。\n入力した内容が失われますがよろしいですか?";
    }
  });

  $("form input, form textarea, form select").change(function() {
    changeFlg = true;
  });

  $("input[type=submit]").click(function() {
    changeFlg = false;
  });
});

上のままだと、送信ボタンを押したときでもアラートが出てしまうので、送信ボタンを押したときはchangeFlgを消しています。
ちなみにjQueryの本体が古いと動かない場合があるので1.9以上に上げると動くと思います。

スマホにも対応する

※2020/07追記
スマホ版が動かなかったので修正しました。
ただ、別ページへ移動・タブを閉じるでは処理されず、
戻る操作を行ったときにしか処理できません。

history.jsを準備する

Gitからhistory.jsをDLして、読み込んでください。

GitHub - browserstate/history.js: History.js gracefully supports the HTML5 History/State APIs (pushState, replaceState, onPopState) in all browsers. Including continued support for data, titles, replaceState. Supports jQuery, MooTools and Prototype. For HTML5 browsers this means that you can modify the URL directly, without needing to use hashes anymore. For HTML4 browsers it will revert back to using the old onhashchange functionality.
History.js gracefully supports the HTML5 History/State APIs (pushState, replaceState, onPopState) in all browsers. Including continued support for data, titles,...

history.jsは古いブラウザではpushStateやpopstateが対応していないので、それらに対応するためにHistoryライブラリをオーバライドするライブラリです。

Bootstrapを準備する

BootstrapをDLして、bootstrap.min.cssとbootstrap.min.jsを読み込んでください。

ダウンロード~Bootstrap5設置ガイド
Bootstrapをダウンロードして、コンパイル済のCSSやJavaScriptファイルやソースコードを入手したり、npm, RubyGemsなどの好きなパッケージマネージャーに追加する。

popstateやhashchangeをトリガーにして動かす処理が、スマホのブラウザでは、alertやconfirmは動作しません。
面倒なのでBootstrapのmodalを使ってアラートを表示しています。

モーダルを設置する

html

<div class="modal" tabindex="-1" role="dialog">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
      </div><!-- /.modal-header -->
      <div class="modal-body">
        <p>入力途中ですがキャンセルしてよろしいですか?</p>
      </div><!-- /.modal-body -->
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">いいえ</button>
        <button type="button" id="back" class="btn btn-primary">はい</button>
      </div><!-- /.modal-footer -->
    </div><!-- /.modal-content -->
  </div><!-- /.modal-dialog -->
</div><!-- /.modal -->

「はい」ボタンにidを振ってあります。

JavaScriptを設置する

JavaScript

$(function(){
  var hash = location.hash;
  if(hash != '#message') {
    // pushStateで現在のURLを履歴にスタックする
    history.pushState(null,null,location.href);
    // URLにtagを設置する
    location.hash = '#message';
  }
  // URLが変更されるのを監視
  $(window).on('popstate',function(event){
    if(location.hash != '#message') {
      // モーダルを実行
      $('#modal').modal('show');
    }
  });
  $('#back').click(function() {
    history.back();
    return false;
  });
});

処理的には一旦ページがロードされると、URLに#messageのアンカーを付けてpushStateで履歴をスタックする。
popstateでurlが変更されたときに処理を発火させて、戻るで#messageが消えたときにモーダルが起動。
その中でページを戻るかそのページにとどまるかを選択。
戻る場合は、history.back();で戻るようにしている。

コメント

  1. ビバ覇者 より:

    初めまして!
    現在ページ離脱防止の実装で、参考にさせていただいてます!

    DEMOページを見たのですが、
    スマホのsafariやchromeで見ても
    ダイアログが出てこないのですが、

    バージョンや仕様が変わったとか
    ありますでしょうか?

    • むぅ より:

      この記事を作成しているときにスマホは気にしていなかったのですが、この方法ではスマホは反応しないようです。
      pagehideで判別する必要があるみたいですがbeforeunloadとは挙動が違うようです。

タイトルとURLをコピーしました