HTML代码里的命令:command 和 commandfor

按钮对于构建动态 Web 应用至关重要。按钮用于打开菜单、切换操作和提交表单。它们为 Web 上的互动性奠定了基础。让按钮简单易用可能会带来一些意想不到的挑战。构建微前端或组件系统的开发者可能会遇到过于复杂的解决方案。虽然框架有用,但 Web 可以提供更多帮助。

Chrome 135 引入了新功能,可通过新的 command 和 commandfor 属性提供声明式行为,从而增强和替换 popovertargetaction 和 popovertarget 属性。这些新属性可添加到按钮中,让浏览器能够解决一些与简单性和无障碍性相关的核心问题,并提供内置的常用功能。

随着生产代码的演变,在不使用框架的情况下构建按钮行为可能会带来一些有趣的挑战。虽然 HTML 为按钮提供了 onclick 处理脚本,但由于内容安全政策 (CSP) 规则,通常不允许在演示或教程中以外的地方使用这些脚本。虽然这些事件会分派给按钮元素,但按钮通常会放置在页面上以控制其他元素,这需要代码同时控制两个元素。您还需要确保辅助技术用户可以访问此互动。这通常会导致代码看起来如下所示:

<div class="menu-wrapper">
  <button class="menu-opener" aria-expanded="false">
    Open Menu
  </button>
  <div popover class="menu-content">
    <!-- ... -->
  </div>
</div>
<script type="module">
document.addEventListener('click', e => {  
  const button = e.target;
  if (button.matches('.menu-opener')) {
    const menu = button
      .closest('.menu-wrapper')
      .querySelector('.menu-content');
    if (menu) {
      button.setAttribute('aria-expanded', 'true');
      menu.showPopover();
      menu.addEventListener('toggle', e => {
        // reset back to aria-expanded=false on close
        if (e.newState == 'closed') {
          button.setAttribute('aria-expanded', 'false');
        }
      }, {once: true})
    }
  }
});
</script>

这种方法可能有点脆弱,而框架旨在改善工效学。 使用 React 等框架的常见模式可能涉及将点击映射到状态更改:

function MyMenu({ children }) {
  const [isOpen, setIsOpen] = useState(false);
  const open = useCallback(() => setIsOpen(true), []);
  const handleToggle = useCallback((e) => {
      // popovers have light dismiss which influences our state
     setIsOpen(e.newState === 'open')
  }, []);
  const popoverRef = useRef(null);
  useEffect(() => {
    if (popoverRef.current) {
      if (isOpen) {
        popoverRef.current.showPopover();
      } else {
        popoverRef.current.hidePopover();
      }
    }
  }, [popoverRef, isOpen]);
  return (
    <>
      <button onClick={open} aria-expanded={isOpen}>
        Open Menu
      </button>
      <div popover onToggle={handleToggle} ref={popoverRef}>
        {children}
      </div>
    </>
  );
}

许多其他框架也旨在提供类似的人体工学体验,例如,这段代码在 AlpineJS 中可以写为:

<div x-data="{open: false}">
  <button @click="open = !open; $refs.popover.showPopover()" :aria-expanded="open">
    Open Menu
  </button>
  <div popover x-ref="popover" @toggle="open = $event.newState === 'open'">
    <!-- ... -->
  </div>
</div>

在 Svelte 中编写此代码时,代码可能如下所示:

<script>
  let popover;
  let open = false;
  function togglePopover() {
    open ? popover.hidePopover() : popover.showPopover();
    open = !open;
  }
</script>
<button on:click={togglePopover} aria-expanded={open}>
  Open Menu
</button>
<div bind:this={popover} popover>
  <!-- ... -->
</div>

某些设计系统或库可能会更进一步,在按钮元素周围提供封装状态更改的封装容器。这会提取触发器组件背后的状态更改,以牺牲一点灵活性为代价来改进人体工学:

import {MenuTrigger, MenuContent} from 'my-design-system';
function MyMenu({children}) {
  return (
    <MenuTrigger>
      <button>Open Menu</button>
    </MenuTrigger>
    <MenuContent>{children}</MenuContent>
  );
}

借助 command 和 commandfor 属性,按钮现在可以声明式地对其他元素执行操作,从而实现框架的人体工学设计,而不会牺牲灵活性。commandfor 按钮接受 ID(类似于 for 属性),而 command 接受内置值,从而实现更便携、更直观的方法。

以下 HTML 会在按钮和菜单之间建立声明式关系,以便浏览器为您处理逻辑和无障碍功能。您无需管理 aria-expanded 或添加任何其他 JavaScript。

<button commandfor="my-menu" command="show-popover">
Open Menu
</button>
<div popover id="my-menu">
  <!-- ... -->
</div>

如果您之前使用过 popover,可能对 popovertarget 和 popovertargetaction 属性很熟悉。它们的运作方式分别与 commandfor 和 command 类似,但仅适用于弹出式窗口。command 和 commandfor 属性完全取代了这些旧属性。新属性支持旧属性支持的所有功能,同时还添加了新功能。

command 属性具有一组内置行为,这些行为会映射到互动元素的各种 API:

  • show-popover:映射到 el.showPopover()
  • hide-popover:映射到 el.hidePopover()
  • toggle-popover:映射到 el.togglePopover()
  • show-modal:映射到 dialogEl.showModal()
  • close:映射到 dialogEl.close()

这些命令会映射到其 JavaScript 对应项,同时简化无障碍功能(例如提供 aria-details 和 aria-expanded 等效关系)、焦点管理等。

<button commandfor="confirm-dialog" command="show-modal">
  Delete Record
</button>
<dialog id="confirm-dialog">
  <header>
    <h1>Delete Record?</h1>
    <button commandfor="confirm-dialog" command="close" aria-label="Close" value="close">
      <img role="none" src="/close-icon.svg">
    </button>
  </header>
  <p>Are you sure? This action cannot be undone</p>
  <footer>
    <button commandfor="confirm-dialog" command="close" value="cancel">
      Cancel
    </button>
    <button commandfor="confirm-dialog" command="close" value="delete">
      Delete
    </button>
  </footer>
</dialog>

点击 Delete Record 按钮会以模态方式打开对话框,而点击 CloseCancel 或 Delete 按钮会关闭对话框,同时还会向对话框分派 "close" 事件,该事件具有与按钮值匹配的 returnValue 属性。这样一来,除了对话框上的单个事件监听器之外,就无需再使用 JavaScript 来确定后续要执行的操作:

dialog.addEventListener("close", (event) => {
  if (event.target.returnValue == "cancel") {
    console.log("cancel was clicked");
  } else if (event.target.returnValue == "close") {
    console.log("close was clicked");
  } else if (event.target.returnValue == "delete") {
    console.log("delete was clicked");
  }
});

除了内置命令之外,您还可以使用 -- 前缀定义自定义命令。自定义命令会在目标元素上分派 "command" 事件(就像内置命令一样),但除此之外,绝不会像内置值那样执行任何其他逻辑。这样,您就可以灵活地构建可以以各种方式响应按钮的组件,而无需提供封装容器组件、遍历目标元素的 DOM 或将按钮点击映射到状态更改。这样,您就可以在 HTML 为组件提供 API:

<button commandfor="the-image" command="--rotate-landscape">
 Landscape
</button>
<button commandfor="the-image" command="--rotate-portrait">
 Portrait
</button>

<img id="the-image" src="photo.jpg">

<script type="module">
  const image = document.getElementById("the-image");
  image.addEventListener("command", (event) => {
   if ( event.command == "--rotate-landscape" ) {
    image.style.rotate = "-90deg"
   } else if ( event.command == "--rotate-portrait" ) {
    image.style.rotate = "0deg"
   }
  });
</script>

由于 commandfor 属性采用 ID,因此在穿越 shadow DOM 时存在限制。在这些情况下,您可以使用 JavaScript API 设置 .commandForElement 属性,该属性可跨阴影根设置任何元素:

<my-element>
  <template shadowrootmode=open>
    <button command="show-popover">Show popover</button>
    <slot></slot>
  </template>
  <div popover><!-- ... --></div>
</my-element>
<script>
customElements.define("my-element", class extends HTMLElement {
  connectedCallback() {
    const popover = this.querySelector('[popover]');
    // The commandForElement can set cross-shadow root elements.
    this.shadowRoot.querySelector('button').commandForElement = popover;
  }
});
</script>

未来的提案可能会提供一种声明式方式,用于跨阴影边界共享引用,例如引用目标提案

我们将继续探索新的内置命令的可能性,以涵盖网站使用的常用功能。开放式界面提案中介绍了建议的想法。我们已经探索了一些想法:

  • 打开和关闭 <details> 元素。
  • 适用于 <input> 和 <select> 元素的 "show-picker" 命令,映射到 showPicker()
  • <video> 和 <audio> 元素的播放命令。
  • 复制元素中的文本内容。

我们欢迎社区提供反馈。如果您有任何建议,请随时在 Open UI 问题跟踪器中提交问题。

如需详细了解 command 和 commandfor,请参阅规范和 MDN

你也许感兴趣的:

