qiankun父子之间相互通信

本功能实现:父传子、子传父
此链接有下载qiankun插件和qiankun的介绍:qiankun官网介绍

  1. 先创建两个项目 一个作为项目基座(vue-dp-base),一个作为子应用(vue-children)

  2. 配置基座父框架

    搭建基座及配置信息

     1. 下载插件
    
			npm install qiankun
     2.在main中导入qiankun 并启动
import { createApp } from 'vue'
import {registerMicroApps, start} from "qiankun";
import App from './App.vue'
import router from './routes/index'
const app = createApp(App)
// 基座的配置
const apps = [
    {
        name: "fileManagementApp", // 应用的名字 档案管理
        entry: "//localhost:20000", // 默认会加载这个html解析里面的js动态的执行(子应用必须支持跨域) fetch
        container: "#fileManagement", // 加载到哪个元素上面,容器名称
        activeRule: '/fileManagement',
        sandbox: {
            strictStyleIsolation:true,// 开启样式隔离
        }
    }
];
start();//开启
// 导出 qiankun 的启动函数export default start;
app.use(router)
app.use(ElementPlus, {
    locale:zhCn,
});
app.mount('#app')
		 3. 放置路由或按钮把子路由加载到相应的元素上面
			 - 可以放在app.vue中
			 - 也可以放到页面的按钮的点击事件中
<template>
  <div>
    <el-menu :router="true" mode="horizontal">
      <!--基座中可以放自己的路由-->
      <el-menu-item index="/">Home</el-menu-item>
      <!--引用其他子应用-->
      <el-menu-item index="/fileManagement">vue应用</el-menu-item>
    </el-menu>
    <router-view></router-view>
    <div id="fileManagement"></div>
  </div>
</template>
<template>
	 <a
	    href="javascript:;"
	    @click="goBBGL"
	  >
	   去往子路由档案管理
	  </a>
</template>
<script setup lang="ts">
const goBBGL = () => {
  let href = "/fileManagement";
  let title = "档案管理";
  let stateObj = {};
  window.history.pushState(stateObj, title, href);
};
</script>
			4. 基座设置路由 注意 最好是history模式
import { RouteRecordRaw, createRouter, createWebHistory,createWebHashHistory } from "vue-router";
const routes: Array<RouteRecordRaw> = []
// 路由
const router = createRouter({
    history: createWebHistory(),
    routes
})
// 导出
export default router 
			 5.配置基座的vuex 
			 	会涉及到更改更新相应的值 
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    token: ''
  },
  getters: {
  },
  mutations: {
    changeName(state, token){
      state.token= token;
    }
  },
  actions: {
    changeName(context, username){
      context.commit('changeToken', token);
    }
  },
  modules: {
  }
})
				 6.基座定义全局状态,并返回通信方法,子应用通过props获取通信方法
import { initGlobalState, MicroAppStateActions } from 'qiankun';

// 注意放到start()下面
const state = {
  token: 'abckdlajflajdf====jalkdjf------'
}
// 初始化 state
const actions: MicroAppStateActions = initGlobalState(state);

actions.onGlobalStateChange((state, prev) => {
  // state: 变更后的状态; prev 变更前的状态
  console.log(state, prev);
});
actions.setGlobalState(state);// 初始化了state

store.dispatch('changeToken', state.token);// 修改vuex中值
  1. 配置子应用

     1. 在子应用 mian.js中 设置补全路径,浏览器跨域的问题,需要拿到完整url
     2. 入口文件 main.js 修改,为了避免根 id #app 与其他的 DOM 冲突,需要限制查找范围
    
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";

