wujie icon indicating copy to clipboard operation
wujie copied to clipboard

【方案讨论】针对el中依赖了poper.js 的fixed定位偏移解决方案

Open TheYuuu opened this issue 2 years ago • 19 comments

我这边是fork的qiankun自己在团队内增加特性功能,最近参考(缝)了wujie的一些方案后,也遇到了poper fixed定位偏移问题

解决思路如下,对body的append进行劫持,判断className是否有el-popper,有的话用MutationObserver监听style属性,有变化就把fixed改成abs,再处理好隐藏和删除逻辑,目前运行没有什么问题。

image

TheYuuu avatar Aug 28 '23 04:08 TheYuuu

昨晚熬夜4个小时排查原因,以及使用最小代价实现弹框偏移解决办法:刚刚写了热乎的文章。可以参考一下。 微前端下element-ui弹框偏移问题解决 另外附上实现效果: GIF

quqingfei avatar Aug 28 '23 17:08 quqingfei

elmenet plus 依旧没有解决

xjown avatar Sep 06 '23 09:09 xjown

elmenet plus 依旧没有解决

将popper定位强制改成绝对定位可以解决吗 image

yiludege avatar Sep 06 '23 09:09 yiludege

elmenet plus 依旧没有解决

将popper定位强制改成绝对定位可以解决吗 image

这样可以诶。。。。。谢谢

xjown avatar Sep 06 '23 09:09 xjown

昨晚熬夜4个小时排查原因,以及使用最小代价实现弹框偏移解决办法:刚刚写了热乎的文章。可以参考一下。 微前端下element-ui弹框偏移问题解决 另外附上实现效果: GIF

antd5.8的版本不生效

LedoTao avatar Sep 07 '23 08:09 LedoTao

@quqingfei 解决了哥,666,感谢

zqy233 avatar Sep 14 '23 07:09 zqy233

子应用内打开的 popover 的弹层,点击子应用内的非自身会关闭,但是点击基座应用的菜单,不会自动关闭

ShihHsing avatar Oct 16 '23 06:10 ShihHsing

@quqingfei vxe-modal不生效啊哥们

nigiwen avatar Oct 23 '23 03:10 nigiwen

解决思路:把popper的dom直接塞进主应用的body中,判断定位和显示边界也直接以主应用作为左边起点,这样的效果就和正常在项目中使用appendToBody的效果一致,代码改动也非常的少。

因为公司内部使用的组件库是基于element-ui进行封装的,所以直接在源码上进行更改了。 如果不能直接修改element-ui的源码,明确修改代码位置后,可以使用js-loader或者项目build之前修改node_modules代码。 以下代码目录都是基于element-ui源码的目录,对应在node_modules中的地址是lib/utilssrc/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];
  }

kqq0825 avatar Nov 23 '23 12:11 kqq0825

解决思路:把popper的dom直接塞进主应用的body中,判断定位和显示边界也直接以主应用作为左边起点,这样的效果就和正常在项目中使用appendToBody的效果一致,代码改动也非常的少。

因为公司内部使用的组件库是基于element-ui进行封装的,所以直接在源码上进行更改了。 如果不能直接修改element-ui的源码,明确修改代码位置后,可以使用js-loader或者项目build之前修改node_modules代码。 以下代码目录都是基于element-ui源码的目录,对应在node_modules中的地址是lib/utilssrc/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的代码可能不太一致,压缩后代码还需要自己找出来做替换了

yiludege avatar Nov 24 '23 07:11 yiludege

@quqingfei 学习了,感谢

Maple01 avatar Dec 08 '23 03:12 Maple01

子应用内打开的 popover 的弹层,点击子应用内的非自身会关闭,但是点击基座应用的菜单,不会自动关闭

这个问题有解决的吗?

hoganjobs avatar Mar 12 '24 10:03 hoganjobs

.el-popper, .el-tooltip__popper { position: absolute !important; } 可以解决 子应用 弹出层&tooltip 定位问题

Mart0119 avatar Apr 25 '24 10:04 Mart0119

昨晚熬夜4个小时排查原因,以及使用最小代价实现弹框偏移解决办法:刚刚写了热乎的文章。可以参考一下。 微前端下element-ui弹框偏移问题解决 另外附上实现效果: GIF GIF

我用的也是官方实例,然后加了一个固定顶部的导航,向下滚动后popper计算定位会出现向下偏差

dun-er avatar Jul 19 '24 02:07 dun-er

我用的是官方实例,然后加了一个固定顶部的导航,用的方法五,向下滚动后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;
      },
    },

方案五

初始点击都是正常,非固定的也是正常, image-20240719134646357

但是导航部分向下滚动后 image-20240719134753207

方法六的效果

popper组件样式会丢失 image-20240719134413864

滚动后的方法六 里的popper会出现固定了 image-20240719134523570

dun-er avatar Jul 19 '24 06:07 dun-er

子应用内打开的 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);
    });
});

jianzhang810 avatar Aug 20 '24 03:08 jianzhang810

昨晚熬夜4个小时排查原因,以及使用最小代价实现弹框偏移解决办法:刚刚写了热乎的文章。可以参考一下。 微前端下element-ui弹框偏移问题解决 另外附上实现效果: GIF

    [
      
    
        ![GIF](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)
    
    
      
        
          
        
        
          
          
        
      
      [
        
          
        
      ](https://user-images.githubusercontent.com/16645035/263782970-ddd8e6b1-dc3d-4695-9be9-1a1596f60b38.gif)

antd5.8的版本不生效

你这个如果是顶部有个固定导航上的下拉框和页面不是固定的下拉框会有问题啊,试过了吗

dun-er avatar Sep 23 '24 02:09 dun-er

处理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));
  });
}

kqq0825 avatar Oct 09 '24 09:10 kqq0825

var root = window.parent

换成var root = window.top,符合多层嵌套场景

raoenhui avatar Mar 27 '25 06:03 raoenhui