Từ Chrome 135, nút bấm được bổ sung `command` và `commandfor`
(developer.chrome.com)- Nút bấm là thành phần thiết yếu để xây dựng ứng dụng web động. Chúng được dùng để mở menu, chuyển đổi tác vụ và gửi biểu mẫu
- Trong Chrome 135, các thuộc tính mới
commandvàcommandforcải tiến và thay thế các thuộc tính trước đây làpopovertargetactionvàpopovertarget - Những vấn đề thường gặp khi triển khai hành vi của nút bấm theo cách cũ:
- Trình xử lý
onclickcủa HTML có thể bị hạn chế trong mã thực tế do chính sách bảo mật (CSP) - Cần đồng bộ trạng thái giữa nút bấm và các phần tử khác, và mã để quản lý trạng thái trong khi vẫn giữ được khả năng truy cập thì khá phức tạp
- Ngay cả trong React, AlpineJS, Svelte... việc xử lý trạng thái và sự kiện cũng phức tạp
- Trình xử lý
Mẫu command và commandfor
- Khi dùng các thuộc tính
commandvàcommandfor, nút bấm có thể hoạt động theo cách khai báo đối với phần tử khác. Cách này mang lại sự tiện lợi như framework nhưng vẫn giữ được tính linh hoạt - Nút
commandforsử dụng ID (tương tự thuộc tínhfor), còncommandnhận các giá trị dựng sẵn để mang đến cách tiếp cận trực quan hơn - Ví dụ: triển khai nút mở menu
- Không cần
aria-expandedhay JavaScript bổ sung
<button commandfor="my-menu" command="show-popover"> Open Menu </button> <div popover id="my-menu"> <!-- ... --> </div> - Không cần
command và commandfor so với popovertargetaction và popovertarget
- Nếu đã từng dùng
popover, bạn có thể đã quen với các thuộc tínhpopovertargetvàpopovertargetaction - Chúng hoạt động tương tự
commandforvàcommand, nhưng được thiết kế riêng cho popover - Các thuộc tính mới thay thế hoàn toàn các thuộc tính cũ và cung cấp thêm chức năng
Lệnh dựng sẵn
- Thuộc tính
commandtích hợp sẵn các hành động được ánh xạ tới nhiều API khác nhaushow-popover: ánh xạ tớiel.showPopover()hide-popover: ánh xạ tớiel.hidePopover()toggle-popover: ánh xạ tớiel.togglePopover()show-modal: ánh xạ tớidialogEl.showModal()close: ánh xạ tớidialogEl.close()
- Ví dụ: triển khai hộp thoại xác nhận xóa
- Có thể quản lý trạng thái và khả năng truy cập mà không cần JavaScript
<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"> <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>- Mã xử lý kết quả: có thể xử lý giá trị trả về trong sự kiện
closecủa hộp thoại
dialog.addEventListener("close", (event) => { if (event.target.returnValue === "cancel") { console.log("Cancel was clicked"); } else if (event.target.returnValue === "delete") { console.log("Delete was clicked"); } });
Lệnh tùy chỉnh
- Ngoài các lệnh dựng sẵn, bạn còn có thể định nghĩa lệnh tùy chỉnh bằng tiền tố
-- - Lệnh tùy chỉnh sẽ phát sinh sự kiện
"command"trên phần tử đích, nhưng không thực hiện thêm logic nào khác - Ví dụ: triển khai lệnh xoay ảnh
<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>
Xử lý lệnh trong Shadow DOM
- Trong Shadow DOM, do
commandforhoạt động dựa trên ID nên có các hạn chế sau:- Không thể tham chiếu phần tử giữa các Shadow DOM
- Trong trường hợp này, có thể dùng API JavaScript để thiết lập thuộc tính
.commandForElement
- Ví dụ: kết nối lệnh trong Shadow DOM
<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]'); this.shadowRoot.querySelector('button').commandForElement = popover; } }); </script>
Kế hoạch sắp tới
- Chrome đang có kế hoạch bổ sung thêm các lệnh dựng sẵn:
- Mở và đóng phần tử
<details> - Hỗ trợ lệnh
"show-picker"trên<input>và<select> - Lệnh phát cho
<video>và<audio> - Chức năng sao chép văn bản từ phần tử
- Mở và đóng phần tử
1 bình luận
Ý kiến Hacker News
Các nhà lý thuyết ngôn ngữ lập trình đã suy đoán về
comefrom, một phiên bản mạnh hơn củagoto, từ những năm 80. Nó chỉ được triển khai trong intercal. intercal vượt trội hơn các ngôn ngữ như C về độ an toàn, hiệu năng và tính công thái học, nhưng lại gặp khó khăn khi thâm nhập thị trường thương mại. Thật thú vị khi thấy javascript tích hợp tính năng này của intercal. Hy vọng điều này có thể dẫn đến sự bùng nổ của lập trình lịch thiệp, giống như cách các đối tượng dựa trên closure của javascript đã đưa lập trình hàm vào dòng chínhInvokers không chỉ dành riêng cho Chrome. Nó đã dùng được trong Firefox nightly
Ý tưởng triển khai hành vi UI theo kiểu khai báo mà không cần JS khá hấp dẫn
aria-expanded)show-modaltích hợp khả năng truy cập ngay trong markup--rotate-landscape) cho phép component phơi bày API thông qua HTMLMột số băn khoăn:
.commandForElementgiữa các shadow root. Điều này trông như một vấn đề mới chỉ được giải quyết một nửashow-picker,toggle-details), liệu nền tảng có phình to vì cú pháp ngách không?Đặc tả:
commandforcommandĐây có phải là mẫu action/messaging mà Next, Be, Apple và các hãng khác đã dùng khoảng 30 năm trước không, hay là tôi đang bỏ sót điều gì?
Bộ công cụ UI Java đời đầu của Netscape (IFC) từng cho phép nối các phần tử hành động với nhau
Hai thuộc tính mới
commandvàcommandforcải tiến và thay thế các thuộc tínhpopovertargetactionvàpopovertargetTôi hoàn toàn dị ứng với kiểu lập trình bằng chuỗi. Tôi hiểu lợi ích về khả năng truy cập, nhưng không thấy đặc biệt hứng thú với việc dùng ID phần tử như một lớp hành vi khác cho web app
Lẽ ra không nên triển khai cái này nếu chưa có API hoàn chỉnh. Thay vì khoảng 5 lệnh, trông như mọi khả năng của JavaScript đều có thể được hiện thực qua HTML. Như vậy có thể thành hàng nghìn lệnh
Tôi đã mong chờ
command and conquertrong HTMLViệc cải tiến và mở rộng HTML là điều tốt, nhưng vẫn còn một chặng đường dài. Nhóm HTMX có một vài ý tưởng hay