(Vue3 / Vite)不渲染嵌套的外部vue组件

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

我正在构建由不同的 Vite/Vue 项目组成的模块 vue.js 应用程序。

工作流程 - 拥有 Theme 插件 / **菜单 **插件,可以在 vue 应用程序中动态应用。

组件在应用程序的根级别渲染,但它在嵌套时无法渲染。 (主题组件渲染菜单组件),但是它在 DOM 中仅显示为组件名称....

我尝试创建单独的 vite/vue 应用程序,构建它们,然后在 index.html 中手动加载它们。

主题插件项目

  • 主题/vite.config.ts
import { fileURLToPath, URL } from "node:url";

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import vueJsx from "@vitejs/plugin-vue-jsx";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue(), vueJsx()],
  build: {
    rollupOptions: {
      output: {
        dir: "./dist",
        entryFileNames: "plugin.js",
        assetFileNames: "plugin.css",
        chunkFileNames: "chunk.js",
        manualChunks: undefined,
      },
    },
  },
  resolve: {
    alias: {
      "@": fileURLToPath(new URL("./src", import.meta.url)),
    },
  },
});

  • 主题/ThemeWrapper.vue
<template>
  <div class="vite-theme-plugin-build">
    <MenuLauncher></MenuLauncher>
    <div style="color:red" v-if="test1">Is Rendered from Theme Wrapper</div>
  </div>
</template>

<script lang="ts">
import type { App, Component } from 'vue';

type Framework = {
  app: App;
  externalComponents: {
    ThemeWrapper: Component;
    MenuLauncher: Component;
  };
};
const w = window as unknown as Framework;

console.log(w);

export default {
  name: "ThemeWrapper",
  components: {
    MenuLauncher: w.externalComponents.MenuLauncher
  },
  setup() {
    return {
      test1: true,
    };
  },
};
</script>
  • 主题/main.ts
import type { App, Component } from "vue";
import ThemeWrapperVue from "./ThemeWrapper.vue";

type Framework = {
  app: App;
  externalComponents: {
    ThemeWrapper: Component;
    MenuLauncher: Component;
  };
};

const w = window as unknown as Framework;
w.externalComponents = w.externalComponents || {};
w.externalComponents.ThemeWrapper = ThemeWrapperVue;

菜单插件项目

  • 菜单/vite.config.ts
Identical to the ThemePlugin project configuration
  • 菜单/MenuLauncher.vue
<template>
  <div class="vite-menu-plugin-build">
    <div>
      This is dynamic menu launcher!
    </div>
    <div style="color:blue" v-if="test1">Is Rendered from MenuLauncher</div>
  </div>
</template>

<script lang="ts">
export default {
  name: "MenuLauncher",
  setup() {
    return {
      test1: true,
    };
  },
};
</script>

  • 菜单/main.ts
import type { App, Component } from "vue";

import MenuLauncherVue from "./MenuLauncher.vue";

type Framework = {
  app: App;
  externalComponents: {
    ThemeWrapper: Component;
    MenuLauncher: Component;
  };
};

const w = window as unknown as Framework;

w.externalComponents = w.externalComponents || {};
w.externalComponents.MenuLauncher = MenuLauncherVue;



index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Test</title>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <script  src="./menu/dist/plugin.js"></script>
    <script  src="./theme/dist/plugin.js"></script>
  </head>
  <body>
    <div id="app"></div>

    <script>
      document.addEventListener("DOMContentLoaded", (event) => {
        window.app = Vue.createApp({
          setup() {
            return {};
          },
          template: `
        <div>
            <div style="border: 1px solid gainsboro; margin:1rem;">
              <div>ThemeWrapper component doesn't load MenuLauncher component....</div>
              <ThemeWrapper></ThemeWrapper>
            </div>
            <div style="border: 1px solid gainsboro; margin:1rem;">
              <div>Root component is able to render MenuLauncher... But above "ThemeWrapper" component cannot render it Why???</div>
              <MenuLauncher></MenuLauncher>    
            </div>
        </div>`,
        });
        window.app.component('MenuLauncher', window.externalComponents.MenuLauncher)
        window.app.component('ThemeWrapper', window.externalComponents.ThemeWrapper)
        window.app.mount("#app");
      });
    </script>
  </body>
</html>

最终结果预览:

期望的结果:

MenuLauncherVue
组件应该能够在
ThemeWrapper
组件内渲染。

vue.js vuejs3 vite
1个回答
0
投票

我绝不是 vue 方面的专家,但我发现这很有趣。因此,在复制代码后,以下行似乎只会在构建时注册组件:

  components: {
    MenuLauncher: w.externalComponents.MenuLauncher
  },

所以我想也许我们可以使用像

defineAsyncComponent
这样的东西,但我尝试使用
<component :is="" />
,它似乎足以满足这个要求(它似乎能够在运行时注册,而不是构建时注册)。 所以在模板中,不要使用这个:

<MenuLauncher></MenuLauncher>

我们可以用这个:

<component :is="menuLauncherComponent"></component>

然后在脚本部分,我不知道为什么我们不能使用

ref
来表示
menuLauncherComponent
,所以我们可以使用好的 ol' options API,如下所示:

  data() {
    return {
      menuLauncherComponent: null,
    };
  },
  ...
  mounted() {
    this.menuLauncherComponent = (window as any).externalComponents.MenuLauncher; // register the component here
  },

所以

ThemeWrapper.vue
的完整代码可以是这样的:

<template>
  <div class="vite-theme-plugin-build">
    <component :is="menuLauncherComponent"></component>
    <div style="color: red" v-if="test1">Is Rendered from Theme Wrapper</div>
  </div>
</template>

<script lang="ts">
import type { App, Component } from "vue";

type Framework = {
  app: App;
  externalComponents: {
    ThemeWrapper: Component;
    MenuLauncher: Component;
  };
};

export default {
  name: "ThemeWrapper",
  data() {
    return {
      menuLauncherComponent: null,
    };
  },
  setup() {
    return {
      test1: true,
    };
  },
  mounted() {
    this.menuLauncherComponent = (window as any).externalComponents.MenuLauncher; // register the component here
  },
};
</script>

我在这个存储库上对此进行了测试。

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