Vue中使用乾坤(qiankun)微应用开发多应用

乾坤qiankun文档地址:乾坤qiankun文档

方法参数备注
registerMicroApps <Array> name ✅ sub-app 微应用的名称
  entry ✅ //localhost:4001 子应用地址
  container ✅ #subapp-viewport 微应用的容器节点选择器
  activeRule ✅ /vue 微应用的激活规则(子应用路由history规则)
  props:{ globalState updateState } globalState updateState globalState:传递数据 updateState:传递修改方法 ✅ 核心
start <Objct> sandbox : {} strictStyleIsolation: true 样式隔离
setDefaultMountApp   '/homeApp' 设置主应用启动后默认进入的微应用
       
       
       
       

主应用

安装乾坤qiankun
$ yarn add qiankun # 或者 npm i qiankun -S
在主应用中注册微应用
// main.js

import { registerMicroApps, start } from "qiankun";
// 自己维护全局状态(不依赖 qiankun)
const globalState = {
  user: { name: "admin", role: "admin" },
  token: "123456",
};

// 定义修改方法(子应用也能调用)
function updateState(state) {
  Object.assign(globalState, state);
  // 派发事件,所有应用同步更新
  window.dispatchEvent(new CustomEvent("stateChange", { detail: globalState }));
}

// 注册子应用
registerMicroApps([
  {
    name: "sub-app", // 子应用名称
    entry: "//localhost:4001", // 子应用地址
    container: "#subapp-viewport", // EL容器
    activeRule: "/vue", //子应用路由history规则 [ history: createWebHistory("/vue")]
    props: {
      globalState, // 传递数据
      updateState, // 传递修改方法 ✅ 核心
    },
  },
]);

// 启动应用
start({
  // 样式沙箱
  sandbox: {
    // 🌈 关闭严格隔离(关闭 Shadow DOM)
    strictStyleIsolation: false,
    // ✅ 开启:实验性样式隔离(推荐!动态加前缀,类似 Vue scoped)
    experimentalStyleIsolation: true,
  },
});
加载子应用
// App.vue
<template>
  <h1>主应用</h1>
  <p>{{ user.name }} , {{ user.role }} , {{ token }}</p>
  <button @click="change">主应用修改数据</button>
  <router-view></router-view>
  <!-- 导航 -->
  <div style="margin:10px 0">
    <router-link to="/">首页</router-link> |
    <router-link to="/vue">子应用 Vue3</router-link> |
    <router-link to="/vue2">子应用 Vue2</router-link>
  </div>
  <div id="subapp-viewport"></div>
</template>

<script setup>
import { ref } from "vue";

const user = ref({});
const token = ref("");

// 监听数据更新
window.addEventListener("stateChange", (e) => {
  console.log(e.detail);
  user.value = e.detail.user;
  token.value = e.detail.token;
});

// 更新数据
const change = () => {
  window.dispatchEvent(
    new CustomEvent("stateChange", {
      detail: {
        user: { name: "主应用更新啦", role: "role-main" },
        token: "new-token",
      },
    }),
  );
};
</script>
router配置
// router.js

import { createRouter, createWebHistory } from "vue-router";
import Home from "./components/Home.vue";

const routes = [
  { path: "/", component: Home },
  // 子应用路由占位(自动匹配)
  { path: "/vue/:pathMatch(.*)*", component: { render: () => null } },
  // { path: '/vue2/:pathMatch(.*)*', component: { render: () => null } }
];

const router = createRouter({
  history: createWebHistory(),
  routes,
});

export default router;

子应用

安装vite-plugin-qiankun
npm install vite-plugin-qiankun --save-dev
vite.config.js配置
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import qiankun from "vite-plugin-qiankun";

// https://vite.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    // ✅ 注册微前端子应用
    qiankun("sub-app", {
      useDevMode: true, // 禁用 Vite 热更新(HMR),以避免与 qiankun 的沙箱机制冲突,确保子应用能正确注册并被主应用加载
    }),
  ],
  server: {
    port: 4001,
    host: "0.0.0.0",
    cors: true, // ✅ 子应用开启跨域
    origin: "http://localhost:4001",
  },
});
子应用main.js
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import {
  renderWithQiankun,
  qiankunWindow,
} from "vite-plugin-qiankun/dist/helper";

let app = null;

// 渲染函数
function render(props = {}) {
  const { container } = props;
  console.log(props, "render"); // 获取主应用传入子应用数据
  app = createApp(App);
  app.use(router);
  app.mount(container ? container.querySelector("#app") : "#app");

  // 将通信方法挂载到全局
  window.$qiankun = props;
}

// 独立运行时直接渲染
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
  render();
}

// qiankun 生命周期
renderWithQiankun({
  // 挂载时触发
  // 用于初始化子应用的状态
  mount(props) {
    render(props);
  },
  // 只有子应用第一次加载会触发
  bootstrap() {},
  // 卸载时触发
  // 用于清理子应用的状态和事件
  unmount() {
    app.unmount();
  },
});

export { render };
子应用App.vue
<template>
  <h2>🧩 子应用 A</h2>
  <p>🌈接收数据:{{ user?.name }}</p>
  <button @click="updateSub">子应用修改全局数据</button>
  <div @click="goAbout" style="padding: 10px; background: #ccc; width: 300px;">
    去关于我们页面
  </div>
  <router-view></router-view>
</template>

<script setup>
import { ref, onMounted, nextTick } from "vue";
import { useRouter } from "vue-router";
const router = useRouter();
const user = ref({});

onMounted(async () => {
  // 等待 nextTick 确保子应用状态更新完成
  await nextTick();
  // 从全局状态中获取用户信息
  user.value = window.$qiankun.globalState?.user;
});
// 子应用修改全局数据
const updateSub = () => {
  window.$qiankun.updateState({
    user: { name: "子应用A修改成功", role: "role-child" },
    token: "token-999",
  });
};
// 去关于我们页面
const goAbout = () => {
  router.push({
    path: "/about",
    query: {
      id: "55555",
    },
  });
};
</script>
子应用router.js
import { createRouter, createWebHistory } from "vue-router";
import Home from "./components/HelloWorld.vue";

export default createRouter({
  history: createWebHistory("/vue"), // 🌈 必须和主应用 activeRule 一致
  routes: [
    { path: "/", component: Home },
    { path: "/about", component: () => import("./components/About.vue") },
  ],
});

 

下载案例代码:下载按钮

 

posted @ 2026-04-17 14:59  蜗牛snail  阅读(7)  评论(0)    收藏  举报
蜗牛前端 蜗牛文学