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

分享-修复严格沙盒模式下子应用使用element-ui弹窗时间下拉自动关闭的bug #3000

Closed
MR-ZiWeiter opened this issue Aug 16, 2024 · 1 comment

Comments

@MR-ZiWeiter
Copy link

MR-ZiWeiter commented Aug 16, 2024

原因:由于在shadow-dom的事件传递机制不同导致的

事件捕获阶段:
事件首先从文档的根节点开始向下传播。
在 Shadow DOM 中,事件会先到达 Shadow Root 节点,然后继续向下传播到 Shadow DOM 内部的元素。

事件冒泡阶段:
事件从内部元素开始向上冒泡。
在 Shadow DOM 中,事件首先从内部元素冒泡到 Shadow Root 节点,然后再冒泡到外部 DOM 结构。

步凑
1、在子应用中将容器的container存储

mount(props) {
  document.parentContainer = props.container;
  // 其他代码 ...
}

2、将element-ui目录下node_modules/element-ui/src/utils/clickoutside.js拷贝下来到自己的目录
3、改变该文件内容

// import Vue from 'vue';
// import { on } from 'element-ui/src/utils/dom';

const nodeList = [];
const ctx = '@@clickoutsideContext';

let startClickTarget;
let seed = 0;

// !Vue.prototype.$isServer && on(document, 'mousedown', e => {
//   console.log(e);
//   startClick = e
// });

// 添加事件监听器到 Shadow DOM 的根节点
(document.parentContainer || document).addEventListener('mousedown', (event) => {
  startClickTarget = event.composedPath()[0];
}, true); // 第三个参数为 true,监听捕获阶段

// 添加事件监听器到 Shadow DOM 的根节点
(document.parentContainer || document).addEventListener('mouseup', (event) => {
  nodeList.forEach(node => node[ctx].documentHandler(event.composedPath()[0], startClickTarget));
}, true); // 第三个参数为 true,监听捕获阶段

// !Vue.prototype.$isServer && on(document.parentContainer || document, 'mouseup', e => {
//   console.log(document.parentContainer)
//   nodeList.forEach(node => node[ctx].documentHandler(e, startClick));
// });

function createDocumentHandler(el, binding, vnode) {
  return function(mouseup = {}, mousedown = {}) {
    if (!vnode ||
      !vnode.context ||
      !mouseup ||
      !mousedown ||
      el.contains(mouseup) ||
      el.contains(mousedown) ||
      el === mouseup ||
      (vnode.context.popperElm &&
      (vnode.context.popperElm.contains(mouseup) ||
      vnode.context.popperElm.contains(mousedown)))) return;

    if (binding.expression &&
      el[ctx].methodName &&
      vnode.context[el[ctx].methodName]) {
      vnode.context[el[ctx].methodName]();
    } else {
      el[ctx].bindingFn && el[ctx].bindingFn();
    }
  };
}

/**
 * v-clickoutside
 * @desc 点击元素外面才会触发的事件
 * @example
 * ```vue
 * <div v-element-clickoutside="handleClose">
 * ```
 */
export default {
  bind(el, binding, vnode) {
    console.log(el);
    nodeList.push(el);
    const id = seed++;
    el[ctx] = {
      id,
      documentHandler: createDocumentHandler(el, binding, vnode),
      methodName: binding.expression,
      bindingFn: binding.value
    };
  },

  update(el, binding, vnode) {
    el[ctx].documentHandler = createDocumentHandler(el, binding, vnode);
    el[ctx].methodName = binding.expression;
    el[ctx].bindingFn = binding.value;
  },

  unbind(el) {
    let len = nodeList.length;

    for (let i = 0; i < len; i++) {
      if (nodeList[i][ctx].id === el[ctx].id) {
        nodeList.splice(i, 1);
        break;
      }
    }
    delete el[ctx];
  }
};

4、注册该指令覆盖原有的即可

Vue.directive('clickoutside', clickoutside)
Copy link

由于缺乏足够的信息(github、stackblitz、codesandbox等可复现仓库),我们暂时关闭了该 Issue。请修改(不要回复) Issue 提供最小重现以重新开启。谢谢。如果只是单独的技术咨询,可移步 https://qiankun.umijs.org/#-community 交流~

@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Aug 16, 2024
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

1 participant