繁体   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