Vue.config.productionTip = false;
let instance = null;
function render(props) {
  instance = new Vue({
    router,
    store,
    render: (h) => h(App),
  }).$mount(container ? container.querySelector('#app') : '#app');
}
/*eslint disable no undef*/
// 上方这一行用于eslint的忽略,因为下方代码的指向其实是不存在的,在有eslint的环境中不加入此行会报错
// 如果是qiankun框架使用它
if (window.__POWERED_BY_QIANKUN__) {
  store.state.isQiankun = true;
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
// 如果是独立运行的话
if (!window.__POWERED_BY_QIANKUN__) {
  render();
}
function storeTest(props) {
  props.onGlobalStateChange((value, prev) => {
    console.log("从基座传过来的值onGlobalStateChange:", value.token);
  }, true);
  props.setGlobalState &&
    props.setGlobalState({
      ignore: props.token,
      user: {
        name: props.token,
      },
    });
}

// 子组件的协议就ok了
export async function bootstrap(props) {}
export async function mount(props) {
  storeTest(props);
  render(props);
}
export async function unmount(props) {
  instance.$destroy();
  instance.$el.innerHTML = "";
  instance = null;
}

		 3. 子路由打包配置修改 vue.config.js
const { defineConfig } = require("@vue/cli-service");
const path = require("path");
const { name } = require('./package');
module.exports = defineConfig({
  transpileDependencies: true,
  devServer: {
    port: 20000,
    open: "http://localhost:20000",
    headers: {
      "Access-Control-Allow-Origin": "*",
    },
  },
  configureWebpack: {
    output: {
      library: "fileManagementApp",
      libraryTarget: "umd", // 打包的类型
       jsonpFunction: `webpackJsonp_${name}`,// 取决于webpack的版本(可不要,但小于webpack5.x则需要加上)
    },
  },
});
		 4. 修改子框架的路由 router目录下的index.js文件
import Vue from "vue";
import VueRouter from "vue-router";
Vue.use(VueRouter);
const routes = [];
const router = new VueRouter({
  mode: "history",
  base: window.__POWERED_BY_QIANKUN__ ? "/fileManagement" : "/",// 注意此处的名字要与基座中对应
  routes,
});

export default router;

		 5. 修改子框架的 mian.js
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
Vue.config.productionTip = false;
let instance = null;
function render(props) {
  instance = new Vue({
    router,
    store,
    render: (h) => h(App),
  })..$mount(container ? container.querySelector('#app') : '#app');
  // 可以给根路由另外起个名字 涉及到的文件 public下的index.html 和app.vue中的id
  // $mount("#app_children");
}
/*eslint disable no undef*/
// 上方这一行用于eslint的忽略,因为下方代码的指向其实是不存在的,在有eslint的环境中不加入此行会报错
// 如果是qiankun框架使用它
if (window.__POWERED_BY_QIANKUN__) {
  store.state.isQiankun = true;
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
// 如果是独立运行的话
if (!window.__POWERED_BY_QIANKUN__) {
  render();
}
function storeTest(props) {
  props.onGlobalStateChange((value, prev) => {
    console.log("从基座传过来的值onGlobalStateChange:", value.token);
  }, true);
  props.setGlobalState &&
    props.setGlobalState({
      ignore: props.token,
      user: {
        name: props.token,
      },
    });
  console.log("子路由走这个方法=>setGlobalState", props.token);
}

// 子组件的协议就ok了
export async function bootstrap(props) {}
export async function mount(props) {
  storeTest(props);
  render(props);
}
export async function unmount(props) {
  instance.$destroy();
  instance.$el.innerHTML = "";
  instance = null;
}

4.基座(父应用)和子应用之间的数据互通。

 1. 修改基座项目里的mian.js
// 如果要在页面中使用,可以挂在到原型链上
Vue.prototype.$setGlobalState = actions.setGlobalState;
// 也可以将需要通信的数据在vuex中进行操作

actions.onGlobalStateChange((state, prev) => {
  // state: 变更后的状态; prev 变更前的状态
  console.log(state, prev);
  // 监听子应用数据更改
});
 2. 在app.vue中修改 或者在页面中使用
<script>
  export default {
    name: 'App',
    methods:{
      changeName(){
        this.$store.dispatch('changeToken','=======adlfkjads=====');
        this.$setGlobalState({token:'=======adlfkjads====='})// 将数据发送给子应用
      }
    }
  }
</script>
 3. 子应用 的mian.js
function storeTest(props) {
    props.onGlobalStateChange &&
      props.onGlobalStateChange(
        (value, prev) => {
          store.dispatch('changeName', value.username);
        },
        true,
      );
    if(props.setGlobalState){
        Vue.prototype.$setGlobalState = props.setGlobalState; // 同基座,将set方法加载到原型链上
    }
}
 4. 子应用中的 App.vue中
<div id="app">
    <button @click="changeToken">changeToken</button>
    {{ $store.state }}
    <br/>
</div>
<script>
  export default {
    name: 'App',
    methods:{
      changeToken(){
        this.$store.dispatch('changeName','====aldfj=====');
        this.$setGlobalState({token:'====aldfj====='});// 更改主应用数据
      }
    }
  }
</script>
<style>
Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