首頁 > 軟體

vue3+ts+MicroApp實戰教學

2022-11-01 14:02:16

專案准備

1、基於amin-work-x專案作為原始專案,改造動態選單為自定義選單

2、分別在主應用專案(main)和子應用(childrenOne,childrenTwo)專案中安裝microApp

npm i @micro-zoe/micro-app --save

子專案設定

1,修改子專案mian.ts,新增與基座的互動設定和路由衝突解決

import { createApp } from "vue";
import App from "./App.vue";
import { Router } from 'vue-router'
import router from "./router";
import "./utils/router";
import ElementPlus from "element-plus";
import "element-plus/dist/index.css";
import "dayjs/locale/zh-cn";
import zhCn from "element-plus/es/locale/lang/zh-cn";
import "@/icons/iconfont/iconfont.css";
import "@/icons/iconfont/iconfont.js";
import "@/styles/main.css";
import LayoutStore from "@/layouts";
import http from "@/api/http";
import { registerComponents } from "./components";
import * as Icons from "@element-plus/icons";
import pinia from "./store/pinia";

import "./setting";
declare global {
  interface Window {
    microApp: any
    __MICRO_APP_NAME__: string
    __MICRO_APP_ENVIRONMENT__: string
    __MICRO_APP_BASE_ROUTE__: string
  }
}

// 與基座進行資料互動
function handleMicroData(router: Router) {
  // 是否是微前端環境
  if (window.__MICRO_APP_ENVIRONMENT__) {

    // 監聽基座下發的資料變化
    window.microApp.addDataListener((data: Record<string, unknown>) => {
      console.log('child-vue3 addDataListener:', data)

      // 當基座下發path時進行跳轉
      if (data.path && data.path !== router.currentRoute.value.path) {
        router.push(data.path as string)
      }
    })

    // 向基座傳送資料
    setTimeout(() => {
      window.microApp.dispatch({ myname: 'tenant-app' })
    }, 3000)
  }
}

/**
 * 用於解決主應用和子應用都是vue-router4時相互衝突,導致點選瀏覽器返回按鈕,路由錯誤的問題。
 * 相關issue:https://github.com/micro-zoe/micro-app/issues/155
 * 當前vue-router版本:4.0.12
 */
function fixBugForVueRouter4(router: Router) {

  // 判斷主應用是main-vue3或main-vite,因為這這兩個主應用是 vue-router4
  if (window.__MICRO_APP_ENVIRONMENT__) {
    //if (window.location.href.includes('/main-vue3') || window.location.href.includes('/main-vite')) {
    /**
     * 重要說明:
     * 1、這裡主應用下發的基礎路由為:`/main-xxx/app-vue3`,其中 `/main-xxx` 是主應用的基礎路由,需要去掉,我們只取`/app-vue3`,不同專案根據實際情況調整
     *
     * 2、realBaseRoute 的值為 `/app-vue3`
     */

    const realBaseRoute = window.__MICRO_APP_BASE_ROUTE__;//.replace(/^/app-tenant-[^/]+/g, '')

    router.beforeEach(() => {
      if (typeof window.history.state?.current === 'string') {
        window.history.state.current = window.history.state.current.replace(new RegExp(realBaseRoute, 'g'), '')
      }
    })

    router.afterEach(() => {
      if (typeof window.history.state === 'object') {
        window.history.state.current = realBaseRoute + (window.history.state.current || '')
      }
    })
  }
}
const app = createApp(App);
Object.keys(Icons).forEach((it) => {
  app.component(it, (Icons as any)[it]);
});
registerComponents(app);
app.use(LayoutStore, {
  state: {
    layoutMode: "ltr",
  },
  actions: {
    onPersonalCenter() {
      router.push({ path: "/personal", query: { uid: 1 } });
    },
    onLogout() {
      router.replace({ path: "/login", query: { redirect: "/" } }).then(() => {
        window.location.reload();
      });
    },
  },
});
app.use(pinia).use(router);
app.use(ElementPlus, {
  locale: zhCn,
});
app.use(http);
app.mount("#app");

handleMicroData(router)
fixBugForVueRouter4(router)
// 監聽解除安裝操作
window.addEventListener('unmount', function () {
  //console.log("r4開始解除安裝", window.location, window.history, app)
  app?.unmount()
  //console.log('微應用child-vue3解除安裝了')
})

2,修改vue.config.js檔案,設定publicPath、埠號、允許跨域

3,為保證子應用的路由在主應用中能直接使用,可在每個路由前新增子應用的路由標誌

這一步可不操作,如果不新增,則需要在主應用新增選單或者動態獲取選單時,根據其他標誌,為路由手動加上當前子應用的標誌,用於判斷子應用來源

4、修改子應用路由問history模式

const router = createRouter({
  history: createWebHistory(window.__MICRO_APP_BASE_ROUTE__||process.env.BASE_URL),
  routes: mapTwoLevelRouter([...constantRoutes, ...asyncRoutes]),
});

主應用專案設定

1,在layout中新增子應用入口檔案(srclayoutsmicroappapp-one.vue)

<template>
  <div style="height: 100%">
    <micro-app
      name="appname-one"
      :url="url"
      baseroute="/app-main"
      :data="microAppData"
      @created="handleCreate"
      @beforemount="handleBeforeMount"
      @mounted="handleMount"
      @unmount="handleUnmount"
      @error="handleError"
      @datachange="handleDataChange"
      style="height: 100%"
    ></micro-app>
  </div>
</template>

<script lang="ts">
export default {
  name: "name-app",
  data() {
    return {
      url:
        process.env.NODE_ENV === "development"
          ? "http://localhost:4009/app-one"
          : "通過設定獲取線上地址",
      microAppData: { msg: "來自基座的資料" },
    };
  },
  methods: {
    handleCreate(): void {
      console.log("child-vue3 建立了");
    },

    handleBeforeMount(): void {
      console.log("child-vue3 即將被渲染");
    },

    handleMount(): void {
      console.log("child-vue3 已經渲染完成");

      setTimeout(() => {
        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
        // @ts-ignore
        this.microAppData = { msg: "來自基座的新資料" };
      }, 2000);
    },

    handleUnmount(): void {
      console.log("child-vue3 解除安裝了");
    },

    handleError(): void {
      console.log("child-vue3 載入出錯了");
    },

    handleDataChange(e: CustomEvent): void {
      console.log("來自子應用 child-vue3 的資料:", e.detail.data);
    },
  },
};
</script>

<style></style>

2,在主應用中註冊子應用路由

子應用的路由第一次指向主應用的layout,第二層指向上面新建的入口檔案

3,修改主應用publicPath

此處的publicPath需與app-one中的baseroute保持一致

設定完成後,先後執行兩個專案後,在主應用中手動新增一個子應用的的具體頁面路由,就可以在主應用中開啟子應用了,但是此時子應用的路由表覆蓋了主應用。

為解決這個問題,需要在子應用中新增一個非layout佈局的空頁面,當子應用單獨執行時,指向layout佈局頁面,如果是在微服務中使用,則指向空頁面

srclayoutsEmptyLayout.vue

<template>
  <div class="empty-layout">
    <router-view> </router-view>
  </div>
</template>
<style lang="scss" scoped>
.empty-layout {
  height: 100%;
}
</style>

srcrouterindex.ts

到此這篇關於vue3+ts+MicroApp實戰教學的文章就介紹到這了,更多相關vue3 ts MicroApp內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com