wujie icon indicating copy to clipboard operation
wujie copied to clipboard

主应用跟子应用都用了localStorage 来记录登录的信息 同个浏览器2个标签页打开主应用 跟子应用 会被覆盖

Open TryChai opened this issue 1 year ago • 3 comments

描述bug 主应用跟子应用都用了localStorage 来记录登录的信息 同个浏览器2个标签页打开主应用 跟子应用 会被覆盖

如何复现 主应用跟子应用都用了localStorage 来记录登录的信息 同个浏览器2个标签页打开主应用 跟子应用 会被覆盖

错误截图

最小复现仓库或者地址

TryChai avatar Feb 07 '24 09:02 TryChai

wujie暂不支持,分享下我的解决方案,在主应用中修改window的localStorage事件,来给localStorage根据url设置前缀,子应用用的也是主应用的window,所以子应用不用处理

    // 隔离localstorage
    const originalSetItem = window.localStorage.setItem;
    const originalGetItem = window.localStorage.getItem;
    // 不需要添加前缀的白名单存储键
    const whiteStorage = ['core_platform_user_information'];
    window.localStorage.setItem = function (key, value) {
      originalSetItem.call(
        window.localStorage,
        // 这里加上的localStorage前缀根据自己需求修改
        whiteStorage.includes(key) ? key : window.location.pathname + '_' + key,
        value
      );
    };
    window.localStorage.getItem = function (key) {
      return originalGetItem.call(
        window.localStorage,
        whiteStorage.includes(key) ? key : window.location.pathname + '_' + key
      );
    };
    window.localStorage.clear = function () {
      for (let i = 0; i < localStorage.length; i++) {
        const key = localStorage.key(i);
        if (
          key.startsWith(window.location.pathname) ||
          whiteStorage.includes(key)
        ) {
          localStorage.removeItem(key);
        }
      }
    };

zqy233 avatar Apr 26 '24 06:04 zqy233

wujie暂不支持,分享下我的解决方案,在主应用中修改window的localStorage事件,来给localStorage根据url设置前缀,子应用用的也是主应用的window,所以子应用不用处理

// 隔离localstorage
const originalSetItem = window.localStorage.setItem;
const originalGetItem = window.localStorage.getItem;
// 不需要添加前缀的白名单存储键
const whiteStorage = ['core_platform_user_information'];
window.localStorage.setItem = function (key, value) {
  originalSetItem.call(
    window.localStorage,
    // 这里加上的localStorage前缀根据自己需求修改
    whiteStorage.includes(key) ? key : window.location.pathname + '_' + key,
    value
  );
};
window.localStorage.getItem = function (key) {
  return originalGetItem.call(
    window.localStorage,
    whiteStorage.includes(key) ? key : window.location.pathname + '_' + key
  );
};
window.localStorage.clear = function () {
  for (let i = 0; i < localStorage.length; i++) {
    const key = localStorage.key(i);
    if (
      key.startsWith(window.location.pathname) ||
      whiteStorage.includes(key)
    ) {
      localStorage.removeItem(key);
    }
  }
};

主应用上加了这段代码,子应用在调用 setItem 和 getItem 并没有触发主应用的这段代码吗。看代码应该是没有问题的,不知道是不是我那些写得不对。可以麻烦大佬贴个demo吗? 感谢感谢

KiteWorld avatar Apr 08 '25 00:04 KiteWorld

主应用上加了这段代码,子应用在调用 setItem 和 getItem 并没有触发主应用的这段代码吗。看代码应该是没有问题的,不知道是不是我那些写得不对。可以麻烦大佬贴个demo吗? 感谢感谢

不好意思,可能是我当时弄错了,这样写子应用确实不生效,通过设置plugins给子应用插入该段代码

<template>
    <WujieVue
      height="100%"
      name="vue2"
      :url="wujieUrl"
      :plugins="plugins"
      :props="{}"></WujieVue>
</template>
<script>
export default {
  data() {
    return {
      wujieUrl: window.wujieUrl,
      plugins: [
        {
          // 在子应用所有的js之前
          jsBeforeLoaders: [
            // 插入一个内联脚本,隔离localstorage
            {
              content: `const originalSetItem = window.localStorage.setItem;
    const originalGetItem = window.localStorage.getItem;
    const whiteStorage = ['core_platform_user_information'];
    window.localStorage.setItem = function (key, value) {
      originalSetItem.call(
        window.localStorage,
        whiteStorage.includes(key) ? key : window.location.pathname + '_' + key,
        value
      );
    };
    window.localStorage.getItem = function (key) {
      return originalGetItem.call(
        window.localStorage,
        whiteStorage.includes(key) ? key : window.location.pathname + '_' + key
      );
    };
    window.localStorage.clear = function () {
      for (let i = 0; i < localStorage.length; i++) {
        const key = localStorage.key(i);
        if (
          key.startsWith(window.location.pathname) ||
          whiteStorage.includes(key)
        ) {
          localStorage.removeItem(key);
        }
      }
    };`,
            },
          ],
        },
        {
          // 解决子应用使用vite时样式丢失问题
          patchElementHook(element, iframeWindow) {
            if (element.nodeName === 'STYLE') {
              element.insertAdjacentElement = function (_position, ele) {
                iframeWindow.document.head.appendChild(ele);
              };
            }
          },
        },
        {
          // 在子应用所有的css之前,为子应用插入样式
          cssBeforeLoaders: [
            // 强制使子应用body定位是relative
            { content: 'body{position: relative !important}' },
            { content: 'html{height: 100%}' },
            { content: 'body{height: 100%}' },
            { content: '#app{height: 100%}' },
          ],
        },
        {
          // 解决子应用计算偏移量错误问题
          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'
            );
          },
        },
      ],
    };
  },

};
</script>

zqy233 avatar Apr 08 '25 04:04 zqy233