Skip to content

GitLab

  • Projects
  • Groups
  • Snippets
  • Help
    • Loading...
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in / Register
T treasure
  • Project overview
    • Project overview
    • Details
    • Activity
    • Releases
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 12
    • Issues 12
    • List
    • Boards
    • Labels
    • Service Desk
    • Milestones
  • Merge requests 0
    • Merge requests 0
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Operations
    • Operations
    • Incidents
    • Environments
  • Packages & Registries
    • Packages & Registries
    • Container Registry
  • Analytics
    • Analytics
    • CI/CD
    • Repository
    • Value Stream
  • Wiki
    • Wiki
  • External wiki
    • External wiki
  • Snippets
    • Snippets
  • Members
    • Members
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • FE
  • treasure
  • Issues
  • #128

Closed
Open
Created Feb 20, 2023 by JayChen@JayChenOwner

微应用开发注意事项

1、window.open 不能滥用,(在微应用开发里,必须使用dispatchWindowOpen)

邻汇吧项目跳转不能用orgin,但是其他三方链接跳转得用orgin!!!

错误示例:

const url = type === 'placeName' ? `/placeMng/detail?tenantPlaceId=${id}` : `/pointMng/detail?tenantSpotId=${id}`;
dispatchWindowOpen(location.origin + url);

正确做法:

dispatchWindowOpen(url);

2、navigate跳转不可滥用,(在微应用开发里优先使用 dispatchNavigate)

3、微应用项目开发,不能直接用 ant的 Modal,如 Modal.confirm 等函数式写法

必须使用已经封装好的window.microModal,如 window.microModal.confirm

4、微应用项目开发,不能直接用 ant的 message,如 message.error, message.info 等函数式写法

必须使用已经封装好的window.microMessage,如 window.microMessage.error

5、微应用项目开发,不能直接用 ant的 notification,如 notification.error, notification.info 等函数式写法

必须使用已经封装好的window.microNotification,如 window.microNotification.error

6、所有用到 Image组件的预览功能时,如 <Image.PreviewGroup> 组件

需要进行如下设置

<PreviewGroup preview={{
    getContainer: false
}}>

7、不要直接用antd的 Anchor 组件,在主应用是hash模式时会有问题

请使用经过封装的 CustomAnchor 组件,参数和Anchor一致 image

8、样式覆盖使用.ant-xx不会生效,需要使用.resant

9、document的使用需要注释

document是获取的外层的,是不能正确的获取到沙河内部的,当然querySelector可以,但是会优先查找父级,所以需要通过如下方式操作

import { MainAppContext } from '@/index';
import { useContext } from 'react';
const demo = () => {
  const { container } = useContext(MainAppContext);
}

在使用到的地方

// container就是微应用沙盒对象
(container || document)?.querySelector('#spotForm .resant-form-item-has-error');

10、当出现套娃弹窗时需要注意

示例: 先弹出一个 drawer,再点击按钮弹出一个modal,同时modal上挂载了forcerender
因为预加载了modal,他会在drawer之前生成浮层,就会导致drawer遮盖住mode
解决方案:
html文件有个

<Modal
   ...
   getContainer={() => (container || document).querySelector('#lhb-mirco-matryoshka')}

11、useModal、Modal.method()用法注意

在微应用内,必须使用useModal写法,不能用函数写法!!! 直接使用window.microModal可能会有层级问题。可以直接使用封装的ConfirmModal,z-index固定1009(仅次于microMessage),如有其他层级混乱可参考第9点套娃弹窗,尽量不要使用z-index修改层级。

// 详细可参考 resource-service-web 的 ConfirmModal
export const ConfirmModal = ({
  onSure = () => {},
  onCancel = () => {},
  cancelText = '取消',
  okText = '确定',
  icon = <ExclamationCircleOutlined />,
  title = '提示',
  content = '此操作将永久删除该数据, 是否继续?',
}:ConfirmModalProps) => {
  // 在微应用内,必须使用useModal写法,不能用函数写法!!!
  const modal = window.microModal.confirm({
    title: title,
    content: content,
    icon: icon,
    okText: okText,
    cancelText: cancelText,
    zIndex: 1009,
    onOk: () => onSure(modal),
    onCancel: () => onCancel(modal)
  });
};

