qiankun的简单使用和通信

文章目录

  • 简单使用
    • 主应用
      • 1. 安装 qiankun
      • 2. 在主应用中注册微应用
    • 微应用
      • 1. 配置main.js
      • 2.导出routes
      • 3. 配置微应用的打包工具
        • vue.config.js
        • 新建src->public-path.js
  • 通信
    • api
    • 简单实验
      • 主应用
      • 微应用

qiankun是一个微前端js框架

简单使用

主应用

1. 安装 qiankun

注意我们只需要在主应用中安装qiankun,子应用中是不用的。

$ yarn add qiankun # 或者 npm i qiankun -S

2. 在主应用中注册微应用

vue项目在main.js中注册。

import {
      registerMicroApps, start } from 'qiankun';

/**
 * 路由监听
 * @param {*} routerPrefix 前缀
 */
// function genActiveRule(routerPrefix) {
     
//   console.log(location.pathname)
//   return location => location.pathname.indexOf(routerPrefix);
// }   //activeRule的配置函数,当然我们也可以直接配置字符串和其他规则,具体参考文档


registerMicroApps([
  {
     
    name: 'new-project',  // 子应用名称
    entry: '//localhost:8082', //子应用入口,就是单独访问子应用时的url,这里我把子应用配置在8082端口
    container: '#container',	// 子应用挂载的dom容器,我们把它写在主应用的app.vue中
    // activeRule: genActiveRule("/app1"), //子应用触发路径,这里使用前面配置的函数
    activeRule:"/app1" //当我们主应用的url含有app1时会触发子应用加载,为了方便触发,建议主应用路由使用history模式,在hash模式下,自动添加的#号会影响子应用触发(不知道为什么)
  },
]);
//启动
start();

增加挂载子应用的盒子

app.vue

<template>
    <div id="app">
         <p>我是父应用</p>
         <!-- 子应用容器 -->
        <div id="container"></div>
    </div>
</template>

微应用

微应用不需要额外安装任何其他依赖即可接入 qiankun 主应用。

1. 配置main.js

微应用需要在自己的入口 js 导出 bootstrapmountunmount 三个生命周期钩子,以供主应用在适当的时机调用。

main.js

import './public-path' // 注意需要引入public-path
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router';
import routes from './router';

let router = null;
let instance = null;

function render(props = {
     }) {
     
  const {
      container } = props;
  router = new VueRouter({
     
    base: '/app1', //这里要和在主应用配置的activeRule一样
    mode: 'history',
    routes,
  });

  instance = new Vue({
     
    router,
    render: h => h(App),
  }).$mount(container ? container.querySelector('#app') : '#app');
}

// webpack打包公共文件路径
if (window.__POWERED_BY_QIANKUN__) {
     
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}else{
     
	// 独立运行
  render();
}

// 生命周期
export async function bootstrap() {
     
  console.log('[vue] vue app bootstraped');
}
export async function mount(props) {
     
  console.log('[vue] props from main framework', props);
  render(props);
}
export async function unmount() {
     
  instance.$destroy();
  instance.$el.innerHTML = '';
  instance = null;
  router = null;
}

2.导出routes

在上面的main.js中,我们导入的是routes对象,并非router实例

对应router->index.js我们调整为

import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
const routerPush = Router.prototype.push
Router.prototype.push = function push (location) {
     
    return routerPush.call(this, location).catch(error => error)
}

const routes= [
    {
     
        path: '/',
        name: '1',
        component: () => import('./views/1.vue')
    }
]

export default routes;

3. 配置微应用的打包工具

除了代码中暴露出相应的生命周期钩子之外,为了让主应用能正确识别微应用暴露出来的一些信息,微应用的打包工具需要增加如下配置:

vue.config.js

const {
      name } = require('./package');

module.exports = {
     
    devServer: {
     // 环境配置
        host: 'localhost',
        port: 8082,
        // https
        https: false,
        hotOnly: true,
        headers: {
       //子应用必须支持跨域
            'Access-Control-Allow-Origin': '*',
        },
    },
    configureWebpack: {
     
        output: {
     
            // 把子应用打包成 umd 库格式(必须)
            library: `${
       name}-[name]`,
            libraryTarget: 'umd',
            jsonpFunction: `webpackJsonp_${
       name}`,
        },
    },
}

