自定义 DefineCustomElement 实现中缺少插槽

问题描述 投票:0回答:2

我们正在使用 Vue 3、TS 和 Tailwind 开发 Web 组件库。我们正在使用 DefineCustomElement 宏的自定义实现,@tony19 能够提供 vue-router 和 pinia 等插件支持。除老虎机外,每个功能都完美无缺。

这里有一个使用此自定义宏和重现的 @tony19 示例 fork 的链接:https://stackblitz.com/edit/vue-nested-custom-elements-lose-styles-gtj3fy?file=src/App.vue

我该如何解决这个问题?

我试图通过 setup 函数传递槽,然后返回带有 {...slots } 的 h 函数,但没有成功。直到那里,我不知道如何继续。

vue.js vuejs3 web-component vite custom-element
2个回答
0
投票

我遇到了同样的问题,但基于yyx990803评论是不可能的

我的解决办法:

// MyCustomElement.ce.vue

<template>
    <div>
        <div class="header">
            <slot name="header">Default Header</slot>
        </div>
        <slot></slot>
    </div>
</template>
<script setup>
    //Code
</script>

// 该函数确实使用共享数据定义自定义元素

function createElementInstance({ component, app, renderOptions = {} } = {}){

    return defineCustomElement({
        setup() {
            const inst = getCurrentInstance()

            Object.assign(inst.appContext, app._context)
            Object.assign(inst.provides, app._context.provides)
        },
        render: () => h(component, null, renderOptions)
    })
}
import MyCustomElementfrom './MyCustomElement.ce.vue'
const app = createApp()
customElements.define('my-custom-element', createElementInstance({
   app,
   MyCustomElement,
   {
      default: () => h('slot'),
      header: () => h('slot', { name: 'header' }),

   }
}))

上面的方法并不理想,因为我们必须多次定义插槽,但它可以在您需要在自定义元素之间共享相同的

app
实例的情况下使用。


-1
投票

所以你的 main.ts 文件中有类似的东西

defineCustomElement({
    styles: component.styles,
    props: component.props,
    setup(props, { slots }) {
        const app = createApp();
        plugins.forEach(plugin => {
            app.use(plugin);
        });
        const inst = getCurrentInstance();
        Object.assign(inst.appContext, app._context);
        Object.assign(inst.provides, app._context.provides);
        return () =>
            h(component, {
                ...props,
                ...slots
            });
    }
});

如果您检查该插槽变量,它始终为空,即使自定义元素具有类似的内容

<my-component><div>hmmm...</div></my-component>

这似乎是一个错误,实现此功能的另一种方法是将 main.ts 中的设置代码移动到主 App.vue 设置中,并将其用于自定义元素。所以 App.vue 设置会是这样的:

// Plugin initialization and the list can probably be exported from main.ts, putting this here for simplicity
import router from './router';
const plugins = [plugins];

const app = createApp();
plugins.forEach(plugin => {
    app.use(plugin);
});
const inst = getCurrentInstance();
Object.assign(inst.appContext, app._context);
Object.assign(inst.provides, app._context.provides);

那么 main.ts 将减少为

const styles: string[] = [];
const modules = import.meta.glob('./**/*.vue');

for (const path in modules) {
    const mod = await modules[path]();
    styles.push(mod.default.styles);
}

App.styles = [styles.flat().join('')];

customElements.define('swim-app', defineCustomElement(App));

App 组件中定义的任何插槽现在都应该可以工作。您可以忽略上面的样式内容,这只是修复了另一个错误,即子样式不包含在 Shadow dom 样式标记中。

© www.soinside.com 2019 - 2024. All rights reserved.