Help us understand the problem. What is going on with this article?

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

このダイアログの表示機能を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:

kimuchan
AWS(SAA取得)/ TypeScript/ Nuxt.js/ Vue.js/ Vuetify/ Ruby on Rails/ Laravel/ Selenium WebDriver フルスタックエンジニアってやつなのかもしれない・・ お仏壇に置きたいお菓子は「チーズアーモンド」です。
https://github.com/kimuchanman
lifull
日本最大級の不動産・住宅情報サイト「LIFULL HOME'S」を始め、人々の生活に寄り添う様々な情報サービス事業を展開しています。
https://lifull.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away