【方案讨论】针对el中依赖了poper.js 的fixed定位偏移解决方案
我这边是fork的qiankun自己在团队内增加特性功能,最近参考(缝)了wujie的一些方案后,也遇到了poper fixed定位偏移问题
解决思路如下,对body的append进行劫持,判断className是否有el-popper,有的话用MutationObserver监听style属性,有变化就把fixed改成abs,再处理好隐藏和删除逻辑,目前运行没有什么问题。
昨晚熬夜4个小时排查原因,以及使用最小代价实现弹框偏移解决办法:刚刚写了热乎的文章。可以参考一下。
微前端下element-ui弹框偏移问题解决
另外附上实现效果:
elmenet plus 依旧没有解决
elmenet plus 依旧没有解决
将popper定位强制改成绝对定位可以解决吗
elmenet plus 依旧没有解决
将popper定位强制改成绝对定位可以解决吗
这样可以诶。。。。。谢谢
@quqingfei 解决了哥,666,感谢
子应用内打开的 popover 的弹层,点击子应用内的非自身会关闭,但是点击基座应用的菜单,不会自动关闭
@quqingfei vxe-modal不生效啊哥们
解决思路:把popper的dom直接塞进主应用的body中,判断定位和显示边界也直接以主应用作为左边起点,这样的效果就和正常在项目中使用appendToBody的效果一致,代码改动也非常的少。
因为公司内部使用的组件库是基于element-ui进行封装的,所以直接在源码上进行更改了。
如果不能直接修改element-ui的源码,明确修改代码位置后,可以使用js-loader或者项目build之前修改node_modules代码。
以下代码目录都是基于element-ui源码的目录,对应在node_modules中的地址是lib/utils。
src/utils/vue-popper
// 源码
this.appendToBody && document.body.appendChild(this.popperElm);
// 修改后
if (this.appendToBody) {
if (window.__POWERED_BY_WUJIE__) {
window.parent.document.body.appendChild(this.popperElm);
} else {
document.body.appendChild(this.popperElm);
}
}
src/utils/popper.js
// 源码
var root = window;
// 修改后
var root = window.__POWERED_BY_WUJIE__ ? window.parent : window;
// 源码
function getStyleComputedProperty(element, property) {
// NOTE: 1 DOM access here
var css = root.getComputedStyle(element, null);
return css[property];
}
// 修改后
function getStyleComputedProperty(element, property) {
// NOTE: 1 DOM access here
// wujie环境下向上遍历offsetParent时 过滤document类型得节点,避免方法getComputedStyle报错
if (window.__POWERED_BY_WUJIE__ && element.nodeType === 9) return 'static';
var css = root.getComputedStyle(element, null);
return css[property];
}
解决思路:把popper的dom直接塞进主应用的body中,判断定位和显示边界也直接以主应用作为左边起点,这样的效果就和正常在项目中使用appendToBody的效果一致,代码改动也非常的少。
因为公司内部使用的组件库是基于element-ui进行封装的,所以直接在源码上进行更改了。 如果不能直接修改element-ui的源码,明确修改代码位置后,可以使用js-loader或者项目build之前修改node_modules代码。 以下代码目录都是基于element-ui源码的目录,对应在node_modules中的地址是
lib/utils。src/utils/vue-popper// 源码 this.appendToBody && document.body.appendChild(this.popperElm);// 修改后 if (this.appendToBody) { if (window.__POWERED_BY_WUJIE__) { window.parent.document.body.appendChild(this.popperElm); } else { document.body.appendChild(this.popperElm); } }
src/utils/popper.js// 源码 var root = window;// 修改后 var root = window.__POWERED_BY_WUJIE__ ? window.parent : window;// 源码 function getStyleComputedProperty(element, property) { // NOTE: 1 DOM access here var css = root.getComputedStyle(element, null); return css[property]; }// 修改后 function getStyleComputedProperty(element, property) { // NOTE: 1 DOM access here // wujie环境下向上遍历offsetParent时 过滤document类型得节点,避免方法getComputedStyle报错 if (window.__POWERED_BY_WUJIE__ && element.nodeType === 9) return 'static'; var css = root.getComputedStyle(element, null); return css[property]; }
不错的思路,无界把整个子应用dom都塞到shadowdom了,递归body的时候到了子应用的body就停止了,你这个从源头解决了,可以贡献一个 plugin,不过不同组件库appendToBody的代码可能不太一致,压缩后代码还需要自己找出来做替换了
@quqingfei 学习了,感谢
子应用内打开的 popover 的弹层,点击子应用内的非自身会关闭,但是点击基座应用的菜单,不会自动关闭
这个问题有解决的吗?
.el-popper, .el-tooltip__popper { position: absolute !important; } 可以解决 子应用 弹出层&tooltip 定位问题
昨晚熬夜4个小时排查原因,以及使用最小代价实现弹框偏移解决办法:刚刚写了热乎的文章。可以参考一下。 微前端下element-ui弹框偏移问题解决 另外附上实现效果:
![]()
![]()
我用的也是官方实例,然后加了一个固定顶部的导航,向下滚动后popper计算定位会出现向下偏差
我用的是官方实例,然后加了一个固定顶部的导航,用的方法五,向下滚动后popper计算定位会出现向下偏差,方法六是都变成固定的了(并且方法六的element ui组件样式会丢失),用的是element ui,子应用版本是"element-ui": "2.15.6", 主应用"wujie": "workspace:^1.0.22",
// 方法五5
// {
// jsLoader: (code) => {
// // 替换popper.js内计算偏左侧偏移量
// var codes = code.replace(
// "left: elementRect.left - parentRect.left",
// "left: fixed ? elementRect.left : elementRect.left - parentRect.left"
// );
// // 替换popper.js内右侧偏移量
// return codes.replace("popper.right > data.boundaries.right", "false");
// },
// },
// 方法6
{
jsLoader(code) {
// 解决element-ui,popper.js计算问题
let newCode = code
.replace("var root = window;", "var root = window.parent")
.replace(
"document.body.appendChild(this.popperElm);",
"window.parent.document.body.appendChild(this.popperElm);"
)
.replace(
"var css = root.getComputedStyle(element, null);",
"if (window.__POWERED_BY_WUJIE__ && element.nodeType === 9) return 'static';var css = root.getComputedStyle(element, null);"
);
return newCode;
},
},
方案五
初始点击都是正常,非固定的也是正常,
但是导航部分向下滚动后
方法六的效果
popper组件样式会丢失
滚动后的方法六 里的popper会出现固定了
子应用内打开的 popover 的弹层,点击子应用内的非自身会关闭,但是点击基座应用的菜单,不会自动关闭
我这边解决方案是,主应用监听document上的事件,传递给子应用,通过自定义插件和bus实现
import { bus } from "../index";
const simpleJsAfterLoader = (callback: Function) => {
return {
jsAfterLoaders: [
{
callback: callback as any,
},
],
};
};
// 点击子应用外,触发子应用的document的mousedown事件
const HostDocumentMouseDown = "HOST_DOCUMENT_MOUSE_DOWN";
// 监听document的mousedown事件
document.addEventListener("mousedown", event => {
let clickOutside = true;
const customElements = document.getElementsByTagName("wujie-app");
for (let i = 0; i < customElements.length; i++) {
const element = customElements[i];
if (element?.shadowRoot?.contains(event.target)) {
clickOutside = false;
break;
}
}
if (clickOutside) {
bus.$emit(HostDocumentMouseDown);
}
});
export const DocumentEventPlugin = () => simpleJsAfterLoader(appWindow => {
const mousedownEvent = new appWindow.MouseEvent("mousedown", {
bubbles: true,
cancelable: true,
button: 0, // 0 表示主鼠标按钮
});
appWindow?.$fineMicroApp?.bus?.$on(HostDocumentMouseDown, () => {
appWindow.document.body.dispatchEvent(mousedownEvent);
});
});
昨晚熬夜4个小时排查原因,以及使用最小代价实现弹框偏移解决办法:刚刚写了热乎的文章。可以参考一下。 微前端下element-ui弹框偏移问题解决 另外附上实现效果:
[  ](https://user-images.githubusercontent.com/16645035/263782970-ddd8e6b1-dc3d-4695-9be9-1a1596f60b38.gif) [ ](https://user-images.githubusercontent.com/16645035/263782970-ddd8e6b1-dc3d-4695-9be9-1a1596f60b38.gif)antd5.8的版本不生效
你这个如果是顶部有个固定导航上的下拉框和页面不是固定的下拉框会有问题啊,试过了吗
处理element-ui中子应用内打开的 popover 的弹层,点击子应用内的非自身会关闭,但是点击基座应用范围不会关闭。
解决思路修改组件库源码: src/utils/clickoutside.js(对应打包后的地址是lib/utils)。这个文件就是处理所有弹出框,点击外部关闭的指令。
!Vue.prototype.$isServer && on(document, 'mousedown', e => (startClick = e));
!Vue.prototype.$isServer && on(document, 'mouseup', e => {
nodeList.forEach(node => node[ctx].documentHandler(e, startClick));
});
// ===== 新增部分=====
if (window.__POWERED_BY_WUJIE__) {
!Vue.prototype.$isServer && on(window.parent.document, 'mousedown', e => {
// 排除子应用渲染的区域
if (e.target && e.target.nodeName === 'WUJIE-APP') return;
startClick = e;
});
!Vue.prototype.$isServer && on(window.parent.document, 'mouseup', e => {
// 排除子应用渲染的区域
if (e.target && e.target.nodeName === 'WUJIE-APP') return;
nodeList.forEach(node => node[ctx].documentHandler(e, startClick));
});
}
var root = window.parent
换成var root = window.top,符合多层嵌套场景

