带有占位符的 Web 组件和 JS DOM 元素

Web components and JS DOM Elements with a placeholder

最近,每个人都在跳上与框架无关的 Web 组件火车UI 元素。 当我阅读这篇文章时,它看起来是一种通过浏览器编写自定义元素的本机方式。但我有一个问题。它与 js 扩展 div(占位符) 以增强和提供我们需要的一些功能的方式有何不同。

例如: 如果我想要一个 table 组件 Web Component: <my-table></my-table> ---- JS中对应代码 --- 编译成js文件,在外部脚本中使用

JS方式:<div id="my-table"></div>---- code in JS ---- 编译成JS在外部script标签中使用 我正在以 ag-grid 示例来说明清楚

例如:农业网格 https://www.ag-grid.com/javascript-grid/

<div id="myGrid" style="height: 200px; width:500px;" class="ag-theme-alpine"></div>

new agGrid.Grid(gridDiv, gridOptions);

两者的区别和优势是什么?请帮助

我的第一反应是,

What is the difference between ES5 and ES6? (unless you are still doing ES3)

差别太大了,很快就要做苹果和苹果的比较了。

阅读所有博客,使用自定义元素,学习。


TL;DR

  • 使用DOM元素与Javascript - 需要顺序(1和2可以切换):

    1. 加载JavaScript
    2. 创建 DOM 个元素
    3. 运行JavaScript
    4. 转换DOM个元素
  • 使用自定义元素API: - 顺序重要:

  • 创建自定义 DOM 元素

  • 加载JavaScript


差异和优势

假设客户想要页面上的三个网格:

  • 你加3个DIV:
    <div id="myGrid1" .../>
    <div id="myGrid2" .../>
    <div id="myGrid3" .../>

  • 要激活它们,您还必须添加:
    new agGrid.Grid(document.getElementById("myGird1")
    new agGrid.Grid(document.getElementById("myGird2")
    new agGrid.Grid(document.getElementById("myGird3")

  • 如果 JavaScript 在 之前 执行 DOM 元素
    所以你添加一个事件监听器:
    window.addEventListner("onload",()=>ActivateGrids());

请注意您必须如何在此处添加(某种类型的)全局函数;
所以祈祷没有人会覆盖您宝贵的代码;

  • 考虑到以上含义,您决定谨慎行事:

    • 您将所有 ID 重命名为真正独特的(并且真的不可读)
    • 您将所有 BEM 选择器重命名为真正唯一(且不可读)的名称
    • React,Angular,Vue(部分)为您做这件事,
      但是你做的是 Native JavaScript,所以必须手工做。
  • 为什么不起作用?
    你按下 F12,调试,然后猛撞你的头……你在 ID 中打错了字……gridgird

  • 2 天后...
    该死的!客户想要第四格!
    在他第 5 次打扰您之前,您决定重构 ActivateGrids 函数以处理页面中任意数量的网格

[...document.querySelectorAll('[id*="MyuniQueIDgridComponent_KUT!"]')].forEach(...)

我们有组件!! Play: Queen, We are the Champions!

  • 3 周后,客户有一个非常简单的要求,你可以在半小时内完成,他说。 我们要改变背景颜色,用一个属性就DIV

  • 你被难住了!
    更改具有 DIV 个属性的属性!?!
    为什么他们不能直接调用 JavaScript 网格实例?!?

    您几年前曾尝试教育客户;语义 HTML 没有未来!
    只雇用高级 Web 开发人员...但他不听

    <my-grid background=green></my-grid>

    有什么意义

    当你可以用 程序员的方式做到时:

    document.getElementById("myGird1").mySetPropperty("background","green");

    但是客户支付了您的抵押贷款;
    所以你了解了 MutationObserver,并将其贴在 BODY 标签上。
    这句话很容易写,但编码很费功夫!

  • 5 个月后,客户说他不想再雇用你了,因为 adding/removing 他们 SPA 中的网格导致内存泄漏。

输入自定义元素API(又名 Web 组件)

使用框架,以上所有内容(只是稍微)更容易..

但是您想构建一个可重复使用的组件,而不是构建一个使用 组件

的应用程序
  • 所以您决定使用原生自定义元素API

    您考虑过使用 Lit 或 Stencil 或 Hybrids 或 Component Libray X;
    但决定反对他们。
    使用 Native JavaScript 只需要几行额外的代码,
    但最重要的是,您不想引入依赖项(您还记得早期 jQuery 的日子,那里有许多替代方案,您不得不放弃 $$$ 项目,因为开发人员选择了 Mootools)

Native JavaScript will work as long as JavaScript is supported in the Browser.

  • 您设计(最终)用户将如何使用您的组件:

    <KCB-grid rows=3 columns=5 background=color ></KCB-grid>

  • 然后您对组件进行编程。
    我从你的 Twitter 句柄
    中获取了 KCB- 命名空间 此命名空间(如您的全局函数)在页面中必须是唯一的
    看下面的代码,它是一个文本字符串,所以可以动态创建!
    <KCB-Grid-Customer rows=3 columns=5 background=color ></KCB-grid-Customer>

  • 适用于任何现代浏览器
    有一个 IE11 的 polyfill;但坦率地说,避免使用 IE11。
    您在 9 年前就停止支持 IE。有一个停止支持 IE11 的时刻,那个时刻就是现在.. even Microsoft said so over a year ago

  • 适用于所有框架和库
    (除了在 React 中你需要做额外的工作..
    因为 Facebook 仍然试图将他们的 'standard' 强加给世界其他地方)
    https://custom-elements-everywhere.com/libraries/react/results/results.html

  • 没有onload问题,元素是在脚本之前还是之后声明都没有关系。自定义元素自动升级。

  • 你可以随时.innerHTML = "<KCB-Grid></KCB-Grid>"
    客户也想要,
    但聘请了另一位程序员使用下面的自定义元素来完成

  • 否 CSS 选择器唯一性问题...并且可能根本不执行 BEM

  • rowscolumns可以随时更改
    运行 代码片段,点击网格

<template id="KCB-GRID">
  <!-- use TEMPLATES! don't mess with JSX, CSSinJS or HTML in textstrings! -->
  <style>
    #grid { /* no BEM, no forced unique IDs or style names */
      display: grid;
      grid-template-columns: repeat(var(--columns), 1fr);
      grid-auto-rows:        minmax(min-content, max-content);
      gap: .2em;
    }
    #grid div {
      background: var(--background);
      text-align: center;
    }
  </style>
  <div id=grid></div>
</template>

<KCB-Grid columns=5 rows=3 background=#FF9933></kcb-grid>
<KCB-Grid columns=3 rows=3 background=white  ></kcb-grid>
<KCB-Grid columns=4 rows=3 background=#138808></kcb-grid>

<script>
  customElements.define('kcb-grid', class extends HTMLElement {
    static get observedAttributes() {
      return [ "columns", "rows" ] // only these can be changed at any time
    }
    constructor() {
      super().attachShadow({ mode: 'open' })
             .append(document.getElementById(this.nodeName).content.cloneNode(true));
      this.grid = this.shadowRoot.querySelector("#grid");
    }
    connectedCallback() {
      const random = (x, y) => Math.floor(Math.random() * (y + 1 - x) + x);
      this.setProperty("background");
      this.grid.onclick = () => {
                this.setAttribute("columns", random(2, 6));
                this.setAttribute("rows",    random(2, 4));
      }
    }
    attributeChangedCallback(name, oldValue, newValue) {
      let columns = this.setProperty("columns");
      let rows =    this.setProperty("rows"   );
      this.grid.innerHTML = "<div>Hello World!</div>".repeat(columns * rows);
    }
    setProperty(name, value = this.getAttribute(name)) {
      this.grid.style.setProperty("--" + name, value);
      return value;
    }
    disconnectedCallback() {} //clean memory, remove listeners, etc.
  });
</script>

Cue Tom Lehrer 的 Elements 歌曲:https://www.youtube.com/watch?v=AcS3NOQnsQM

自定义元素还有更多内容

你可以玩KCB-Grid

在这个 JSFiddle 中:https://jsfiddle.net/CustomElementsExamples/nk9co3bu/