今天我遇到了一个问题,可以通过使用像 Vue 这样的反应式和状态管理框架来轻松解决。可悲的是,它不可能使用它。
\n以下(简化的)情况(链接到 codepen):我们有一个服务器渲染的页面,其中有一个价格字段。它有机会添加或删除注释。如果我们添加注释,它就会发布到服务器,并且 UI 应该自行更新。删除注释也是如此。
\nconst priceField = document.getElementById("priceField");\n\npriceField.querySelector("#create-note-btn").addEventListener("click", () => {\n priceField.querySelector("#note-input-row").classList.toggle("hidden");\n\n // depending on state #create-note-btn can hide/show #note-row or #node-input-row\n});\n\npriceField.querySelector("#submit-note-btn").addEventListener("click", () => {\n priceField.querySelector("#note-row").classList.toggle("hidden");\n priceField.querySelector("#note-input-row").classList.toggle("hidden");\n\n const input = priceField.querySelector("input").value;\n priceField.querySelector("#note").innerHTML = input;\n // api call\n // further ui updates, like changing icon of #create-note-btn\n});\n\npriceField.querySelector("#delete-note-btn").addEventListener("click", () => {\n priceField.querySelector("#note-row").classList.toggle("hidden");\n // api call\n // resetting icon of #create-note-btn\n});\n\n// much more logic with additional UI update operations, like recalculation of price etc.Run Code Online (Sandbox Code Playgroud)\r\n.hidden {\n display: none;\n}Run Code Online (Sandbox Code Playgroud)\r\n<div id="priceField">\n <div>\n <span>100 \xe2\x82\xac</span>\n <button id="create-note-btn">Create Note</button>\n </div>\n <div id="note-input-row" class="hidden">\n <input></input>\n <button id="submit-note-btn">Submit</button>\n </div>\n <div id="note-row" class="hidden">\n <span id="note">Placeholder note</span>\n <button id="delete-note-btn">Delete Note</button>\n </div>\n</div>Run Code Online (Sandbox Code Playgroud)\r\n为了实现这一点(仅!),使用 javascript 来更新视图。因此,许多classlist.toggle("..")调用或其他事情都是为了显示/隐藏元素而进行的。此外,还有许多不同的操作也会更新不同位置的视图。
为了保持代码的可维护性,我希望实现 UI 更新在一个中心位置完成,而不是分散在不同的调用中。还应该保留页面重新加载的状态。
\n有什么简单且可维护的方法来做到这一点?
\n我的想法:\n实现一个小状态机(INITIAL,OPEN_NOTE,CLOSED_NOTE,...)和一个render()取决于实际状态的函数。为了保留页面重新加载的更改,必须使用本地存储,或者服务器端渲染的 html 也需要有状态。
我遵循我的想法,使用一个render包含所有 UI 相关更改的函数来实现内部状态。
const RenderMode = {
INITIAL: "Initial",
CREATE: "Create",
OPEN: "Open",
SHOW_NOTE: "Show note input",
TOGGLE_PRICE: "Toggle price input",
};
render() {
switch (this.renderMode) {
case RenderMode.INITIAL:
this._hideIndicatorIcon();
this._hideIndicatorRow();
this._hideInputRow();
this._hidePriceInput();
break;
case RenderMode.CREATE:
this._showInputRow();
break;
case RenderMode.OPEN:
this._showIndicatorIcon();
this._hideInputRow();
this._hideIndicatorRow();
break;
case RenderMode.SHOW_NOTE:
this._showIndicatorRow();
break;
case RenderMode.TOGGLE_PRICE:
this._togglePriceInputs();
break;
default:
console.error("No render mode defined!");
}
Run Code Online (Sandbox Code Playgroud)
页面重新加载后的状态由服务器端呈现的 html 的自定义属性确定:
initializeRenderMode() {
...
// if note already exists on page load switch render mode to open
this.renderMode = existingNote ? RenderMode.OPEN : RenderMode.INITIAL;
this._render();
}
Run Code Online (Sandbox Code Playgroud)
到目前为止,它不是最好的解决方案,但它帮助我让事情变得简单。