共有 247 条讨论

  1. 虽然编程语言理论家们从 80 年代起就一直在猜测 “goto ”的更强大的表亲 “comefrom”,但它只在 intercal 中实现过。Intercal 虽然在安全性、性能和人体工学方面明显优于 C 等语言,但却一直难以打入商业市场(可能是因为越差越好)。看到 javascript 从 intercal 中集成了这一功能,我们感到非常兴奋–希望这能带来礼貌编程的热潮,就像 javascript 对基于闭包对象的接受推动了函数式编程成为主流一样。

    1. 哈哈,我完全忘了 intercal 和 “comefrom”。

      真是天才。它预见并巧妙地总结了我在维护和支持使用反应式编程设计模式编写的代码时遇到的问题,这些问题已经存在了 40 年之久。

    2. C# 也有 COMEFROM:https://github.com/dotnet/roslyn/blob/main/docs/features/int…

      它们使手动使用变得繁琐,但并非不可能

    3. >希望这将导致礼貌编程的兴起

      但不能太礼貌。编译器不会喜欢的。

        1. 说起话来像个会吃的西格玛–没有帽子。

      1. 当然不会。惺惺作态的代码是非常令人讨厌的。

        1. 心理antic语言的下载地址是什么?

    4. command 和 commandfor 与 comefrom 有什么相似之处?

      在我看来,它们与 goto 很相似。对于 goto,触发器指定要做什么。这就是 command 和 commandfor 的作用。

      对于 comefrom,要做什么指定了触发器。这似乎类似于 Javascript 中现有的 document.addEventListener()。

      1. 我也不明白。它甚至与 goto 都不相似。它只不过是方法调用,而方法调用与 goto 完全不同。

        1. 梵语是用梵文书写的,有近十亿人在使用,所以任何能理解 Unicode 标识符的语言都能很好地处理它。如果你想挑战一下,也许可以试试 Rongorongo 或 Klingon 等语言。而我,我想用真正的象形文字来写我的代码。

          1. TeX 允许你重写解析器(ala TeXInfo),使用 unicode 引擎将允许你使用 UTF。

            TeX 还允许你嵌入和强制使用字体。

            最后一步: 使用像 Lyx 这样的软件,让你在书写的同时看到嵌入的字体。

          2. 哇。你的评论中错误真多:

            介绍:

            他在高中学习了 3 年梵语,然后在大学学习了 2 年梵语,在高中学习了 4 年印地语,包括这两种语言的语法、词汇和文学(诗歌和散文),还用印地语写作文。

            成年后的大部分时间都讲印地语。

            这两种语言都是用梵文书写的。

            >Sanskrit 是用 Devanagari 书写的,而 Devanagari 有将近十亿人在使用,因此任何能识别 Unicode 标识符的语言都能很好地处理它。

            编程)语言能否理解 Unicode 与使用梵文或梵文的人数无关,所以你的说法缺乏逻辑性。

            您说

            >梵语是用梵文书写的,有近十亿人使用梵文。

            这种说法显示了你对事实的无知。

            原因就在这里:

            作为一个生活在印度的印度人,我已经非正式地了解了这些观点,但我还是在谷歌上快速搜索了几下,以进行验证:

            按印度母语使用者人数列出的语言列表:

            https://en.m.wikipedia.org/wiki/List_of_languages_by_number_

            印度人口统计:

            https://en.m.wikipedia.org/wiki/Demographics_of_India

            https://www.google.com/search?q=number+of+people+who+use+dev

            上述搜索结果的最上面一段:

            >今天,梵文字母被用来书写三种主要语言: 印地语(使用人数超过 5.2 亿)、马拉地语(使用人数超过 8,300 万)和尼泊尔语(使用人数超过 1,400 万)。

            即使加上散居在斐济、加勒比海等地的印度人数量,也不会达到近十亿。

            你做了一个错误的假设:

            > 你想提出挑战,也许可以试试朗戈龙戈语或克林贡语。

            你认为我在提出挑战。我没有。

            你似乎没有意识到我是在开玩笑:

            >但是……Perl 支持梵文吗?

            1. 老兄,我觉得你不会开玩笑。去看心理医生吧。

    5. 这很有趣,我把它看成是一个死板的笑话。

      1. 是的,我同意。书呆子气太重了。

    6. 也许我不知道这里的理论是什么。作为一个非 JS 开发人员,他们似乎只是为事件添加了一些 OO 糖。我不太愿意称它为糖,因为它看起来比 “my-menu.show-popover() ”要啰嗦得多,但总比全局监听器要好吧。

      1. COMEFROM 是构成 Intercal 语言的众多精彩笑话之一。我建议您阅读语言规范。

        当然,COMEFROM 的兄弟姐妹是 COBOL 中的 ALTER GOTO。

            1. 感谢您的更正!我已经记住了 COME FROM 是最初的 INTERCAL 的一部分。我错了。

      2. 这是一个合理的类比,但我认为它更新颖、更有趣的地方在于:

        – 将一个元素与另一个元素联系起来的声明式机制

        – 具有一系列语义,用于声明通过它们之间的关系调用的交互性

        – 在高层次上,明确保证一致的可访问性和用户体验

        在很多方面,这与人们希望多用 HTML 少用 JS 时所描述的情况很相似。(除了完全拒绝网络交互性的极端极简主义版本)。

    7. 更不用说可逆计算的 “gofrom ”和 “cometo ”了。

      1. 我的新语言将包括 “thataway”、“overonder ”和 “uptown ”结构。

          1.   for (let i = 1; i <= 4; i++) {
                  woman.getOn(floor);
                  try {
                      getDown();
                  } catch (e) {
                      if (e instanceof NotUpError) {
                          getUp();
                          getDown();
                      }
                  }
              }
      2. 鉴于 “醒过来 ”的意思是 “恢复意识”,这副对联听起来应该与线程睡眠控制有关。

            1. 你们从 2017 年开始开展的 “堆叠缩略词 ”运动取得了巨大成功,我想把 2000 年代中期在 Neopets 论坛上独立发起这项运动的功劳归功于你们,但我自己当然无法做到这一切,因此我想提议开展下一项运动。

              让我们重拾代词副词!你可能已经熟悉了 “因此 ”或 “鉴于 ”等经典副词。为什么不恢复所有这些副词呢?“据此 “和 ”此后 “不再是律师的专利。仅这一点就足以成为史诗般的经典,但我们必须超越这一点。很难相信有人真的用过 “therethroughout ”或 “wherewithin ”这样的词,但我们可以确保有人用过。

              你甚至可以自己创造!

              只要把任何指示代词(这/那/这些/那些)、疑问代词(什么/哪个/谁/在哪里)或第三人称人称代词,根据你是想表示在什么地方、从什么地方来还是到什么地方去,把它变成相应的位置副词就可以了:

              This -> Here/Hence/Hither;

              That -> There/Thence/Thither;

              What/who/which -> Where/Whence/Whither;

              Him/Her/Them -> There/Thence/Thither; etc.

              有道理吗?没有问题?很好

              现在选择你最喜欢的介词,把它贴在末尾。别忘了尝试一些古介词,比如 “anighst”、“overthwart”,还有一个非常好的介词–“withinside”。这个词的意思是 “在内部”,我相信你已经看到了它的潜力。

              “我该去哪个地方?” 不对 “我应该去哪里?” 这才对嘛。

      3. >可逆计算的 “gofrom ”和 “cometo”。

        哇,哦,我是说,哇,先生。

        你激发了我更深的呼吸。

        由此,我对深度学习产生了不可逆转的渴望。

    8. 咳咳,我在此提出两个新的语言结构和相应的关键字,它们可以在许多语言中广泛应用(听起来更像是功能性的,而不是实现性的),至少是过程式/命令式语言:

      goto和comefrom

      以及可选的同义词:

      离开和返回

      以上每个关键字可以缩短到只有两个字母:

      go 和 co

      le和re

      为简洁/简明爱好者而设。

      公共关系开放。

      1. > 可选同义词

        Leave 我同意,但 “return from ”与 “come from ”不同,后者是一个非本地的 goto,难道 “return from ”不能正确地描述一个继续吗?

        1. 我还没开始学,就已经不理解连续运算了。

          1. 我不知道你是不是认真的。延续性很有趣,所以我把它贴出来,希望能帮到别人。

            在不令人困惑之前,它们都是令人困惑的。将堆栈帧建模为独立状态。当你从一个函数返回时,堆栈框架可以继续存在。之后,将堆栈指针放回之前返回的框架中。

            如上所述,在更新堆栈指针时添加传递参数的约定。现在,你有了连续函数。

            1. 所以你可以把堆栈指针放回之前返回的帧中? 这可能就是他们在开始之前就不理解连续性的原因。

              1. 这就是棘手的地方。现在已经没有堆栈了。函数的激活记录是堆分配的,只要有必要,就可以一直存在。

                1. 我在解释这个笑话?因为我回复的那个人似乎在怀疑这是否真的是个笑话,而对我来说,从结构上看这显然是个笑话。

                2. 公平地说,它仍然是一个栈(数据结构)。只是内存不再连续而已。

                  当然,现代的 LLVM 已经将堆栈分割成若干块(至少给定了某些标志),所以无论如何,堆栈都可能不是连续的。

  2. > 按钮……是网络互动的基础。

    这句话很好地概括了 “旧 ”网络和 “新 ”网络的区别。当然,超链接才是网络互动性的基础。

    1. 我喜欢这句话,但我不太确定。

      超链接不是互动的。它们是书签。当我点击一个链接时,我是否与网页产生了互动?某种意义上是的。但我改变了它的状态吗?没有,我只是从一个静态的地方移动到了另一个静态的地方。

      1. 超链接+查询参数是提供交互性的一种方式(当然需要服务器往返)。

        例如,要对表格进行排序,可以让列标题成为指向同一网址的链接,并加上?sort_by={colname}。

        然后服务器看到后进行排序并返回。

        输入字段的 “动态 ”数量也是如此。当点击添加字段链接时,重新加载 “num_fields=2”。

        1. > 超链接+查询参数是提供交互性的一种方式(当然需要服务器往返)。

          如果你想迂腐一点,那就不是了。至少,如果你想遵守规则的话,GET 请求绝不能改变服务器上的可见状态。

          因此,交互性将仅限于搜索/过滤现有内容,但不能添加新内容。

          为此,你需要使用 POST 请求,即按钮。

          1. 很酷的评论,让我有了一些思考,如果你不介意的话,我希望你能说清楚。

            在 GET 请求参数中进行排序不会改变服务器的状态。它只会改变数据表示,而不会改变底层资源。

            这符合 “安全 ”方法定义(RFC 9110)https://www.rfc-editor.org/rfc/rfc9110.html#safe.methods。

            但我同意排序感觉像是在 “做什么”……这也是我在思考这个问题时卡住的地方。

            但你的意思是,客户端视图状态(排序数据的示例)不应由服务器通过 GET 来处理?

            如果你是这么想的,我想了解更多关于这条规则的信息。

            1. 啊,对不起。不,我只是为了简洁起见省略了排序。查询结果的排序完全是其参数和现有服务器状态的函数,因此在 GET 请求中进行服务器端排序是完全正确的。

              但改变资源的 “默认 ”排序顺序(通过在磁盘上对行进行物理洗牌或通过设置某些服务器端全局变量)就不行了。

              我认为这就是对列表进行排序复制(同时保留原始列表不动)和对列表进行内联排序之间的区别。

              这同样适用于过滤。

              即使将处理后的结果存储在缓存中也不能验证惰性,因为从客户端的角度来看,无论服务器是重新计算结果还是从缓存中提取结果,下一次请求的行为都是一样的。

              (编辑:意识到我把 “empotent ”和 “safe ”方法搞混了。我说的是 “安全 ”方法–但这些方法适用于 GET 请求,也可以用超链接来表示。)

          2. GET 请求总是会改变服务器上的状态,因为我们有日志。此外,日志通常由 XML 解析器解析,而 XML 解析器往往容易出错。

            1. 这就是通过服务器上的可见状态来定义幂等性的原因。服务器上发生的事情并不重要,但 GET 请求不应改变客户端可见的后续请求的结果。例如,通过 GET 请求添加或修改文章或博客条目就违反了规则。

              (在实践中,没有什么能阻止你忽略这一要求,但这可能会导致丑陋的意外,例如爬虫会因为抓取了 /delete 链接而触发大规模删除)。

        2. 在我看来,这只是一个技术问题。这和使用按钮+JS 得到的体验是一样的,只不过延迟更长。

        3. > 超链接+查询参数是提供交互性的一种方式(当然需要服务器往返)。

          无需服务器处理:返回的页面可以与获取 GET 参数的 onload 函数完全相同,并在客户端进行处理,例如重新排列表格的行。

        4. 输入 type=“submit” 会在 1993 年显示一个按钮。没有 javascript,就像一个超链接,但仍然是一个按钮。

          1. 当时最明显的区别(在使用 JS 和 CSS 之前)是,浏览器会非常明显地显示链接的目的地,而输入按钮则完全不透明。我们在 a href 标签内创建了带有图片的按钮,使按钮的样式(在 photoshop 中)与链接相似,并生成 GET 请求。我们可以添加查询字符串。唯一能进行 POST 请求的方法是在表单中添加一个按钮。

      2. 作者可能指的是超媒体。按钮和链接只是一种手段,如果用户不点击或移动鼠标,就不会有任何互动。

        当然,我们也可以讨论纯客户端的交互性(如油漆应用程序等厚客户端),但这不是主题。

      3. 有两个例外: – url hash 链接和 css :target 伪类。- 以 iframe 为目标的链接

        我不建议随意使用这些模式,但它们确实适用于轻度交互。

        1. 不过,这些只是让超链接表现得像按钮一样的额外功能。当然,这是严格定义下的 “超链接”,即两个网页之间的链接。

    2. 我不知道作者是否真的考虑过网络互动性的基础,或者他们只是让人工智能为他们关于新按钮功能的文章写一个好听的引言。

    1. WebKit 采取了 “支持 ”立场。https://github.com/WebKit/standards-positions/issues/264

  3. 规范

    按钮元素,命令属性:https://html.spec.whatwg.org/multipage/form-elements.html#at…

    按钮元素,命令属性:https://html.spec.whatwg.org/multipage/form-elements.html#at…

  4. 这真的是大约 30 年前 Next、Be、Apple 以及其他公司使用的动作/消息模式吗?

    它在某种程度上是有用的,但由于需要的复杂性和保持基本底层设计模式的愿望,它基本上演变成了基于界面的控制器模式。因此,一旦这个盒子被打开,我希望能看到大量的改进请求:)

    一些浏览器供应商(可能是网景公司的 IFC)曾推出过一个早期的 Java UI 工具包,可以将动作元素这样串联起来。

    1. 你以为网络落后了 15 年,但它很快就赶上了 30 年前的技术!

      这样的新闻让我感到恶心。我本以为它能在我有生之年成为可用之物,但我都有膝关节骨关节炎了,它却还在重塑穷人的目标行动。可悲的小丑。

    2. 这并不是说这个想法是全新的,只是它现在已经在 Chrome 浏览器和网页规范中实现了。

  5. > 新的 command 和 commandfor 属性增强并取代了 popovertargetaction 和 popovertarget 属性。

    这些属性不是刚成为可用的基准线吗?替换它们是什么意思?是否有一天会像导入断言/属性一样移除它们?有时,这样的事情会让我怀疑负责人是否意识到,他们放入的所有东西都会永远存在。你不能只是发布一个更新,然后删除你(“你 ”是指:你公司里的网络开发人员,他们碰巧也在同一家公司里开发浏览器)不再需要的东西。

    1. 我也觉得奇怪。如果他们先为媒体控件实施这个功能,然后再把弹出窗口的属性整合到这个功能中,那就更合理了。这感觉就像是创下了网络功能最快淘汰的纪录。

  6. 2025:

    > 虽然 HTML 为按钮提供了点击处理程序,但由于内容安全策略(CSP)规则的限制,在演示或教程之外通常不允许使用这些处理程序。

    2033:

    > 虽然 HTML 为按钮提供了命令和命令执行处理程序,但由于内容安全策略 (CSP) 的规定,在演示或教程之外通常不允许使用这些处理程序。

  7. 我不知道这是我大脑工作的方式,还是审美的问题,但我对使用字符串编程完全过敏。我完全理解这背后的原因,尤其是在可访问性方面,但我对使用元素 ID 来实现另一层网络应用行为并不感到特别兴奋。

    1. 字符串代码是我最喜欢的代码气味范例。你可以这样做,它可以工作,是的,只要你写得正确,它就能正确工作,但你充其量只是在路上踢了一脚而已。

      HTML 元素具有天然的字符串特性,这在 HTML 描述文档时是合理的。但在复杂的应用程序中,这就有很多不足之处了。这简直就是黑客。

      这并不是说正在讨论的功能是一件坏事。很明显,它是一个黑客。在这样一个成熟的平台上,“全部扔掉 ”和 “再打一个补丁 ”之间的余地实在太小了。

    2. 我同意,但至少它是一致的。这也是 `for`、`list`、`aria-labelledby`、`aria-describedby` 和许多其他属性的工作方式。

    3. 我也不喜欢它,但至少我们可以用框架来铺垫它,除非你对框架过敏。它是一个很好的构件。

      1. 没错,别误会我的意思,我认为事件很好,即使使用现有的框架,这也是一个很好的简化。

        如果它是图灵完备的、无主见的,并且不使用模板,我就可以把肾上腺素收起来了。

  8. 有阅读障碍的我对 HTML 中的命令和征服感到兴奋

    1. 就在今天,我发现有一个 Red Alert 移植到 Three.js 的项目正在进行中:https://github.com/chongdashu/CnC_Red_Alert-ThreeJs

    2. 我也是。我在阅读关于按钮的文章时……还在想游戏在哪里?

      不过,按钮还是很有趣的。

    3. 我肯定是在读关于按钮的文章,等着看这将如何以某种新颖的方式解锁《命令与征服》的转译能力。

      不过我还是很欣赏它的新功能。

  9. 看起来他们不应该在没有完整 API 的情况下实现这个功能。看起来通过 HTML 可以实现所有 JavaScript 功能,包括高级 API,而不是 5 条左右的命令。那可能会有成千上万条命令……

    1. 我认为这并不难实现,您可以抽象地建立一个系统,将命令字符串翻译成以下格式:

      1. 用破折号将字符串分割成一个数组

      2. 2. 将第一个数组项的第一个字符小写,其余的第一个字符大写

      3. 将这些字符串串联起来

      4. 执行`document.getElementById(element.commandfor)[concatenated]()`。

      很明显,这样做没有无数的检查来确保元素存在、方法存在、方法不需要参数等。

      这样也可以轻松实现自定义命令,因为您可以使用 `document.getElementById(element.commandfor).myCustomMethod = function() { /* … */ }`

      1. 鉴于这是内联 JS 的安全替代方案,执行任意 JS 将适得其反。

    2. 真正强大的是自定义命令和实现这些命令的标准方法。内置命令始终只是一种便利,随着复杂性的增加,许多命令都会转换为自定义版本。

      即使是 close 这样的命令,最终也会变成 –my-close,而且在调用 dialogEl.close() 之前,还会执行若干额外的检查。

    3. 我也是这么想的,我很难想象一个相当复杂的用户界面在什么情况下不需要使用 JS。我想这提供了一个逐步采用的路线图。

  10. 改进和扩展 HTML 是件好事,但仍有很长的路要走。HTMX 的人有一些不错的想法。

    1. 不,“他们 ”继续扩展和 “改进” HTML 才是可怕的。

      这就是独立网络浏览器似乎不可能被创建和维护的原因:因为在过去二十年中,本应是一个简单、可预测的规范,却成了一个快速移动的目标,光是跟踪就需要大量资源。

      如果我们不在 HTML 规范中塞满没人想要的臃肿内容,而我们又都安装了扩展来禁用这些内容的话,我们本可以有十种不同的开源网络浏览器(比如 Konqueror)……

      1. 我确信这是唯一的目标。每个有一两个神经元的人都能看出,互联网并不使用网络技术,而且会尽快将其抽象化。这些人只是通过添加无意义的废话来增加他们公司的安全性,而这些废话在现实中没有任何作用。

      2. > 我们可以有十种不同的开源网络浏览器

        目的是什么?

        1. 理智的竞争,开发者和最终用户都会从竞争中受益。这只是企业锁定。当用户在使用网络应用时必须安装 Chrome 浏览器时,作为一个平台,我们是在辜负他的期望,而开放网络也会因此停滞不前。

        2. 浏览器完全(或大部分)使用内存安全语言编写。

          LadyBird 现在使用了一些 Swift,但大部分代码仍是 C++。该浏览器虽然令人印象深刻(我非常感谢它的存在),但要真正取代 Chromium/Blink、Firefox/Gecko 或 Safari/WebKit,还有很长的路要走,用 Swift 重写所有现有代码将是一项浩大的工程。

          Chromium 和 Firefox 也使用了一些 Rust,但完全用 Rust 重写这些浏览器将是一项更大的工程。

          相比之下,一个更简单的浏览器规范将使使用内存安全语言创建一个全新的浏览器变得容易得多。这不仅能大大提高所有操作系统的安全性,因为浏览器是一个巨大的漏洞载体,而且还能创建新的、更安全的操作系统。目前,使用 RedoxOS(一种用 Rust 编写的操作系统)等系统的最大障碍可以说是它没有一个真正适用于大量网络的网络浏览器。但如果网络浏览器的规格更简单,那么创建一个这样的操作系统就会容易得多。

          显然,我们不可能回到过去,制定一个更简单的网络规范,而且删除功能也是一个糟糕的想法,因为这会破坏现有的网站。但我认为,在添加新功能之前,我们应该慎重考虑。我认为完全冻结功能是矫枉过正–对于许多网络开发人员来说,一些新功能可以使网络开发变得更简单、更干净。我确实认为需要考虑一下网络浏览器的最终目标是什么。有这样一个目标吗?还是我们将永远以目前的速度不断增加新功能?如果是这样,那么构建一个新的、更安全的浏览器的希望就渺茫了。就我个人而言,我更喜欢更安全的浏览器,而不是功能更多的浏览器。

          相比之下,C++ 一直在增加大量新功能,但几乎没有开发人员了解它的全部功能,尽管它的目标是让事情变得更简单,但我认为许多开发人员对它还是一如既往地感到迷茫,因为他们仍然要与以旧的和不同的方式编写的代码打交道。在网络开发方面,某些 JS 和 CSS 功能确实简化了开发,让事情变得更简单,但我认为可以说,并非所有新增功能都是如此。

  11. 不使用 JS 的基本点击事件。

    似乎只适用于弹出窗口?

    也许是谷歌广告对不使用 JS 的超小部分广告市场的一种推动。

  12. 在这一变化和其他变化之间,我担心他们只是在往墙上扔越来越多的东西,以扩大他们在浏览器上的护城河。

    command 和 commandfor 真的是个好主意吗?我理解它的意义,但它似乎又增加了一层认知负担。

    为什么不把同样的原理应用到 CSS 中呢?如果我可以为一个元素创建一个 CSS 选择器,但让其结果针对其他元素,那么就可以达到同样的效果,甚至更多。这只需要增加几个伪选择器。虽然可能没有必要,但我认为对状态发生变化的属性进行标记可能是明智之举。比如

        #my-popover { display:= none; }
        #my-button:click {
          |> #my-popover {
            display:= block;
          }
        }
    

    其中 `|>` 表示重定向,而 `=` 表示属性可以发生状态变化。(也许语法可以更好,但你可以理解)。

  13. 我不明白为什么 JavaScript 已经这样做了,他们现在还要这样做。这只会增加熵,而没有明确的值。

  14. 我想知道这些新的 html 功能最终是否会得到推广,有人知道最新的弹出窗口和对话框元素的使用情况吗?我之所以问这个问题,是因为我一直在想,基于 JavaScript 的对话框无处不在,谁会使用它们呢?为了实现语义化?但现在还有谁会真正编写语义网络呢?也许是为了人工智能代理?为什么要继续膨胀网络平台?

    1. 我不知道还有谁在这么做,但我和我的团队一直在使用语义 HTML,包括对话框元素。

      不幸的是,这是我至少能做到的对用户的尊重,因为我无法控制用户在浏览器中加载可怕的跟踪脚本的决定。

      1. 我真希望每个人都能尽可能使用语义 HTML。这对可访问性的提升是巨大的。

        以 JS 对话框或弹出菜单为例。你会认为这对每个人来说都很容易使用,但屏幕阅读器用户可能根本意识不到它的存在。即使他们意识到了,他们仍然需要在线性的、可能非常杂乱的页面中找到它。它可能就在 “打开菜单 ”按钮旁边、页面底部或其他地方。菜单/对话框也可能在用户移动焦点试图找到它时立即消失!

        这些都是我经常遇到的问题。

        我认为任何能让开发人员更轻松地进行无障碍访问的东西都是好东西,尤其是在无需考虑无障碍访问的情况下就能正常工作的时候。

    2. 谷歌就是谷歌,他们这么做可能只是为了从不太可能被屏蔽的弹出式广告中榨取收入。

      这也解释了为什么他们会突然决定开发 HTML 对话框。在他们看来,对话框就是弹出窗口,而无法屏蔽的广告弹出窗口就等于给他们带来了更多的收入。

      也许,他们是在为自己的未来创造一个可以利用的规范领域。当然,是以一种扭曲的方式,通过扩展清单 V4 或类似的东西。

      1. 我觉得你混淆了一些东西。原生对话框元素作为弹出窗口更容易阻止,例如,你只需根据标签名称选择所有对话框元素,然后将它们转换为 div 内嵌元素或类似元素。如果对话框是由使用随机 ID 或生成类名的 div 的 javascript 库创建的,就无法可靠地做到这一点。

  15. 哦,这似乎是对 popover 特定属性的一个很好的概括。可以将 <button type=“submit”> 替换为 <button command=“submit”>,并将 commandfor 默认为祖先表单。

    1. 有趣的是,他们终于可以废弃按钮上的表单属性了…

  16. 我们需要一个合适的富 UI 应用程序执行环境,而 HTML 作为一个主要面向文档的平台,如果不能改装以提供这样的环境,那么我们就需要一个新的环境了

    1. 伊恩-希克森(Ian Hickson)是 HTML5 规范的作者,同时也是 Flutter 的领导者,他撰写的《迈向现代网络协议栈》(Towards a Modern Web Stack)[0][1]一文正是在讨论这个问题,以创建一个能处理现代网络应用的新协议栈。Flutter 是其中的一部分,但他谈到的是一个更通用(可推广)的堆栈。他还在 HN 线程中阐述了背后的原理。有趣的是,HN 上的某些人似乎并不完全喜欢它,看到他们崩溃的样子有点好笑。

      [0] https://news.ycombinator.com/item?id=34612696

      [1] https://docs.google.com/document/d/1peUSMsvFGvqD5yKh3GprskLC… (实际文档阅读)

      1. 我看了希克森的提案,很有意思。

        不过我注意到,他建议从与我相反的方向来解决问题,尽管我认为他的方法也是可行的。我的梦想是建立一个类似 HTML 的平台,以支持丰富的用户界面应用程序,并提供更高级别的可配置基元,从而消除对大量脚本和依赖性的需求。他谈到的是提供可适当配置的低级基元。

        如果构建得当,这两种方法都能支持开发人员实际想要做的事情。让我对 WASM 望而却步的一点是,它需要依赖 JS 进行引导。如果采用这种方法,我就不想再在管道中使用 JS。高级基元的优势在于,开发人员想要构建的东西有更多已经内置于平台中。

        1. 你试过 Flutter 吗?虽然网络性能还有待提高,但它运行得很好。

    2. +1. 网络平台是声明式和命令式的有趣结合,但两者都没有好处。

      在我看来,网络平台需要像 Qt Widgets、AppKit 或 UIKit 那样的保留模式用户界面模型。这样,像 Figma 这样的桌面应用程序就不需要编译为 WASM,也不需要为其用户界面渲染 WebGL。他们只需将 <divs> 视为视图或图层即可。

      1. 我知道你持怀疑态度,但这些技术的失败并不意味着新的 HTML 类平台不会成功。

        从那时起,我们在安全、DX 和用户体验方面学到了很多。新平台可以应用所有这些技术。

    3. 乔伊-赫斯(Joey Hess)最近提出了这样一个建议–https://news.ycombinator.com/item?id=43202773

  17. 哦,它又回来了!

    呼吁:https://news.ycombinator.com/item?id=40888664

  18. 作为一个网络编程新手,我很好奇。第一个例子是

     document.addEventListener('click', ...
    

    而不是

     someButton.addEventListener('click', ...
    

    事实上,所有框架示例显示的都是按钮 onClick,而不是文档 onClick。

    我知道在某些情况下,将事件监听器添加到文档是正确的,但我从未见过这种按钮类型的情况。

    这种按钮模式常见吗?它能解决什么问题?

    1. 使用 document.addEventListener 意味着即使 DOM 更新了也能正常工作,而无需添加新的事件监听器。如果我不希望 DOM 发生变化,我会更倾向于使用类似的方法:

        document.querySelectorAll('.menu-wrapper')).forEach(menuWrapper => {
          const button = menuWrapper.querySelector('.menu-opener');
          const content = menuWrapper.querySelector('.menu-content');
          if (!content || !button) {
            return;
          }
          button.addEventListener(() => {
            button.setAttribute('aria-expanded', 'true');
            menu.showPopover();
          });
          content.addEventListener('toggle', e => {
            // reset back to aria-expanded=false on close
            if (e.newState == 'closed') {
              button.setAttribute('aria-expanded', 'false');
            }
          });
        });
      

      React 的示例似乎也有点奇怪,如果 “open ”回调实际上调用的是 “showPopover()”,而不是只调用 “setIsOpen”,那么 “useEffect ”就完全多余了。我认为这样的代码会清晰得多。

      1. > 即使更新了 DOM,也能正常工作,无需添加新的事件侦听器

        答对了。

        兄弟姐妹的评论也说到了这一点,但在 Google 上搜索这种技术的 “神奇短语 ”是 “事件委托”。还有两个短语:委托依赖于 “事件冒泡”,而冒泡可以通过 “事件捕获 ”来中断。(您很少会想要捕获事件,这相当于 JS 的“!重要”)。

        一个不错的概述:https://javascript.info/bubbling-and-capturing

    2. 一般情况下,当你有很多元素需要监听,或者特别是元素会被动态添加和移除时,你可以采用 “文档 ”方式(通常称为 “委托 ”监听器)。

      如果直接监听每个目标元素,就必须找到这些元素并全部循环一遍,在设置监听器时它们必须存在,而且必须确保每次添加具有相同行为的新元素时都添加监听器。如果你在文档(或某个适当的父元素)中监听,然后检查触发事件的元素是否与你要处理的事件相匹配,那么你就可以拥有一个监听器,它将适用于所有匹配的子元素,无论它们是在何时何地添加的。

    3. 这确实是一种常见的网络模式,如果你想搜索更多相关信息,它被称为 “事件委托”!正如其他人所说,它允许一次性绑定一个事件处理程序,这样,无论用户交互导致页面内容发生多大变化,它都可以坐在那里等待触发(而不是每次创建新按钮或可交互元素时都绑定一个新的事件处理程序)。

  19. 这基本上就是 HTMX。他们为什么不把它原生集成到浏览器中呢?

  20. 既然都是关于按钮的,他们错过了将其命名为 butfor 的机会,实在是太可惜了。

    1. 叹气。好吧,我来做。

      什么是 butfor?

  21. <style> #my-popover { display: none; border: 1px solid black; padding: 10px; margin-top: 10px; } #toggle:checked + #my-popover { display: block; } </style> <body>

    <label for=”toggle” id=”my-button”>Toggle Popover</label> <input type=”checkbox” id=”toggle” style=”display: none;”> <div id=”my-popover”>My content!</div>

    </body> Wont this work a toggle popup with html+css only no js yet interactive with label

    1. 这个黑客的可访问性非常糟糕。首先,<label>默认情况下是不可聚焦的,因此键盘用户根本无法切换弹出窗口。而且我认为没有 JS 是无法动态设置 ARIA 属性的。

  22. 这太好了!

    我正在开发一款应用程序,这种模式非常有用。该应用程序将服务器端的 html 与 React 的一些元素混合在一起,用于结账流程。Command 和 commandfor 将使两者的连接更加完美。采用岛屿模式的应用程序也将受益于这一功能。

    题外话:我认为未来网络最大的问题将是功能过时有多难。

    也许我们需要 Html6 从浏览器中删除/简化功能?

  23. >新的 command 和 commandfor 属性增强并取代了 popovertargetaction 和 popovertarget 属性。

    起初我很担心,因为他们最近刚刚添加了弹出窗口 API,该 API 本身取代了<dialog>,但这仍然使用的是相同的 API,只是从 HTML 调用的方式不同而已。不过,我还不太清楚他们的长期目标是什么?取代 UI 工具包?通过移除某些函数中的 js 来简化状态框架?例如,播放/暂停功能。[0] 对于一个简单的网站,你不需要添加任何此类功能,因为浏览器内置的视频播放器可以让你进行播放、暂停、静音等操作。因此,对于简单的网站来说,这并不是必须的。但对于更复杂的网站,你应该已经在使用 js了吧?

    我很喜欢这里对项目的总体介绍,这似乎回答了上述问题:

    >但是,自从上一次对表单和用户界面进行重大修改以来,又过去了 15 年。如今,大多数复杂的网络项目所需的功能远远超出 HTML5 表单和用户界面控件所能提供的范围。因此,当今的网络开发人员往往会求助于庞大的 JavaScript 框架来构建设计人员所要求的用户界面。这些自定义界面很少是完全可访问的。它们会减慢页面运行速度、耗费电量、打开安全漏洞并排斥用户。

    >此外,当今的项目往往拒绝现有的内置表单和用户界面控件,因为他们需要对界面的外观和感觉有更多的控制权。网页设计师要求能够通过页面上的每个元素(包括所有用户界面)来表达他们项目的品牌。目前的表单和网站级用户界面控件无法实现这一点[1]。

    因此,我们的目标是为 HTML 原生用户界面的用户界面组件去除 JS。不过,至少在上述视频示例中,有些网站希望在用户点击屏幕时有不同的行为。有些会弹出视频播放栏和设置,有些会立即暂停,有些会在播放栏隐藏时暂停,在播放栏可见时移除,等等。我不知道没有 JS 如何做到这一点,在这一点上,el.playing = false 似乎比使用按钮命令属性要好得多。或者这只是一个糟糕的例子?

    [0] 文章中的链接:https://open-ui.org/components/future-invokers.explainer/

    [1] https://open-ui.org/charter/

    1. 弹出窗口 API 并不是 <dialog> 的替代品。如果用例合适,它可以替代某些类似对话框的功能。

    2. 弹出窗口和 <dialog> 完全是两码事。此外,没有任何正文取代或废弃 <dialog>

  24. 我曾兴奋地将其误读为 HTML 的 “命令与征服”,以为它与最近发布的源代码有关。

  25. 将使人工智能代理在网络上的交互变得更容易。

  26. 有趣的是,示例中没有显示与 <form> 的交互。在删除确认的示例中,我是否可以将其放在表单中,并在确认时继续发送,而在弹出窗口中点击取消时取消?

    如果我仍然需要 js 来提交表单,感觉这就差了很多。

  27. 我在等待 HTMX 作者的意见。他们似乎还没有在这里发表评论。

  28. HTML 需要一个 <button type=“revolt”/> 来抵消 <button type=“submit”/>.

  29. 有人刚刚告诉我,谷歌对网络标准并无重大影响。

  30. 这看起来像是更多的 XSS 向量。

    另外,如果我想连击分析并打开模态,我该怎么做?正确,使用 onClick。

    1. > 这看起来像是更多的 XSS 向量。

      能详细说明一下吗?我不明白这怎么会导致更多的 XSS 向量。

      1. 如果这些建议是在 html 属性和调用 JS 方法之间使用绑定,那么注入 HTML(而不是 JS)就足以开始执行 JS 了。

        1. 它不执行 JS。名称映射到 JS 方法,但 HTML 和 JS 都调用 C++(或 rust 或 swift,不管浏览器用什么编写)。不会出现任意执行 JS 代码的情况。当然,如果您正在摄取用户生成的内容,就不应该允许在按钮上使用这些属性(但为了确保适当的安全性,您应该已经在任何用户生成的内容上设置了标签和属性的允许列表)。

  31. 作者与谷歌无关。这是 “外部 ”贡献者提供的吗?如果这里还存在所谓的开源,我会向你们这些为网络做出贡献的人致以崇高的敬意。

    1. 本文作者。我与谷歌没有任何关系。我目前的雇主是 GitHub,这篇文章是在 OpenUI 工作组中孵化出来的。开放源代码和开放网络依然生机勃勃!

  32. > 虽然 HTML 为按钮提供了点击处理程序,但由于内容安全策略(CSP)规则的限制,在演示或教程之外通常不允许使用这些处理程序。

    如何防止 command 和 commandfor 因与 onClick 相同的原因而被纳入未来的 CSP 规则?

    1. 之所以不允许使用 onclick,是因为它允许完全执行 JavaScript。onlick 属性在点击时进行 “评估”。如果能在页面中注入一个属性,就能执行 JavaScript。因此,内容安全拦截–在页面上提供一条规则,说明 “本页面中的任何内容都不应该有 onclick 属性。如果你看到一个,请忽略它”。

      这些命令属性不是任意的 JavaScript 钩子。它们告诉内置组件做内置的事情。对于内容安全策略来说,“本页面中没有任何内容具有命令属性,如果你看到有命令属性的内容,请忽略它 ”是没有意义的,就像对于内容安全策略来说,“本页面中没有任何内容以粗体显示,如果你看到有内容表示希望以粗体显示,请忽略它 ”是没有意义的一样。

      1. 这很有道理,但感觉这种情况被夸大了… 网站禁用自己的 onclick 属性真的很常见吗?是否只是 CSP 规则禁用了 HTML 中的 onclick,但第一方脚本可以单独附加事件处理程序?

        1. 如果是动态生成 HTML,最安全的做法是将 CSP 设置为禁用所有内联脚本;可以只允许从已知良好位置提供的、具有有效子资源完整性哈希值的静态脚本。

      2. HTML 被注入,但内联脚本不能同时被注入,这种情况常见吗?

  33. 等等,我们什么时候有了 “对话框 ”和 “弹出窗口 ”标记?

    我还以为这个功能会与 CSS 产生某种互动,你可以通过添加和删除样式来实现很多行为

    1. <对话框

      Chrome 37,2014 年 8 月 Safari 15.4,2022 年 3 月

      弹出属性

      Chrome 114,2023 年 5 月 Safari 17,2023 年 9 月

      1. 别忘了 Firefox… 有些人一直试图支持任何不受谷歌或苹果控制的东西。

        Firefox 98 中的对话框 , 2022-03-08 此外,使用多边形填充在 IE 12 中也能正常工作

        火狐浏览器 125 中的弹出窗口 , 2024-04-16

  34. 非常好的创新–去掉所有标准的模板 javascript,以声明的方式将其编码到 HTML 中。

    javascript 越少越好,此外,它还允许从 HTML 标记中推导出动态行为,而无需解析 JS 代码。

    1. 现在看起来很简洁。

      网络开发人员会掌握这一点,并要求他们能改变菜单的大小、外观和消失的动画效果、指定菜单打开或关闭时播放的声音等。我的意思是说,就像所有其他网络事物一样,它也会被肆意篡改和肢解,直到它变得和现有的解决方案一样复杂和不可行,而这正是它想要取代的。

      1. 如果结构性的东西可以用 HTML 来编码,而动画、铃声和口哨声仍需用 JS/CSS 来编码,那我就没意见了。

  35. > 虽然 HTML 为按钮提供了点击处理程序,但由于内容安全策略 (CSP) 的规定,在演示或教程之外通常不允许使用这些处理程序。

    WTF。这是真的吗?这个属性已经存在了几十年。它曾经是处理事件的唯一方法。真不敢相信我在这里读到的东西。所有框架都使用类似的结构。onclick 属性到底有什么问题?

    1. > onclick 属性的实际问题是什么?

      它是一个字符串,所以基本上就是 eval(),而 eval 会因为各种合理的原因被禁用。它通常会与内联脚本标签一起被禁用,这就阻止了一整类 XSS 攻击–也许你的代码并不容易受到这种攻击,但谁知道某些随机的第三方标记符渲染器会启用什么呢?

      on*属性的替代方法是addEventListener,它也已经存在了几十年。

      1. 谢谢你强调了 onClick 和 addEventListener 之间的区别–我的前端技能已经生疏了,我都忘了 eval(some_string) 是多么普遍。

      2. 哇 这太愚蠢了。问题在于执行不受信任的 JavaScript… 开发人员为什么要把不信任的 JavaScript 放在 onclick 处理程序中?如果编写的是香草 JS,这种情况基本上不会发生。onclick 的使用也非常广泛,而且很少被滥用。

        有了这种逻辑,为什么不禁用 fetch() 调用和对任何后端服务的所有其他调用呢?要知道,后端可能会响应一些不受信任的用户输入,而这些输入最终可能会作为脚本执行(例如,在模板或其他东西中,一些框架使用 eval 或动态函数)…… 我们需要保护开发人员免受这种风险… 所有网页都应该是静态网页;不能有不受信任的远程数据!

        我的意思是这些论点不太合理。你不能以增加安全性为借口,删除可能被滥用的有用功能。当你删除所有这些功能时,就根本没有什么功能可以使用了!到头来,你得到的只是一块毫无用处的安全砖。

        1. 如果你能克服道德上的愤怒,你可以试着了解一下 XSS 攻击以及内容安全策略如何缓解这种攻击。XSS 可能有比原始回声输入字段更微妙的载体,而内容安全策略是一套防护栏,可以减轻它可能造成的任何潜在破坏。

          1. 我想它可以服务于一些企业用例,因为大多数人都不具备识别问题的技能,他们更愿意制定一项政策来一刀切地禁止一切。

            某些大公司习惯于禁止任何可能被滥用的工具。

            我看到了它的实用性,但这令人失望。我希望他们不要强迫每个人都使用它,因为风险与解决方案的权衡与大多数使用它的实体无关。

            1. 这不是一个全局浏览器策略设置,而是服务网站按页面启用的。HN 本身就提供了一个(有点宽松的)CSP 标头。

  36. >> show-popover: 映射到 el.showPopover()。

    我很惊讶他们还在沿用这种从 kabob 到amelCase 的函数名转录惯例。我从来都不喜欢这样。

  37. 网络标准的方向有问题。工程化程度越来越高。CSP 是弱智的。试图通过移除功能来防止所有可能的安全漏洞是愚蠢的,也是不可能完成的任务。这只是把简单的漏洞变成了复杂的漏洞。事情正朝着不好的方向发展。把孩子和洗澡水一起扔掉… 要清除所有可能的漏洞,就意味着要清除所有可能的功能。如果我们继续沿着这条路走下去,网络编程将变成一个毫无用处的官僚主义烂摊子。

  38. 更多的内置行为,更少的 JS。

  39. 我喜欢他们把这当作一个新奇的想法,其实这已经是老生常谈了。当然,这并不新鲜,但似乎不会停止。永远不会。

  40. 浏览器: 我们不甘心只有 Tailwind 会污染 HTML。我们也想分一杯羹。

  41. 你们 Chrome 浏览器打算什么时候添加虚拟滚动条、虚拟列表或虚拟表格?

  42. 他们的大多数代码示例都没有语法高亮显示,难道只有我对此感到恼火吗?

  43. 我已经有好几年没有编写任何前端 HTML 代码了。看起来确实变得乱七八糟了。

  44. 如果能找回 ublock origin 和其他 v3 之前的扩展,我很乐意放弃它

  45. 感谢分享

    不使用 JS 的声明式 UI 操作的想法很吸引人

    优点

    * 消除弹出窗口/模版的模板(不再需要ria-expanded juggling)。

    * 内置命令(如 show-modal)可在标记中加入可访问性。

    * 自定义命令(如:–rotate-landscape)可让组件通过 HTML 公开 API。

    我的疑虑

    * 抽象与神奇:这只是将复杂性从 JS 转移到 HTML 吗?框架已经对状态进行了抽象,这两者如何共存?

    * 影子 DOM 摩擦: 需要 JS 跨阴影根设置 .commandForElement 感觉像是一个半成品。

    * 面向未来: 如果 OpenUI 增加了 20 多条命令(如 show-picker、toggle-details),这是否会让平台变得臃肿而语法贫乏?

    1. > 这只是将复杂性从 JS 转移到 HTML 吗?

      说得好。这就是问题所在。

      有句老话说,每种 “脚本 ”语言起初都很小,但最终都需要具备完整编程语言的所有功能。如果我们开始在 HTML 中加入编程功能,我们最终就会把它变成一门图灵完备的编程语言,包括循环、条件、变量和函数调用。届时,我们将在 javascript 之外,重新创造出 javascript。

      1. >> 这只是将复杂性从 JS 转移到 HTML 吗?

        > 说得好。这就是问题所在。

        这是一个问题。与直觉相反,这也是一种解决方案。

        将某些复杂性从 JS 转移到 HTML 可以解决某些问题。将所有复杂性从 JS 搬到 HTML 会产生新的问题。

        例如,我有一个自定义 Web 组件 `<remote-fragment remote-src=’…’>`。这就 “转移 ”了客户端包含的复杂性,从 “需要使用 JS 框架的整个构建步骤 ”转变为直接在记事本中编写纯 HTML 文件,该文件可以包含页眉、页脚等客户端包含。

        这就降低了页面整体的复杂性。

        相反,将 “for ”循环和 “if ”条件从 JS 转移到 HTML,则会增加页面整体的复杂性。

        1. 太可怕了。我们最终会有三种不同的语言: CSS、HTML 和 Javascript,它们都将是图灵完备的编程语言,功能集完全重叠,而且没有明确的理由使用其中一种而不是另一种。

          浏览器将不得不实现对三种 PL 运行时的支持。一切都将变得复杂而混乱。

          1. 天不会塌下来,几乎所有东西都在向好的方向发展,而不是向坏的方向发展。你可以使用任何你想要的浏览器功能。

            1. 有得必有失。进一步提高新网络浏览器的准入门槛有利于那些根深蒂固的浏览器厂商,但也会因为减少了可供选择的浏览器而损害最终用户的利益。

              1. 根深蒂固的厂商决定着浏览器的功能。这是他们的目标

            2. 开发者可以使用他们想要的任何功能,但用户只能眼睁睁地看着自己的电脑耗费越来越多的能源,因为它突然要执行之前在服务器上完成的另一个构建步骤。

            3. 人们对 C++ 也是这么说的。过多的功能会增加学习语言和扩充代码库的难度;他们会对自己使用的语言有不同的标准。

        2. 也许十年后,这三种语言中的每一种都会增加足够多的语言,使它们足以与 Delphi 相抗衡。

      2. 这样很好。JS 的功能太强大了,99% 的网页都不需要 webrtc、navigator api 或其他成千上万的功能点,这些功能点几乎从来都不是用来做好事的,而是用来做坏事的。

        Html 本身的功能应该足够强大,能够为大多数使用情况提供基本的网页功能,只有这样,用户才应该明确允许服务器发布不受限制的代码。

      3. 这不仅仅是复杂性的转移。它改善了行为的局部性(LoB)。你只需看一眼按钮元素,就能立即知道它的作用(在有限的 “命令 ”范围内)。这大大提高了可读性。

        1. 我的长远希望是,页面可以体现页面上的大部分线路,事物的交互方式可以在页面上进行编码。页面的行为可以是可见的!对我来说,能够很好地展示自己的超媒体有很大的诱惑力。

          如果用户/扩展可以即时重新布线页面,而无需深入研究(捆绑、最小化的)JS 层,这将从根本上增强用户代理能力。

          此外,刚刚合并(!)的 moveBefore() 功能也有可能意味着框架将减少重新创建 HTML 元素的次数,而这正是严重阻碍扩展/用户代理的现代倒退。https://github.com/whatwg/dom/pull/1307。

          1. > 我的长远希望是,页面可以体现页面上的大部分线路,事物的交互方式可以在页面上进行编码。

            我很希望如此。过去几年,我一直是 Tailwind 的用户,这让我耳目一新,因为我的样式可以在元素上可读和内联,而不是被归档到 SCSS 中,再也看不到了。即使使用了范围样式,有些组件还是会变得很大,让人感觉很不方便

      4. 这就是为什么我宁愿保持 HTML 的局限性,也不愿接受像 Svelt 这样的东西(我以前还没听说过)。从示例中的内联语法来看,这又是一个需要学习的东西。它解决了一种问题,但通过分散逻辑引入了更多的复杂性(从一个地方提取逻辑并放入另一个地方会产生一种额外的关系,这种关系与提取逻辑的地方之间是一种关系: Svelt 和 JS 必须共存,例如可能会重叠)。

        我最喜欢的逻辑转换经历是在 PHP 中编写模板引擎。PHP 就是一个模板引擎。我很快发现我试图复制越来越多的 PHP feestures,如控制流等。我意识到 PHP 在模板引擎方面做得更好。(这并不意味着不允许使用这些东西,只是说所有看似好的用例都没有动机,而且结果也可能不尽如人意)。

      5. 我的预测 再经过几次迭代,它就会变成 HTMX 的劣质再创造。

        1. 我相信 HTMX 开发者的既定目标是将 HTMX 的功能集成到 HTML 中。

    2. > 抽象与魔法:这只是将复杂性从 JS 转移到 HTML 吗?框架已经对状态进行了抽象,这如何共存?

      就像 React 或其他框架可以挂钩 CSS 动画一样。如果 CSS 动画不存在,JS 框架就必须自己编写所有代码。而有了 CSS 动画,只需设置属性即可实现。

      即使您直接在 React 中编写一个基本的弹出菜单,在 JSX 中直接使用这些属性也能减少代码和出错的可能性。

      然后,如果您需要做一些特殊的事情,您可能需要手工完成,而不能使用这些属性,就像如果您需要一个特殊的动画,您可能必须在不使用 CSS 动画属性的情况下完成一样。

      1. 同意,我的感觉是,框架会像过去一样更新以利用这些属性

    3. 我不是网络开发人员,如果我的问题太幼稚,请原谅。这是否意味着它将仅适用于 Chrome 浏览器,还是会成为网络标准?我之所以这么问,是因为我希望未来不会受制于谷歌的奇思妙想、各种计划和要求。

      1. 这样真的很好,但过去的几个功能也是这样……它可能不会被采用,但如果有足够多的人开始使用它……

    4. 我的经验是,任何声明式的功能都是逐渐附加上去的,直到最后变成命令式(而且很难看)。例如 HCL。

      我认为声明式应该保持纯粹的声明性,以描述静态的数据/文档(如 HTML、JSON),如果需要,可以使用命令式 “层 ”来生成或重新生成数据/文档。

  46. 顺便说一句。他们的代码片段有这样的注释:

     // popovers 具有影响我们状态的轻量级解散。
    

    我以前从未听说过这句话!原来它的意思是 “点击其他地方就会关闭:”。

    >“轻度关闭 ”的意思是,如果弹出窗口的 `popover` 属性处于自动状态,那么点击弹出窗口以外的地方就会关闭弹出窗口。

    就像`<select>`打开时的作用一样。

    这位开发人员觉得这种表述方式很不直观。起初我以为是 “light DOM ”中的 “light”,但我猜是 “explicit ”的反义词 “light”?看起来在这个问题上有一些争论,甚至有人提议将其作为一个属性: https://github.com/openui/open-ui/issues/834

    [0] https://html.spec.whatwg.org/multipage/popover.html#popover-

    1. 我认为 “轻 ”是指 “轻触”(柔软的触感),包括不小心拂过表面。

      1. 我猜它代表突出显示。例如,通常会通过调暗和模糊背景来突出模态。

    2. 另外,我想说的是。我不喜欢模式对话框的这种模式。很多时候,我需要从其他地方收集信息,而在试图将焦点拉回到对话框的过程中,我触摸/点击/单击了某些东西,从而解除了对话框。非常烦人。

      1. 我对模式对话框的这种工作方式没有意见,只要人们能明白:对话框应该是短暂的。如果关闭对话框会丢失重要状态,或者您需要对话框下的信息才能使用对话框,那么您的对话框就不应该是模式对话框。因为在大多数 UI 框架中,该窗口小部件都会被关闭。不幸的是,很多团队并没有理解这一点。

        1. 我不常这么说,但 Jira 做得很好。当您创建一个新的票单时,它是在一个模态中完成的。但如果您关闭它或点击 “X”,它就会最小化到页面底部,这样您就可以查看其他票单,或查找与您正在创建的票单相关的内容。

          我一直认为模态是短暂的,而在使用 Jira 时,我不得不花上几秒钟来思考 “唉,我必须关闭它才能查找东西……等等,不,我不需要”。

      2. 刚刚注意到 Simplifi 费用跟踪网络应用程序中的这个错误。更新交易类别的下拉菜单有多个层级(例如,Business:Travel:Lodging),只要我将鼠标悬停在嵌套的下拉菜单上,整个下拉菜单就会消失。

      3. 大多数情况下,不使用模态会更好地解决这个问题。

    3. 轻是硬的反义词(即硬关闭)。在我看来,使用显式关闭与隐式关闭更合理?在弹出窗口外点击意味着隐式关闭。

    4. 根据我的经验,当我读到你评论的前两行时,我立刻想到 “这可能意味着你可以点击其他地方来关闭它”。

  47. 这就像三十多年前 NeXT AppKit 的目标/选择器模式一样……只不过语法比 1994 年的 Objective-C 更笨拙,类型安全性也更低。

    毫不夸张地说,网络让用户界面倒退了几十年。

    前几天,我试图在一个领先的 “企业级 ”React 组件框架中制作可编辑的表格单元格。这需要几屏晦涩难懂的代码。而在 20 世纪 90 年代的 AppKit 中,同样的操作只需要实现一个委托方法。

    1. 我发现,尽管 CSS 和 JS 在过去 15 年左右的时间里取得了巨大进步,但 HTML 的发展却十分缓慢。我的意思是,看在上帝的份上,我们才刚刚有了弹出窗口。

      这就好比 JS 和 CSS 已经完全融入了应用平台,而 HTML 却固步自封,坚持一切以文档为基础。这种说法也许有道理,但如果我必须与网络应用交互,我宁愿每个开发人员需要用不同质量的 JS 手工滚动的东西比现在少得多。

      1. 我认为问题的根源在于,正如其缩写所言,HTML 的核心其实只是一种用于编写超文本文档的标记语言。

        把它用作用户界面布局的特定领域语言是一种可怕的笨办法,之所以能继续存在,是因为自然选择根本不在乎合理的设计。

        1. 完全正确。

          令我匪夷所思的是,当 HTML5 问世时,人们还在发誓 Flash(和 Java 小程序)将被淘汰。几年后,替代品却变成了最可怕的意大利面条,因为无论你使用什么框架或引擎,它都会变成 HTML+JS!

          他们应该重新开始在浏览器中支持 Java。Java。Javascript。根本不会有人注意到。

          1. > Java。Java-Script。有什么区别?

            我找不到 Wayback Machine 的地址了,但我本打算链接到 Jerkcity 一部经过编辑的漫画,其中 “来自阿肯色州的约翰尼 ”提出了确切的问题,而兰斯很乐意帮助 “美国塔利班”。标题大概是 “把死麋鹿从面板 1 清理出来”

          2. 我一直认为,如果用 python 来代替 JavaScript,那一定会很有趣。

            我曾用 c++(wt 框架)编写过网络应用程序,能够利用我们已有的 c/c++ 库真的很不错,这也是我选择它的原因。

            虽然它不是最棒的,但我能很快提高工作效率,新员工也能很快上手并提高工作效率。

            1. 我喜欢 Python,但我不认为 Python 是 Javascript 的解决方案。我的意思是,Python 比 Javascript 好很多,但 Python 的类型提示比 Typescript 差很多。现代语言需要像 Java 一样,但要有空类型。

              1. 实际上,我们需要做的是让 wasm 变得足够好,以至于其他一切都可以在它的基础上实现。虽然这并不能让我们免于因为哪种语言编译成 wasm 更好而引发的火焰之战,但至少到那时,你可以真正挑选自己喜欢的语言…

        2. 我认为,HTML 的用途很窄,这是件好事。有问题的是,我们希望其他所有目的都只由一两样东西(CSS、JS)来实现。要区分 “让按钮工作的脚本 ”和 “浏览猫视频并将其下载到硬盘的脚本 ”并不难。我们可以称其为 “minJS ”和 “maxJS ”之类的,并让用户可以禁用 “maxJS”,而无需禁用 “minJS”。或者等等,为什么还要强制使用 JS 呢?网络最大的问题不在于特定的设计决策(当然它们也有很多问题),而在于我们不愿意从根本上改变它们,只是一味地堆砌东西

      2. 我的感觉是,与 HTML 相比,JS 和 CSS 更容易构建优雅降级的体验。此外,对 HTML 的更改要么必须是孤立的(在浏览器中不伴随对 JS 的更改),要么必须与对 JS 的更新相协调。

    2. > 可以毫不夸张地说,网络让用户界面倒退了几十年。

      用户界面的倒退换来的是无与伦比的跨平台兼容性、发布的简便性以及沙箱式的安全模式。MacOS 在过去 10 年中才引入了桌面应用程序沙盒功能,大多数桌面运行软件都需要用户权限,这并不可取。

    3. > 这需要几屏晦涩难懂的代码

      我无法想象这在 vanilla js 中会有多复杂。也许只需制作一个 Web 组件,然后在 React 中使用即可。

    4. > 同样的操作在 1990 年代的 AppKit 中只需要实现一个委托方法。

      我很难相信这一点。

      我并不是想 “呃,吖 ”你,但你所描述的内容是可以通过本地 HTML 的 “contenteditable ”属性实现的。

      https://developer.mozilla.org/en-US/docs/Web/HTML/Global_att

      (实际做一些有用的编辑是另一回事,但这不是评论的主题)

      1. contenteditable 使用起来非常痛苦,没有标准化,不同浏览器之间也不一样,而且在 Firefox 中还会出现错误

        1. 当然,虽然问题是关于 “使表格单元格可编辑 ”需要几页晦涩难懂的代码。

          从技术上讲,这只需要一个 HTML 属性。

          如果你想通过单元格和计算建立某种反应式的、类似电子表格的体验,那么是的,这就存在一些固有的复杂性。

    5. > 可以毫不夸张地说,网络让用户界面倒退了几十年。

      一旦你要求提供具体的例子,这些说法似乎总是不攻自破。

      1. React/JS 代码远比 Objective-C 代码简单和笨拙。

      2. 与 Objective-C 的 target/selector 不同,HTML commandfor/command 是声明式的,而且非常简单。

      粘贴 TFA 中的 HTML commandfor 代码段,并询问法律硕士 Objective-C 的对应代码是什么。如果您认为它不那么笨拙,请继续粘贴到这里供我们评判。)

      > 这需要几屏晦涩难懂的代码。

      不过,它还是比我以前开发的程序化 Objective-C Cocoa 应用程序要好得多。

      1. “1.1. React/JS 代码比 Objective-C 代码简单得多,也不那么笨重。

        难以苟同–例如,在 Objective C 中,我从来不用担心如何确保我(以及我使用的每个库)在每次渲染时都以完全相同的顺序调用钩子。它这样做是出于 “脆性 ”原因–它将状态与钩子的顺序关联起来。

        (对于任何有反应的人来说,这并不意味着评判,而只是一种解释:P)。

        因为我已经半退休了,做这个只是为了好玩,所以上个月我花了一周的时间,在我的应用所依赖的库中查找反应钩子使用的 bug 并发送补丁。我想我已经找到了 23 个。由于 javascript 生态系统的依赖性太深,你常常需要依赖大量的人来确保一切正确无误。而在 Obj-C 中,这种情况就少得多。

        他们中的一些人还通过将代码移到 setTimeouts 内的 useCallback 来消除 “错误”,这样就不会被钩子检查器发现(当然,这也不能保证反应效果的顺序),从而导致更多微妙的错误。

        我甚至不想讨论 react 中的 async 与 objective-C 中的 async 之争(不过公平地说,很多流行的 JS 框架都存在与 async 集成不佳的问题)。

        最后: 只要你学会了 React 就没问题。Obj-C 只要你学会了就没问题。

        但是,说 React 不笨拙、不易碎,而说 Obj-C 不笨拙、不易碎,这绝对是夸大其词。

        这里的所有东西都很笨拙和脆弱,只是方式不同而已:)

      2.  > React/JS 代码远比 Objective-C 代码简单和笨拙。
        

        它与 Tcl/Tk 相比如何?尤其是画布(canvas),元素上有标签,标签有自己的绑定。

    6. > 让用户界面倒退

      这就是为什么现在 90% 的在线交互都是在网络上进行的原因……愚蠢的我认为这是因为它是一种卓越的解决方案。

      在你说 “90% 其实都在手机上 ”之前,手机也不会使用 1994 年的东西。不知道为什么。

      1. >你以为你的冷嘲热讽是对的么?

        你以为你的冷嘲热讽是对的,其实不然。“哦,每个人都在用,所以它实际上肯定不坏?这根本不是个好论点。

      2. 网络的主要特点是无处不在。做一个本地应用程序需要安装、更新处理等。

        这就是 “网络胜出 ”的原因。但是,就用户界面而言,网络在技术上并不占优。

        最流行的技术通常并非在所有方面都出类拔萃,但对于流行的用例来说却是最方便的。例如,LISP 比 C 语言早几十年。从技术上讲,C 的抽象性不如 LISP,但 ATT 将其用于 Unix,并迅速成为系统编程的事实标准。这使得 C 成为比 LISP 更好的选择,只是因为你需要进入额外的复杂层才能完成为 C 设计的系统调用。对于网络,你只能使用 HTML/CSS/JS(即使使用 WASM)。

        “移动设备不使用 1994 年的东西”……那么所有的 iOS 应用程序都是基于 80 年代创建的 Next 框架。

        你可能从未使用过本地 UI 框架,也从未尝试过为网络创建一个可访问的组件库,所以才会说出这样的话。试着使用本地框架和 HTML 创建一个可访问的选择组件,在选项中显示一个图标,你很快就会明白我的意思。

        1. 请不要创建选择组件。原生组件就很好,而且 100% 的时间都能正常工作。对于我们这些使用翻译工具的人来说,试图浏览设计师们为了 “美观 ”而想出的鬼东西实在是……恼人且充满痛苦。说 “不 ”就对了。

      3. 网络是世界上有史以来最好的应用分发机制。尽管在过去的十五年里,网络的发展有了巨大的进步,但其上限仍然远远低于本地应用(尽管其下限要比本地应用容易得多)。不过这些都不重要,因为要让你的应用出现在人们的眼前,只需要输入一个 URL 就可以了。

      4. 移动设备使用的绝对是 “1994 年的垃圾”。

        iOS 中的用户界面框架就是我所说的 NeXT 框架的直系后代。

        1. 没错。所有面向消费者的五大操作系统都是上世纪 80 年代末和 90 年代初的产品。

          – Windows 11 是 Windows NT

          – macOS 是 NeXTSTEP/OPENSTEP

          – Linux 是一种类似于自由 Unix 的操作系统,它诞生于 BSD 和 GNU 都在使用它的年代。

          – Android 是 Linux + Java(灵感来自 OpenStep)

          – iOS/iPadOS 是用于手机的 NeXTSTEP/OPENSTEP。

          (OPENSTEP 是一个操作系统,OpenStep 是一个框架)

  48. 这是专有的 HTML 扩展吗?

    难道我们又回到了 IE 时代的混乱局面?

    如果是这样,那就让 <marquee> 回来吧。

    1. >这是一个专有的 HTML 扩展吗?

      当然不是。网络标准是由谷歌决定的。

    2. 你关注过 HTML 在过去 20 年中的发展吗?你的评论表明没有。

      这并不完全是一个标准驱动的过程。浏览器供应商通常只是制造一些东西。这种做法有好有坏,但肯定比 W3C 某些联盟多年来争论 “人体工程学 ”要快。

      成功的新增内容会慢慢回溯到规范中。

    3. Chrome 浏览器是新的 IE。谷歌决定的任何东西都将成为标准(既有事实上的标准,因为他们控制着市场,只是及时推出新版本;也有非标准的标准,因为他们资助了 W3C 联盟和其他标准机构)。

  49. 下一步,我们将获得 DOM 事件 beforecommand 和 aftercommand。/s

    原则上,这种声明式方法的方向是正确的,但如果没有一个总体概念和未来网络用户界面的愿景,这就像是在堆栈中添加了另一个皱褶。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注