Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
TheYuuu opened this issue Aug 28, 2023 · 18 comments

Comments

@TheYuuu
Copy link

TheYuuu commented Aug 28, 2023

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

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

image
@quqingfei
Copy link

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

@xjown
Copy link

xjown commented Sep 6, 2023

elmenet plus 依旧没有解决

@yiludege
Copy link
Collaborator

yiludege commented Sep 6, 2023

elmenet plus 依旧没有解决

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

@xjown
Copy link

xjown commented Sep 6, 2023

elmenet plus 依旧没有解决

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

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

@LedoTao
Copy link

LedoTao commented Sep 7, 2023

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

antd5.8的版本不生效

@zqy233
Copy link

zqy233 commented Sep 14, 2023

@quqingfei 解决了哥,666,感谢

@ShihHsing
Copy link

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

@nigiwen
Copy link

nigiwen commented Oct 23, 2023

@quqingfei vxe-modal不生效啊哥们

@kqq0825
Copy link

kqq0825 commented Nov 23, 2023

解决思路:把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];
  }

@yiludege
Copy link
Collaborator

解决思路:把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的代码可能不太一致,压缩后代码还需要自己找出来做替换了

@Maple01
Copy link

Maple01 commented Dec 8, 2023

@quqingfei 学习了,感谢

@hoganjobs
Copy link

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

这个问题有解决的吗?

@Mart0119
Copy link

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

@dun-er
Copy link

dun-er commented Jul 19, 2024

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

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

@dun-er
Copy link

dun-er commented Jul 19, 2024

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

@jianzhang810
Copy link

jianzhang810 commented Aug 20, 2024

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

@dun-er
Copy link

dun-er commented Sep 23, 2024

昨晚熬夜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的版本不生效

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

@kqq0825
Copy link

kqq0825 commented Oct 9, 2024

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests