gpt4 book ai didi

javascript - 单击标签不聚焦自定义元素(Web 组件)

转载 作者:行者123 更新时间:2023-11-27 22:47:25 25 4
gpt4 key购买 nike

我正在写一个自定义<select>使用原生 DOM 的元素(无 Polymer)。

我正在尝试将我的元素与 <label> 一起使用元素并在 <label> 时正确触发我的元素的点击事件被点击,即:

<label>
My Select:
<my-select placeholder="Please select one">...</my-select>
</label>

<label for='mySelect1'>My Select:</label>
<my-select id='mySelect1' placeholder="Please select one">...</my-select>

但是,即使我添加 tabindex,这种行为似乎也不是开箱即用的。使其可聚焦。

这是代码的精简版本和 JSFiddle进行一些基本的调试:

var MySelectOptionProto = Object.create(HTMLElement.prototype);
document.registerElement('my-select-option', {
prototype: MySelectOptionProto
});
var MySelectProto = Object.create(HTMLElement.prototype);

MySelectProto.createdCallback = function() {
if (!this.getAttribute('tabindex')) {
this.setAttribute('tabindex', 0);
}

this.placeholder = document.createElement('span');
this.placeholder.className = 'my-select-placeholder';
this.appendChild(this.placeholder);

var selected = this.querySelector('my-select-option[selected]');

this.placeholder.textContent = selected
? selected.textContent
: (this.getAttribute('placeholder') || '');
};
document.registerElement('my-select', {
prototype: MySelectProto
});

最佳答案

But the standard is not finished, and maybe in the future you’ll be able to use the built-in semantic with autonomous custom elements, too.

Supersharp, Jul 15, 2016 at 16:05

我们现在生活在未来。标准发生了显着变化,我们现在拥有更强大的自定义元素。

<小时/>

太;博士:

当与自定义元素关联的构造函数具有 formAssociated 时,标签才有效值为 true 的属性.

<小时/>

当查看documentation时乍一看,您可能会得出结论,不允许自定义元素,如 <label>目标。文档说:

Elements that can be associated with a <label> element include <button>, <input> (except for type="hidden"), <meter>, <output>, <progress>, <select> and <textarea>.

但是没有提到自定义元素。不管怎样,你试试你的运气,并尝试在 HTML validator 中输入这个 HTML 片段。 :

<label>Label: <my-custom-element></my-custom-element></label>

或者:

<label for="my-id">Label: </label><my-custom-element id="my-id"></my-custom-element>

这两个都是有效的 HTML 片段!

但是,尝试这个 HTML 片段:

<label for="my-id">Label: </label><span id="my-id"></span>

显示此错误消息:

Error: The value of the for attribute of the label element must be the ID of a non-hidden form control.

但是为什么是随机的 <my-custom-element>被认为是“非隐藏表单控件”?在 validator’s GitHub issues然后你会发现已经修复的 issue #963 :

label for doesn’t allow custom elements as targets

The spec allows form-associated custom elements as for targets
https://html.spec.whatwg.org/multipage/forms.html#attr-label-for

This currently triggers an error:

<label for="mat-select-0">Select:</label>
<mat-select role="listbox" id="mat-select-0"></mat-select>

Easy to check if element name contains a dash.Much harder to check that custom element definition includes a static formAssociated property returning true, since this is likely buried deep in an external framework .js file:
https://html.spec.whatwg.org/multipage/custom-elements.html#custom-elements-face-example

WHATWG specification 中确实有一个特殊的附录。它枚举了与文档 plus form-associated custom elements 相同的“可标记元素” 。有一个example在规范中,今天研究这个问题在结果中产生了这篇问答文章以及博客文章,例如 “More capable form controls” by Arthur Evans ( archived link ),显示解决方案是什么。

启用<label>的解决方案单击定位自定义元素:formAssociated

启用 <label> 所需执行的所有操作。操作是添加 formAssociated值为 true 的属性到自定义元素的构造函数。

但是问题中的代码需要移植到当前的Web Components API 。新formAssociated属性是新的 ElementInternals API 的一部分(请参阅 attachInternals ),用于更丰富的表单元素控制和可访问性。

现在,自定义元素是用 classes 定义的和 customElements.define ,和 ShadowRoots被使用。static formAssociated = true;然后可以将字段添加到您认为属于“表单关联的自定义元素”的类中。拥有此属性可以使您的自定义元素分派(dispatch) click单击 <label> 时发生的事件;现在我们已经取得进展了!

为了把这个click进入focus行动,我们还需要 attachShadow 中的一件事调用:属性(property)delegatesFocus设置为true .

// Rough translation of your original code to modern code, minus the `tabIndex` experimentation.

class MySelectOptionProto extends HTMLElement{}

customElements.define("my-select-option", MySelectOptionProto);

class MySelectProto extends HTMLElement{
#shadowRoot;
#internals = this.attachInternals();
static formAssociated = true;
constructor(){
super();
this.#shadowRoot = this.attachShadow({
mode: "open",
delegatesFocus: true
});
this.#shadowRoot.replaceChildren(Object.assign(document.createElement("span"), {
classList: "my-select-placeholder"
}));
this.#shadowRoot.firstElementChild.textContent = this.querySelector("my-select-option[selected]")?.textContent ?? (this.getAttribute("placeholder") || "");
}
}

customElements.define("my-select", MySelectProto);
<label>My label:
<my-select placeholder="Hello">
<my-select-option>Goodbye</my-select-option>
<my-select-option>world</my-select-option>
</my-select>
</label>

<label for="my-id">My label:</label>
<my-select id="my-id">
<my-select-option>Never gonna give you</my-select-option>
<my-select-option selected>up</my-select-option>
</my-select>
<label for="my-id">My other label</label>

delegatesFocus当单击自定义元素的某些不可聚焦部分时,将聚焦影子根的第一个可聚焦子级。

如果您需要更多控制,可以删除该属性,并向自定义元素实例添加事件监听器。为了确保点击来自<label> ,您可以检查事件是否为target是您的自定义元素,即 this ,屏幕上 x 和 y 位置的元素是 <label>定位您的自定义元素。幸运的是,通过传递 x 可以非常可靠地完成此操作。和 y document.elementFromPoint 。然后,只需调用 focus 在您想要的元素上即可完成工作。

针对自定义元素的标签列表是 ElementInternals API 通过 labels 提供的另一件事。属性。

class MySelectProto extends HTMLElement{
// …
constructor(){
// …

this.addEventListener("click", ({ target, x, y }) => {
const relatedTarget = document.elementFromPoint(x, y);

if(target === this && new Set(this.#internals.labels).has(relatedTarget)){
console.log("Label", relatedTarget, "has been clicked and", this, "can now become focused.");
// this.focus(); // Or, more likely, some target within `this.#shadowRoot`.
}
});
}
}

关于javascript - 单击标签不聚焦自定义元素(Web 组件),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38320270/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com