LoginSignup
8
5

More than 3 years have passed since last update.

Vue.jsでページ離脱時に「このサイトを離れますか?」を表示する

Last updated at Posted at 2020-06-04

このダイアログの表示機能をVueのmixinsとして実装していきます。

まず、あのアラート表示の実態はwindowオブジェクトのbeforeunloadイベントです。
それをEventListenerに登録/解除する処理をVue.jsのmixinsに切り出します。

ポイントを順番に解説していきます。
まず、ページ離脱時に出したい場合、Componentのライフサイクルフックではリロードなどに対応できないため、Vueのナビゲーションガードを用います。該当するのはbeforeRouteLeaveです。
beforeRouteLeaveはvue-class-componentを用いてComponentに登録することで使用することができます。
そのためmixins的な機能ですが、今回はvue-mixin-decoratorを使わず実装しました

Component.registerHooks(['beforeRouteLeave']);

beforeRouteLeaveでルーティングをブロックできるようにフラグを用意しておきます

  enabledWhenUnloadConfirm: boolean = false;

  beforeRouteLeave({ next }): void {
    if (this.enabledWhenUnloadConfirm) {
      next(false);
      return;
    }
    next();
  }

ダイアログの出現条件はそれぞれenableConfirm, disableConfirmを実行することで制御できるようにします。

  enableConfirm(): void {
    this.enabledWhenUnloadConfirm = true;
    window.addEventListener('beforeunload', this.onBeforeunloadHandler, false);
  }
  disableConfirm(): void {
    this.enabledWhenUnloadConfirm = false;
    window.removeEventListener(
      'beforeunload',
      this.onBeforeunloadHandler,
      false
    );
  }

Componentのライフサイクルフックに合わせてbeforeunloadイベントの登録と解除を自動的に行うようにしておきます

  created() {
    window.addEventListener('beforeunload', this.onBeforeunloadHandler, false);
  }
  beforeDestroy() {
    window.removeEventListener(
      'beforeunload',
      this.onBeforeunloadHandler,
      false
    );
  }

また、度々出現しているonBeforeunloadHandlerは自前の関数で、現在IEとEdgeのみですがダイアログのメッセージをカスタムできるのでしています。他ブラウザはセキュリティの観点でメッセージが固定されています。

  onBeforeunloadHandler(evt: BeforeUnloadEvent): void {
    evt.returnValue = '編集中の内容は失われます。よろしいですか?';
  }

これらをまとめた最終的なファイルは以下のようになります。

mixins/ConfirmWhenUnload.ts
import Vue from 'vue';
import Component from 'vue-class-component';

Component.registerHooks(['beforeRouteLeave']);

@Component
export default class ConfirmWhenUnload extends Vue {
  enabledWhenUnloadConfirm: boolean = false;

  created() {
    window.addEventListener('beforeunload', this.onBeforeunloadHandler, false);
  }
  beforeDestroy() {
    window.removeEventListener(
      'beforeunload',
      this.onBeforeunloadHandler,
      false
    );
  }
  beforeRouteLeave({ next }): void {
    if (this.enabledWhenUnloadConfirm) {
      next(false);
      return;
    }
    next();
  }
  onBeforeunloadHandler(evt: BeforeUnloadEvent): void {
    evt.returnValue = '編集中の内容は失われます。よろしいですか?';
  }
  enableConfirm(): void {
    this.enabledWhenUnloadConfirm = true;
    window.addEventListener('beforeunload', this.onBeforeunloadHandler, false);
  }
  disableConfirm(): void {
    this.enabledWhenUnloadConfirm = false;
    window.removeEventListener(
      'beforeunload',
      this.onBeforeunloadHandler,
      false
    );
  }
}

これを、ダイアログを表示したいページで呼んで適宜

this.enableConfirm();
this.disableConfirm();

を実行することでダイアログの出現を制御できるようになります :tada:

8
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
5