使用 webpack 静态 publicPath 配置:在 mian.js 中引入 public-path.js 文件

新建src->public-path.js

;(function () {
     
    if (window.__POWERED_BY_QIANKUN__) {
     
        if (process.env.NODE_ENV === 'development') {
     
            __webpack_public_path__ = `//localhost:8082/`;
            return;
        }
        __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
    }
})();

通信

api

qiankun内部使用initGlobalState(state)定义全局状态,该方法执行后返回一个MicroAppStateActions实例,实例中包含三个方法,分别是onGlobalStateChangesetGlobalStateoffGlobalStateChange。

默认会通过props将通信方法传递给子应用。

MicroAppStateActions

  • onGlobalStateChange: (callback: OnGlobalStateChangeCallback, fireImmediately?: boolean) => void, 在当前应用监听全局状态,有变更触发 callback,fireImmediately = true 立即触发 callback
  • setGlobalState: (state: Record) => boolean, 按一级属性设置全局状态,微应用中只能修改已存在的一级属性(就是用来修改全局状态
  • offGlobalStateChange: () => boolean,移除当前应用的状态监听,微应用 umount 时会默认调用

理解:这里的全局状态和vuex中的state十分类似,不同的是全局状态可以在主应用和微应用中共享

简单实验

主应用

新建src->actions.js

import {
      initGlobalState } from "qiankun"; 
import store from "./store";

const initialState = {
     
  //这里写初始化数据
};

// 初始化 state
const actions = initGlobalState(initialState);
actions.onGlobalStateChange((state, prev) => {
     //监听公共状态的变化
  console.log("主应用: 变更前");
  console.log(prev);
  console.log("主应用: 变更后");
  console.log(state);
  store.commit('setProject',state);//这里我把公共状态存到主应用的vuex里了
});

export default actions;

在组件中使用actions

tab.vue

<template>
  <div>
    <button @click="sendMes1">点击向子应用发送消息1</button>
    <button @click="sendMes2">点击向子应用发送消息2</button>
    <p>当前显示的项目: {
     {
     project}} </p>
  </div>
</template>
jindei
<script>

import actions from './actions'//记得导入actions实例
export default {
     
  data() {
     
    return {
     
      mes1: {
      project_id: '项目1' },
      mes2: {
      project_id: '项目2' },
    }
  },
  computed:{
     
      project:function(){
     
          return this.$store.state.project_id
      }
  },
  methods: {
     
    sendMes1() {
     
      actions.setGlobalState(this.mes1);//通过setGlobalState改变全局状态
    },
    sendMes2() {
     
      actions.setGlobalState(this.mes2);
    }

  },
}
</script>

微应用

新建src->actions.js

function emptyAction() {
       //设置一个actions实例
    // 提示当前使用的是空 Action
    console.warn("Current execute action is empty!");
}

class Actions {
     
    // 默认值为空 Action
    actions = {
     
        onGlobalStateChange: emptyAction,
        setGlobalState: emptyAction,
    };

    /**
     * 设置 actions
     */
    setActions(actions) {
     
        this.actions = actions;
    }

    /**
     * 映射
     */
    onGlobalStateChange(...args) {
     
        return this.actions.onGlobalStateChange(...args);
    }

    /**
     * 映射
     */
    setGlobalState(...args) {
     
        return this.actions.setGlobalState(...args);
    }
}

const actions = new Actions();
export default actions;

main.js

在mounted的生命周期里注入actions实例

export async function mount(props) {
     
  actions.setActions(props); //注入actions实例
  render(props);
}

在vue 组件中使用

1.vue

<template>
  <div>
    <div>这是子应用</div>
    <p>接收到的消息: {
     {
     mes}}</p>
    <button @click= "butClick">点击向父应用发送消息</button>
  </div>
</template>

<script>
import actions from '../actions'//导入实例
export default {
     
  data() {
     
    return {
     
      mes: '',
    }
  },
  mounted() {
     
    actions.onGlobalStateChange((state) => {
      //监听全局状态
      this.mes = state
    }, true);
  },
  methods:{
     
      butClick(){
     
          actions.setGlobalState({
      project_id: '项目99'})//改变全局状态
      }
  }
}
</script>

你可能感兴趣的:(前端,javascript,vue)