我已经建立了一个electronjs应用程序,并使用angular作为前端。起初,我做得有点不对,并使用websocket来进行两者之间的通信。这个应用程序已经完成了,但我想以正确的方式完成,并切换到ipcRenderer进行通信。
在改变了一切之后,发生了一些奇怪的事情。ipcRenderer调用更改值后,UI不再更新。例如,我有一个html元素,如果isInstalling
设置为true
,它将获得一个类。当我更改值时,UI将更改为。这在ws
中确实有效,但现在在ipcRenderer中不起作用。该值仍将被设置,但UI不会更新。当点击事件被触发时,isInstalling
被设置为true
,而当onFinished
被调用时,将被设置为false
。
这是我的代码:
preload.js
contextBridge.exposeInMainWorld("ipcRenderer", {
onStep: (callback) => ipcRenderer.on("step", callback),
onDownload: (callback) => ipcRenderer.on("download", callback),
onFinished: (callback) => ipcRenderer.on("finished", callback),
[...]
});
ipc.service.ts
export class IpcService {
constructor() { }
getIpcRenderer(){
return (<any>window).ipcRenderer;
}
}
app.component.ts
ngOnInit(): void {
console.log("INIT");
this.ipcRenderer.onStep((event: any, text: string) => {
this.addStep(text);
});
this.ipcRenderer.onDownload((event: any, data: any) => {
this.progress = data.percent;
this.current = data.current;
this.total = data.total;
});
this.ipcRenderer.onFinished((event: any) => {
console.log("Finished!!");
this.isInstalling = false;
});
}
addStep(step: string) {
this.steps.push(step)
this.steps = [...this.steps]; // Before, this will force an update of a displayed list that used *ngFor
}
app.component.html
<div [ngClass]="{'disabledImage': isInstalling}" (click)="download()">
<img style="margin: 0px;" width="400px" src="./assets/image.png">
</div>
所以所有的代码在过去都是有效的,但现在不行了。同样奇怪的是,我从this.steps
显示的列表不会显示实时更改,但当我再次触发单击事件时,所有列表项都将显示。好像点击会更新用户界面,就这样。
你知道我在这里需要做什么吗?
Angular使用zone.js来检测变化,但默认情况下它不知道electron的ipcRenderer。您可以通过将其添加到polyfills.ts:的末尾来启用支持
import 'zone.js/dist/zone-patch-electron';
或者,您可以在每次回调中手动触发更改检测:
app.component.ts
constructor(private ngZone: NgZone) {}
//...
this.ipcRenderer.onFinished((event: any) => {
this.ngZone.run(() => { // trigger zone change detection
console.log("Finished!!");
this.isInstalling = false;
});
});
https://github.com/angular/zone.js/blob/master/NON-STANDARD-APIS.md(电子部分)
https://angular.io/guide/zone