我正在尝试编写一个服务类,它侦听页面可见性并向订阅的组件提供状态更改。服务类有一个实例变量doc它几乎保存了当前的HTML文档。我设置了这个docfrom componentsinit方法并在组件中订阅,以侦听页面可见性状态更改。即使在调试窗口中,我看到状态发生了变化,doc变量在那里是空的,我不确定为什么。
下面是我的service class
import { Subject } from "rxjs";
import { Injectable } from '@angular/core';
export enum PageVisibilityState {
Visible,
Hidden
}
@Injectable()
export class PageVisibilityService {
doc: Document;
hiddenString:string = "";
visibilityChange:string="";
pageVisibilityState: PageVisibilityState = PageVisibilityState.Visible;
_pageVisibilityStateSubject: Subject<PageVisibilityState> = new Subject();
constructor() {
this.doc = null;
}
init(doc: Document) {
this.doc = doc;
// Set the name of the "hidden" property and the change event for visibility
if (typeof doc.hidden !== "undefined") {
this.hiddenString = "hidden";
this.visibilityChange = "visibilitychange";
} else if (typeof doc["mozHidden"] !== "undefined") { // Firefox up to v17
this.hiddenString = "mozHidden";
this.visibilityChange = "mozvisibilitychange";
} else if (typeof doc["webkitHidden"] !== "undefined") { // Chrome up to v32, Android up to v4.4, Blackberry up to v10
this.hiddenString = "webkitHidden";
this.visibilityChange = "webkitvisibilitychange";
}
// Warn if the browser doesn't support addEventListener or the Page Visibility API
if (typeof doc.addEventListener === "undefined" || typeof doc[this.hiddenString] === "undefined") {
console.log("This demo requires a modern browser that supports the Page Visibility API.");
} else {
// Handle page visibility change
doc.addEventListener(this.visibilityChange, this.handleVisibilityChange, false);
}
}
private handleVisibilityChange() {
if (typeof this.doc.hidden !== "undefined") { //***this.doc <-- is null here***
this.hiddenString = "hidden";
this.visibilityChange = "visibilitychange";
} else if (typeof this.doc["mozHidden"] !== "undefined") { // Firefox up to v17
this.hiddenString = "mozHidden";
this.visibilityChange = "mozvisibilitychange";
} else if (typeof this.doc["webkitHidden"] !== "undefined") { // Chrome up to v32, Android up to v4.4, Blackberry up to v10
this.hiddenString = "webkitHidden";
this.visibilityChange = "webkitvisibilitychange";
}
if (this.doc[this.hiddenString]) {
this.pageVisibilityStateSubject.next(PageVisibilityState.Hidden);//**all instances are null**
} else {
this.pageVisibilityStateSubject.next(PageVisibilityState.Visible);
}
}
get pageVisibilityStateSubject() : Subject<PageVisibilityState> {
return this._pageVisibilityStateSubject;
}
set pageVisibilityStateSubject(src: Subject<PageVisibilityState>) {
this._pageVisibilityStateSubject = src;
}
public getVisibilityState(): Subject<PageVisibilityState> {
return this.pageVisibilityStateSubject;
}
dispose(): void {
//Called once, before the instance is destroyed.
//Add 'implements OnDestroy' to the class.
this.doc = null;
}
}
这是我的app.module.ts
//some imports removed for easy readability
import { PageVisibilityService } from './shared/services/page.visibility.service';
@NgModule({
imports: [//imports removed for easy readability ],
declarations: [//removed for easy readability ],
providers: [
//some removed for easy readability
PageVisibilityService
],
bootstrap: [AppComponent]
})
export class AppModule { }
这是我的组件
import { PageVisibilityService, PageVisibilityState } from '../../../shared/services/page.visibility.service';
@Component({
selector: 'app-team-consult-action-teamConsult',
templateUrl: './team-consult-action.component.html',
styleUrls: ['./team-consult-action.component.scss'],
animations: [routerTransition()]
})
export class TeamConsultActionComponent implements OnInit {
pageVisibilityStateSubject: Subject<PageVisibilityState>;
constructor(
public router: Router,
private route: ActivatedRoute,
private pageVisibilityService: PageVisibilityService,
private commonService: CommonService) {
this.pageVisibilityService.init(document);
this.pageVisibilityStateSubject = this.pageVisibilityService.pageVisibilityStateSubject;
this.pageVisibilityStateSubject.subscribe((pageVisible: PageVisibilityState) => {
console.log(`Current Page State is ${pageVisible === PageVisibilityState.Visible ? "Visible" : "Hidden"}`);
});
}
在控制台日志中,我得到以下错误:
TypeError: Cannot read properties of undefined (reading 'next')
at HTMLDocument.handleVisibilityChange (page.visibility.service.ts:57:45)
at ZoneDelegate.invokeTask (zone-evergreen.js:399:1)
at Object.onInvokeTask (core.js:41442:1)
at ZoneDelegate.invokeTask (zone-evergreen.js:398:1)
at Zone.runTask (zone-evergreen.js:167:1)
at ZoneTask.invokeTask [as invoke] (zone-evergreen.js:480:1)
at invokeTask (zone-evergreen.js:1621:1)
at HTMLDocument.globalZoneAwareCallback (zone-evergreen.js:1647:1)
你能帮我解释是什么原因导致我的实例失去了初始化吗?
我理解了null问题的原因,为什么在调试时,控制台显示null。原因是窗口调用的PageVisibilityChange是handleVisibilityChange方法(在我的类中)。但是window并没有对初始化对象的引用因此这不是在我们的实例中发生的。因此,我认为一个可能的解决方案是将实例存储在sessionStorage中,显示如何使用该实例引用来推回状态值。还有谁遇到过这个问题并解决了这个问题?或者让我知道是否有一个通用的类,我可以使用它来实现这个。
谢谢,赫曼特。
最后,我的问题是解决通过使方法和成员静态,因为一个选项卡,将有一个浏览器,所以安全的去静态选项,下面是更新的代码,以防有人想要使用它。
import { Subject } from "rxjs";
import { Injectable } from '@angular/core';
export enum PageVisibilityState {
Hidden = 0,
Visible = 1
}
@Injectable()
export class PageVisibilityService {
static hiddenString:string = "";
static pageVisibilityState: PageVisibilityState = PageVisibilityState.Visible;
static _PageVisibilityStateSubject: Subject<PageVisibilityState> = new Subject();
constructor() {
var visibilityChange:string="";
// Set the name of the "hidden" property and the change event for visibility
if (typeof document.hidden !== "undefined") {
PageVisibilityService.hiddenString = "hidden";
visibilityChange = "visibilitychange";
} else if (typeof document["mozHidden"] !== "undefined") { // Firefox up to v17
PageVisibilityService.hiddenString = "mozHidden";
visibilityChange = "mozvisibilitychange";
} else if (typeof document["webkitHidden"] !== "undefined") { // Chrome up to v32, Android up to v4.4, Blackberry up to v10
PageVisibilityService.hiddenString = "webkitHidden";
visibilityChange = "webkitvisibilitychange";
}
// Warn if the browser doesn't support addEventListener or the Page Visibility API
if (typeof document.addEventListener === "undefined" || typeof document[PageVisibilityService.hiddenString] === "undefined") {
console.log("This demo requires a modern browser that supports the Page Visibility API.");
} else {
// Handle page visibility change
document.addEventListener(visibilityChange, PageVisibilityService.handleVisibilityChange, false);
}
}
static handleVisibilityChange() {
if (document[PageVisibilityService.hiddenString]) {
PageVisibilityService._PageVisibilityStateSubject.next(PageVisibilityState.Hidden);
} else {
PageVisibilityService._PageVisibilityStateSubject.next(PageVisibilityState.Visible);
}
}
get PageVisibilityStateSubject() : Subject<PageVisibilityState> {
return PageVisibilityService._PageVisibilityStateSubject;
}
set PageVisibilityStateSubject(src: Subject<PageVisibilityState>) {
PageVisibilityService._PageVisibilityStateSubject = src;
}
}