引用Vue v3自定义元素组件中的主体元素
好的,我知道这个问题的一些变体已经被问到了,在Vue的不同版本和API中...但我一直没能弄明白,所以下面是我认为我的不同的原因:
我正在尝试构建以下组件:
- 内部足够复杂,使用Vue而不仅仅是native web components构建是有帮助的,但是...
- 将在页面上的Vue上下文之外运行(而不是在Vue应用程序中),因此打包为Web组件/自定义元素from Vue和...
- 实现将在
<form>
中使用的数据输入(同样,不是在Vue应用中)。
这方面的一个挑战是Vue Web组件使用影子DOM,而表单不会自动遍历影子根来查找输入:因此,让表单实际查看并提交组件的内部数据并不是自动的。
this helpful blog post中详细说明了一些希望:一个新的ElementInternals API和element-internals-polyfillNPM包,组件可以通过它指示数据到表单。实现与表单关联的自定义元素需要设置静态只读布尔属性(非常简单),但还需要链接类似以下内容:// (`this` == the custom HTMLElement itself)
const _internals = this.attachInternals();
_internals.setFormValue(value);
问题是,我真的很难弄清楚我可以连接到哪里才能访问:
- 挂载的DOM元素(影子根上的,即
<my-custom-element>
,不只是模板中的一些ref()
),和 - 要获取的组件的反应状态
value
script setup
APIs,这确实让人觉得它们使这一点变得更加困难:例如,onMounted
根本没有定义this
。但即使使用等价的选项APImounted: () => {}
,我也看到this.$el
似乎是模板/影子根中的第一个元素,而不是拥有影子根的父自定义元素。我还考虑了另一种方法--从创建的CustomElement类开始,尝试返回到有用的Vue数据和钩子……但在这里也找不到方法:
import { defineCustomElement } from "vue";
import MyCustomComponent from "./components/MyCustomComponent.ce.vue"
const MyCustomElement = defineCustomElement(MyCustomComponent);
class MyCustomElementFormAssoc extends MyCustomElement {
static get formAssociated() {
return true;
}
constructor(initialProps?: Record<string, any> | undefined) {
super(initialProps);
const _internals = this.attachInternals();
// But here the component isn't even mounted yet - this._instance doesn't
// exist and presumably reactive state doesn't either, so can't do:
// _internals.setFormValue(someValueState);
}
}
customElements.define("my-custom-element", MyCustomElementFormAssoc);
因此,虽然一般来说,与其他Vue 3答案"there is no single root element and we should use refs instead"一致,但在我的例子中,我特别尝试访问定义组件的Custom元素-而不是模板内的元素。呈现的DOM如下所示:
<my-custom-element class="this-one-is">
#shadow-root (open)
<div class="custom-element-template-can-have-multiple-roots"></div>
<div class="but-these-are-not-the-elements-im-looking-for"></div>
</my-custom-element>
有人知道怎么做吗?
解决方案
同意这是一种糟糕的代码气味,也是评估VUE是否真的适合一般用例的信号:使用并非完全原生但也不完全VUE的混合Web组件很可能成为维护负担,即使它现在可以工作。
但必须需要-我目前的解决方法是通过DOM从模板中的一些引用元素回溯(实际上并不重要),如下所示:
import { ref } from "vue";
const someTemplateRef = ref();
onMounted(() => {
const hostNode = root.value.getRootNode()?.host;
});
相关文章