12、CustomAnchor用法注意

在微应用内,必须使用className做锚点定位,使用id会导致在history模式下不起作用

13、Image.PreviwerGroup用法注意

在微应用内必选在Image.PreviwerGroup节点上挂载getContainer否则不会出现顶部控制栏以及左右切换按钮

const { container } = useContext(MainAppContext);
<Image
  key={index}
  src={QiniuImageUrl(item.url)}
  style={{ width, height }}
  preview={{ visible: false }}
  onClick={() => {
    setImageIndex(index);
    setPreviewVisible(true);
  }}
/>

<div style={{ display: 'none' }}>
      <Image.PreviewGroup preview={{
        visible: previewVisible,
        onVisibleChange: vis => setPreviewVisible(vis),
        getContainer: (container || document)?.querySelector('#popContainer'), // 需要挂载到当前应用节点,否则不会出现顶部工具栏以及左右切换按钮
        current: imagesIndex
      }}>
        { images.map((image, index) => { return <Image src={QiniuImageUrl(image.url)} key={index} />; }) }
      </Image.PreviewGroup>
    </div>

14、微应用之间如何跳转?

● 主应用和微应用都是 hash 模式,主应用根据 hash 来判断微应用,则不用考虑这个问题。 ● 主应用根据 path 来判断微应用history 模式的微应用之间的跳转,或者微应用跳主应用页面,直接使用微应用的路由实例是不行的,原因是微应用的路由实例跳转都基于路由的 base。

a. history.pushState()

history.pushState(null, '档期管理', window.location.origin + '/schedule');

// 不建议location.href 会有‘白屏现象’
window.location.href = '/schedule';

b. 将主应用的路由实例通过 props 传给微应用,微应用这个路由实例跳转。

15、跳转应用样式丢失问题

主应用vue,子应用react

在子项目跳转到父项目时,子项目的卸载需要一点点的时间,在这段时间内,父项目加载了document.head.appendChild被改写了,导致vue-style-loader没有把样式加到正确的节点上。

解决办法

import VueRouter, { Route } from 'vue-router';
import { Message } from 'element-ui';
const childRoute = ['/lhb-micro-pms']; // 子应用前缀
const isChildRoute = (path: string) => childRoute.some(item => path.startsWith(item));
// 临时解决方案:复制一份HTMLHeadElement.prototype.appendChild和window.addEventListener,路由钩子函数beforeEach中判断一下,如果当前路由是子项目,并且去的路由是父项目的,则还原这两个对象
// const rawAppendChild = HTMLHeadElement.prototype.appendChild; 
// const rawAddEventListener = window.addEventListener;
import { setCurrentRunningApp } from 'qiankun/es/sandbox/common';

export default function routerControl(router: VueRouter) {
  router.beforeEach((to: Route, from: Route, next: Function) => {
     // 判断如果是子应用跳转到父应用
    if (isChildRoute(from.path) && !isChildRoute(to.path)) {
      // 临时解决方案:
      //HTMLHeadElement.prototype.appendChild = rawAppendChild;
      //window.addEventListener = rawAddEventListener;
      // 建议解决方案:
      setCurrentRunningApp(null); // 清空当前应用设置,相当于重新加载
    }
    // 动态设置页面title
    if (to.meta.title) {
      document.title = to.meta.title;
    } else {
      process.env.NODE_ENV === 'development' && Message.error('为了方便数据采集,请添加title!');
    }
    // 路由为空时重定向回首页
    if (to.path === '/') {
      router.replace('/schedule');
    } else {
      next();
    }
  });
  router.afterEach((to: any, from: any) => {
    if (process.env.NODE_ENV !== 'development') {
      // 先发送离开页面的信息 再上传进入页面的信息
      window.LHBbigdata.spa.beforeRouteLeave()(to, from);
      window.LHBbigdata.spa.beforeRouteEnter()(to, from);
    }
  });
}
Edited Jun 01, 2023 by JayChen
Assignee
Assign to
None
Milestone
None
Assign milestone
Time tracking