簡體   English   中英

如何使用 vanilla JS 實現可維護的反應式 UI

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM