我有关于自定义 Web 组件的问题。自定义元素例如:
class CustomButton extends HTMLElement {
connectedCallback() {
this.root = this.attachShadow({mode: "open"});
const form = document.createElement("form");
this.root.append(form);
}
}
customElements.define("custom-button", CustomButton);
现在我将这个包含自己的表单和一些输入的自定义元素放入页面中的另一个表单中
<form>
<input type="text" name="name">
<custom-button>Select</custom-button>
<button type="submit">Submit</button>
</form>
在这种情况下,Web 组件是通用库组件,我无法控制用户将其放在哪里。
通常我不能将
<form>
元素放入另一个 <form>
元素中,但是在这种情况下,shadow dom 又如何呢?有效吗?我可以将任何东西放入 Shadow dom 而不必担心某些特定用法吗?
感谢您的回复!
您的元素始终与单个
<form>
关联,因此只会提交您的元素,而不是父元素。如果您正在构建 <form>
元素的一部分,您不希望它实际上 成为 <form>
。您可以通过将其标记为 <form>
并使用其 ElementInternals来检索其实际的
formAssociated
元素并在需要时提交它,从而使其表现得像 <form>
的实际部分:
customElements.define("my-button", class extends HTMLElement {
#internals;
static formAssociated = true;
constructor() {
super();
this.attachShadow({ mode: "open" });
this.#internals = this.attachInternals();
}
connectedCallback() {
// No <form> in here, we're just a fragment
this.shadowRoot.innerHTML = `
<input name='name'>
<button>submit</button>
`;
this.shadowRoot.querySelector("button").onclick = e => {
const input = this.shadowRoot.querySelector("input");
const fd = new FormData();
fd.set(input.name, input.value);
// Set our own value, will be merged with the one of the <form>
this.#internals.setFormValue(fd);
// Let other code handle the submit event
this.#internals.form?.requestSubmit();
};
}
});
document.forms[0].addEventListener("submit", e => {
e.preventDefault();
console.log("submitting", Object.fromEntries(new FormData(e.target)));
});
<form>
<input name="other-value" value="value set outside">
<my-button></my-button>
</form>