[英]How to achieve a maintainable, reactive UI with vanilla JS
今天我遇到了一個問題,可以通過使用像 Vue 這樣的反應式和狀態管理框架來輕松解決。 可悲的是,它不可能使用它。
以下(簡化)情況(指向 codepen 的鏈接):我們有一個服務器呈現的頁面,其中包含一個價格字段。 它有機會添加或刪除注釋。 如果我們添加注釋,它會發布到服務器,並且 UI 應該會自行更新。 刪除筆記也一樣。
const priceField = document.getElementById("priceField"); priceField.querySelector("#create-note-btn").addEventListener("click", () => { priceField.querySelector("#note-input-row").classList.toggle("hidden"); // depending on state #create-note-btn can hide/show #note-row or #node-input-row }); priceField.querySelector("#submit-note-btn").addEventListener("click", () => { priceField.querySelector("#note-row").classList.toggle("hidden"); priceField.querySelector("#note-input-row").classList.toggle("hidden"); const input = priceField.querySelector("input").value; priceField.querySelector("#note").innerHTML = input; // api call // further ui updates, like changing icon of #create-note-btn }); priceField.querySelector("#delete-note-btn").addEventListener("click", () => { priceField.querySelector("#note-row").classList.toggle("hidden"); // api call // resetting icon of #create-note-btn }); // much more logic with additional UI update operations, like recalculation of price etc.
.hidden { display: none; }
<div id="priceField"> <div> <span>100 €</span> <button id="create-note-btn">Create Note</button> </div> <div id="note-input-row" class="hidden"> <input></input> <button id="submit-note-btn">Submit</button> </div> <div id="note-row" class="hidden"> <span id="note">Placeholder note</span> <button id="delete-note-btn">Delete Note</button> </div> </div>
為了實現這一點(僅!)javascript 用於更新視圖。 因此,許多classlist.toggle("..")
調用或其他事情都是為了顯示/隱藏元素。 此外,還有許多不同的操作也會更新不同位置的視圖。
為了保持代碼的可維護性,我想實現 UI 更新在一個中心位置完成,而不是分散到不同的調用中。 還應保留狀態以重新加載頁面。
什么是簡單且可維護的方法?
我的想法:實現一個小的狀態機(INITIAL、OPEN_NOTE、CLOSED_NOTE,...)和一個依賴於實際狀態的render()
函數。 為了保持頁面重新加載的更改,必須使用 localstorage 或者服務器端呈現的 html 也需要有狀態。
我遵循我的想法,通過使用包含所有 UI 相關更改的render
函數實現內部狀態。
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!");
}
頁面重新加載后的狀態由服務器端呈現的 html 的自定義屬性確定:
initializeRenderMode() {
...
// if note already exists on page load switch render mode to open
this.renderMode = existingNote ? RenderMode.OPEN : RenderMode.INITIAL;
this._render();
}
到目前為止,它不是最好的解決方案,但它幫助我保持簡單。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.