在Vue v3自定义元素组件中引用宿主元素

9jyewag0  于 2023-05-07  发布在  Vue.js
关注(0)|答案(1)|浏览(235)

好了,我知道这个问题已经有了一些变化,在不同版本和API的Vue中...但我一直没能弄清楚,所以这里的背景下,为什么我认为我的是不同的:
我正在尝试构建一些组件:
1.内部足够复杂,使用Vue而不仅仅是native web components构建是有帮助的,但是...
1.将在页面上的Vue上下文之外运行(而不是在Vue应用程序中),因此被打包为Web组件/自定义元素from Vue,并且...
1.实现将在<form> s中使用的数据输入(同样,不在Vue应用程序中)。
其中一个挑战是Vue Web Components使用shadow DOM,表单不会自动遍历shadow根来查找输入:因此,使表单实际看到并提交组件的内部数据并不是自动的。
看起来有一些希望,如this helpful blog post中详细说明的那样:一个新的ElementInternals APIelement-internals-polyfill NPM包,通过它组件可以指示数据直到表单。实现一个“表单关联的自定义元素”需要设置一个静态的只读布尔属性(很简单),但也需要链接如下内容:

// (`this` == the custom HTMLElement itself)
const _internals = this.attachInternals();

_internals.setFormValue(value);

*问题是,我真的很难弄清楚我可以在哪里挂接以访问 * 两者

  • 挂载的DOM元素(影子根上方的元素,即<my-custom-element>不是只是模板中的一些ref()),
  • 要获得value的组件的无功状态

……到目前为止,我主要使用Vue的composition and script setup APIs,无可否认地感觉他们让这变得更难:例如,onMounted根本没有定义this。但即使使用等效的选项API mounted: () => {},我看到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"一致,在我的例子中,我特别试图访问 * 定义组件的自定义元素 * -而不是模板中的元素。呈现的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>

有人知道怎么做吗?

rkue9o1l

rkue9o1l1#

同意这是一个糟糕的代码气味,也是一个评估Vue是否真的适合一般用例的信号:使用混合的Web组件进行黑客攻击,这些组件不是很原生,但也不是很Vue,即使它在今天工作,也可能是一个维护负担。
但是需求必须-我目前的解决方法是通过DOM从模板中的一些引用元素(并不重要)进行跟踪,就像这样:

// (MyCustomComponent.ce.vue script setup)

import { ref } from "vue";

const someTemplateRef = ref();

onMounted(() => {
  const hostNode = someTemplateRef.value.getRootNode()?.host;
});

相关问题