qiankun父子之间相互通信
本功能实现:父传子、子传父
此链接有下载qiankun插件和qiankun的介绍:qiankun官网介绍
-
先创建两个项目 一个作为项目基座(vue-dp-base),一个作为子应用(vue-children)
-
配置基座父框架
搭建基座及配置信息
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. 在子应用 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>