如何在Angular 4中防止页面刷新

16
我希望防止页面在任何地方被刷新。 我尝试了以下代码。
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { CommonServices } from '../services/common.service'; 

@Component({
  selector: 'app-review-prescription',
  templateUrl: './review-prescription.component.html',
  styleUrls: ['../../assets/css/prescriptionView.css'],
  providers:[
    CommonServices
  ]
})
export class ReviewPrescriptionComponent implements OnInit {
    constructor(
        private commonServices:CommonServices,
        private router:Router
        ){}
    ngOnInit(){
      window.onbeforeunload = function(event) {
        return 'By refreshing this page you may lost all data.';
      }
  }

}

我尝试在ngOnChanges()ngOnInit()ngOnDestroy()上使用过,甚至在组件类之外(抱歉不合逻辑),但什么都没有作用?

我需要 Angular 或 JavaScript 的解决方案,而不是 jQuery。

谢谢。


1
请问您能否再添加一些您的代码呢? - Quentin Albert
6
无法阻止页面刷新。浏览器用户始终可以按F5。使用"onbeforeunload"方法可以警告用户,但无法防止刷新。 - Pointy
1
@Pointy 你是对的,但是即使是警告也不起作用。问题是 window.onbeforeunload 不工作 :( - RajnishCoder
1
你说的“不工作”是什么意思?有报错吗?你能看到浏览器弹出的对话框吗? - Pointy
显示剩余3条评论
8个回答

13

尝试以下订阅以在页面刷新时弹出警报窗口。在尝试刷新或关闭窗口之前,进行一些用户事件,如单击页面。在此处查看工作版本

查看beforeunload的官方文档

ngOnInit() {
    window.addEventListener("beforeunload", function (e) {
        var confirmationMessage = "\o/";
        console.log("cond");
        e.returnValue = confirmationMessage;     // Gecko, Trident, Chrome 34+
        return confirmationMessage;              // Gecko, WebKit, Chrome <34
    });
}

3
这对你真的有效吗?至少在我刷新页面时,Chrome上什么也没有发生。 - Peng-Watcher37-Link37
提示:在执行 beforeunload 操作前,请查看官方文档。 - Adrian

7
@HostListener("window:beforeunload", ["$event"]) unloadHandler(event: Event) {
      event.returnValue = false;
  }

4

解决方案取决于您希望防止页面重新加载的原因。如果您想要防止这种情况,因为可能会有未保存的更改,那么您实际上需要防止两种不同的行为:

  1. 浏览器页面重新加载。您可以通过在beforeunload事件上创建HostListener(类似于您的尝试)来实现此目的,例如:
    @HostListener('window:beforeunload', ['$event'])
    beforeUnloadHander() {
        // or directly false
        this.allowRedirect;
    }
  1. 如果你使用了路由,想要进行Angular路由更改:你需要在你想要锁定的路由上使用Deactivation guard。有很多方法可以实现这个目的,但最受欢迎的方法是使用接口实现:

I. 这个接口设置了一些字段,用于在angular守卫中检查是否可以更改路由路径:


    import { Observable } from "rxjs";
    import { HostListener } from "@angular/core";

    // see https://scotch.io/courses/routing-angular-2-applications/candeactivate
    // implementing this interface with a component in angular you can implement a candeactivate
    // guard that automatically checks if there is the canDeactivate function and
    // it allows to navigate out of the route or not
    export default interface LockableComponent {
      allowRedirect: boolean;
      canDeactivate(): boolean;
    }

II. 每个组件都需要实现此接口,使用canDeactivate方法或allowRedirect字段(在问题#1的HostListener中可重用),必须返回一个布尔值,指示是否允许导航。

III. 创建一个路由守卫,检查此组件的字段以进行反激活:

  canDeactivate(
    component: LockableComponent,
    currentRoute: ActivatedRouteSnapshot,
    currentState: RouterStateSnapshot
  ): Observable<boolean> | Promise<boolean> | boolean {
    if (
      (component.allowRedirect === false ||
        (component.canDeactivate && !component.canDeactivate()))
    ) {
      // Angular bug! The stack navigation with candeactivate guard
      // messes up all the navigation stack...
      // see here: https://github.com/angular/angular/issues/13586#issuecomment-402250031
      this.location.go(currentState.url);

      if (
        window.confirm("Sure man?")
      ) {
        return true;
      } else {
        return false;
      }
    } else {
      return true;
    }
  }

III. 在你的 module.routing.ts 文件中设置 canDeactivate 路由守卫:

const myRoutes: Routes = [
      {
        path: "locked-route-path",
        component: ComponentThatImplementsLockedInterface,
        canDeactivate: [TheCanDeactivateGuardJustMade]
      }
      //...
]

1
这是我见过的最干净的代码。虽然对于一些非常简单的应用程序来说可能有点过度,但这种技术是最模块化和可重用的。 - Chax

2
你可以试试这个。
@HostListener('window:beforeunload', ['$event'])
beforeunloadHandler(event) {
    alert('By refreshing this page you may lost all data.');
}

请确保将此内容包含在类内部。

2
你能提供任何例子吗? - Runali
请参考以下链接中提供的代码:https://medium.com/front-end-weekly/angular-how-keep-user-from-lost-his-data-by-accidentally-leaving-the-page-before-submit-4eeb74420f0d。本文介绍如何通过Angular防止用户在提交前意外离开页面而丢失数据。 - priya_21

1

0
所有之前的答案都包含了这段代码,但是我们需要添加一个语句来阻止默认行为。

event.preventDefault()

@HostListener("window:beforeunload", ["$event"])
unloadHandler(event) {
    event.preventDefault();
    return event.returnValue = "Are you sure you want to exit?";
}

0
我已经使用RouteGuard和纯Javascript代码两种方式来防止浏览器关闭标签页/返回/关闭窗口。

组件:

profileForm = this.fb.group({
  ClientName: ['', [Validators.required]]
});

@HostListener('window:beforeunload', ['$event']) beforeUnloadHander(event: any) {
     debugger
     var isFormDirty = document.getElementById('profileformStatus').innerText;
     console.log(isFormDirty);
     if(isFormDirty == 'true'){
       return false;
     }
     else{
       return true;
     }
   }

组件 HTML:

<div id="profileformStatus">{{profileForm.dirty ? true:false}}</div>

组件守卫服务文件(可选):

import { CanDeactivate } from "@angular/router";
import { Injectable } from "@angular/core";
import { YourComponent } from "./projects/your-component";
@Injectable()

export class YourComponentCanDeactivateGuardService
    implements CanDeactivate<YourComponent> {

    canDeactivate(component: YourComponent): boolean {
        if (component.profileForm.dirty) {
            return confirm('Are you sure you want to discard your changes?');
        }
        return true;
    }
}

你的模块:添加上述守卫(可选)

@NgModule({
    providers: [YourComponentCanDeactivateGuardService]
})

最后

更新你的路由模块(可选):

const routes: Routes = [
    {
        path: 'detail/:id',
        component: YourComponent,
        canDeactivate: [YourComponentCanDeactivateGuardService]
    }
];

完成。现在它将防止重新加载/后退导航。

-2
这需要您创建一个守卫(Guard)。
在您的路由配置文件中:
const routes: Routes = [
    {
        path: '',
        redirectTo: '/homePage',
        pathMatch: 'full'
    },
    {
        path: 'accueil',
        component: AccueilComponent,
        canDeactivate: [GuardName]
    }]

通过这样做,您正在调用所选组件上的守卫

更多信息在这里

在您的守卫中:

@Injectable()
export class CanDeactivateGuard implements CanDeactivate<CanComponentDeactivate> {
  canDeactivate(component: CanComponentDeactivate) {
    return true/false;
  }
}

这实际上不是一个Angular的问题,而是基本的浏览器行为。 - Pointy
可能误解了他的问题。 - Terry Pitz
我猜你收到了一个负评,因为守卫在浏览器刷新时根本不起作用。 - Adrian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接