如何使用 vanilla JS 实现可维护的反应式 UI

The*_*iaz 7 javascript css

今天我遇到了一个问题,可以通过使用像 Vue 这样的反应式和状态管理框架来轻松解决。可悲的是,它不可能使用它。

\n

以下(简化的)情况(链接到 codepen):我们有一个服务器渲染的页面,其中有一个价格字段。它有机会添加或删除注释。如果我们添加注释,它就会发布到服务器,并且 UI 应该自行更新。删除注释也是如此。

\n

\r\n
\r\n
const 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
\r\n
\r\n

\n

为了实现这一点(仅!),使用 javascript 来更新视图。因此,许多classlist.toggle("..")调用或其他事情都是为了显示/隐藏元素而进行的。此外,还有许多不同的操作也会更新不同位置的视图。

\n

为了保持代码的可维护性,我希望实现 UI 更新在一个中心位置完成,而不是分散在不同的调用中。还应该保留页面重新加载的状态。

\n

有什么简单且可维护的方法来做到这一点?

\n

我的想法:\n实现一个小状态机(INITIAL,OPEN_NOTE,CLOSED_NOTE,...)和一个render()取决于实际状态的函数。为了保留页面重新加载的更改,必须使用本地存储,或者服务器端渲染的 html 也需要有状态。

\n

The*_*iaz 1

我遵循我的想法,使用一个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)

到目前为止,它不是最好的解决方案,但它帮助我让事情变得简单。