如何在根自定义元素中使用 vue router 和 vuex?

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

我有一个带有嵌套自定义元素的项目。现在我需要 vuex 和 vue 路由器。如何从根自定义元素使用此包,然后在所有子自定义元素中使用?

目前我尝试只在每个组件中使用 vuex,如下所示:

<script>
import store from './store';

export default {
  setup() {
    const state = store.state;

    return { state };
  },
};
</script>

这是带有嵌套自定义元素的演示项目

这是我的

main.js
文件代码:

import { defineCustomElement } from "./defineCustomElementWithStyles";
import App from "./App.ce.vue";

customElements.define("app-root", defineCustomElement(App));
javascript vue.js vuex vue-router vuejs3
3个回答
19
投票

Vue 插件需要应用程序实例,但对于从

defineCustomElement()
创建的组件没有定义该实例。作为解决方法,您可以在临时应用程序实例上安装插件,然后将生成的上下文复制到实际应用程序,如该实用程序所示(我们稍后将使用):

// defineCustomElementWithStyles.js
import { defineCustomElement as VueDefineCustomElement, h, createApp, getCurrentInstance } from 'vue'

export const defineCustomElement = (component, { plugins = [] } = {}) =>
  VueDefineCustomElement({
    render: () => h(component),
    setup() {
      const app = createApp()

      // install plugins
      plugins.forEach(app.use)

      const inst = getCurrentInstance()
      Object.assign(inst.appContext, app._context)
      Object.assign(inst.provides, app._context.provides)
    },
  })

使用上面的

defineCustomElement()
而不是
vue
中的:

// main.js
import { defineCustomElement } from './defineCustomElementWithStyles'
import App from './App.ce.vue'
import store from './store'
import router from './router'

customElements.define(
  'app-root',
  defineCustomElement(App, {
    plugins: [store, router],
  })
)

演示


5
投票

对 tony19 的解决方案进行一点修复:

export const defineCustomElementWrapped = (component, { plugins = [] } = {}) =>
  defineCustomElement({
    styles: component.styles, // <- this
    render: () => h(component),
    setup() {
      const app = createApp()

      // install plugins
      plugins.forEach(app.use)

      const inst = getCurrentInstance()
      Object.assign(inst.appContext, app._context)
      Object.assign(inst.provides, app._context.provides)
    },
  })

然后

customElements.define(
  'app-root',
  defineCustomElementWrapped(App, {
    plugins: [store, router],
  })
)

这还包括组件导出的样式

(如果你要改变它们的行为,我也不喜欢隐藏原始函数名称,所以我重命名了它)

可能还需要:

    styles: component.styles.map((style) => {
      return style
        .replace(":root", ":host") // <- rename :root values to :host
        .replace("body {", "#my-app {"); // <- in case of frameworks like bootstrap that styles directly body
    }),

0
投票

只需对最佳答案进行一些小调整:当您需要道具、发射或样式时,解构组件而不是包装它可能会更容易:

const defineCustomElement = (component, { plugins = [] } = {}) =>
  VueDefineCustomElement({
    ...component, // <---- use all props from the original component (except setup)
    setup(...args) {
      const app = createApp({})
      plugins.forEach(app.use)
      const instance = getCurrentInstance()
      Object.assign(instance.appContext, app._context)
      Object.assign(instance.provides, app._context.provides)

      return component.setup?.(...args) // <---- run initial setup if exists
    },
  })
© www.soinside.com 2019 - 2024. All rights reserved.