更新:因此,我仍在努力创建一个层次结构,由父级负责呈现其嵌套的子级,和跟踪需要注册/未注册的子级。
基本上:如果我没有引用每个视图中的直接子代,那么当它们在更新时被重新创建和渲染时,我就无法检查它们是否已经是模型中的观察者。
我开始认为我应该放弃这种模式,只创建一个自定义事件,并在创建每个文档片段时为其添加一个监听器(如果可能的话)。至少我可以在重新渲染时附加/删除侦听器
原始问题:
我试图在没有控制器IE的情况下在JS中实现观察者模式:模型只是在其数据更改时重新呈现相关视图。
我的问题是,我需要将view
传递给model
的registerObserver
函数作为引用,否则我无法检查观察者是否已经注册,这里是:
if (!this.observers.includes(observer))
this.observers.push(observer)
如果我不能检查观察者,它们会在每次重新渲染时不断添加,所以我在nestedViews
属性中保留对它们的引用。但我正在努力解决父视图可能也需要观察模型的问题,所以我添加了对self
的引用。但是,如果在模型更改时重新渲染父视图,则会丢失对嵌套视图的引用,并且会出现同样的问题。
相对于这种方法,我对webdev非常陌生(这只是一个改进我的vanilla-js的练习),所以我确信这一定是一个我看不到的简单修复?
父视图:
class View {
nestedViews = {};
self = this;
constructor(parentEl, model){
this.model = model;
this.parentEl = parentEl;
}
update() { this.render(); }
render() {
// method to render child classes
this.onRender();
// bind model
this.bindModel();
//... Logic to insert the item into the dom
}
}
class NestedView extends View {
bindModel() {
Object.entries(this.nestedViews).forEach(([key, value]) =>
this.model.registerObserver(value)
);
}
onRender() {
this.nestedViews['nestedView1'] = new NestedView1(
parent,
this.model
);
this.nestedViews['nestedView1'].render();
this.nestedViews['nestedView2'] = new NestedView2(
parent,
this.model
);
this.nestedViews['nestedView2'].render();
}}
型号:
class Model {
observers = [];
registerObserver(observer) {
if (!this.observers.includes(observer)) this.observers.push(observer);
}
unregisterObserver(observer){
this.observers = this.observers.filter((obs) => obs !== observer);
}
updateObservers() {
this.observers.forEach((observer) => observer.update());
}
set() {
// set attr
this.updateObservers();
}
}
感谢
我想我理解您面临的问题。您希望避免每次模型更改时都重新渲染父视图,因为这会导致丢失对嵌套视图的引用。一种解决方案是使用一个单独的方法来更新嵌套视图,并从父视图的更新方法调用它。这样,父视图只负责更新嵌套视图,而不负责重新渲染它们。
以下是一个如何修改代码以实现此目的的示例:
class View {
nestedViews = {};
constructor(parentEl, model) {
this.model = model;
this.parentEl = parentEl;
}
update() {
// Update nested views without re-rendering the parent view
this.updateNestedViews();
}
updateNestedViews() {
Object.values(this.nestedViews).forEach((nestedView) => nestedView.update());
}
render() {
// method to render child classes
this.onRender();
// bind model
this.bindModel();
}
}
class NestedView extends View {
bindModel() {
Object.values(this.nestedViews).forEach((nestedView) =>
this.model.registerObserver(nestedView)
);
}
onRender() {
this.nestedViews['nestedView1'] = new NestedView1(this.parentEl, this.model);
this.nestedViews['nestedView1'].render();
this.nestedViews['nestedView2'] = new NestedView2(this.parentEl, this.model);
this.nestedViews['nestedView2'].render();
}
}
在该解决方案中,父视图的更新方法不会重新渲染自身;相反,它调用updateNestedViews,后者反过来对每个嵌套视图调用update方法。这将有助于维护对嵌套视图的引用,并防止它们多次注册为观察者。
此外,考虑在Model类中使用以下修改后的registerObserver方法,以便在观察员被销毁或不再需要时自动注销它们:
class Model {
// ...
registerObserver(observer) {
if (!this.observers.includes(observer)) {
this.observers.push(observer);
// Automatically unregister the observer when it's destroyed
const unregister = () => {
this.unregisterObserver(observer);
};
observer.onDestroy(unregister);
}
}
// ...
}
在View类中,添加onDestroy方法:
class View {
// ...
onDestroy(callback) {
this._onDestroyCallback = callback;
}
destroy() {
if (this._onDestroyCallback) {
this._onDestroyCallback();
}
}
// ...
}
通过这种方式,您可以在不再需要视图时调用destroy方法,它将自动从模型中注销为观察者。