前言

目前出现了一个需求,需要父页面打开新的子页面,子页面提交表单之后,关闭子页面,然后把数据返回给父页面。
本来考虑使用sharedWorker,但是由于兼容性太差了,就弃用了。看到网上的介绍可以使用localStorage来实现,我就尝试了下。下面是一些具体的细节。

开始

整体流程如图所示:
在这里插入图片描述

需求分析

  1. 子页面需要知道自己的父页面对应的是谁,所以父页面打开子页面的时候需要传输一个父页面的KEY
  2. 由于表单是使用dialog来显示,需要注意避免出现事件重复注册的,及时销毁事件,保留监听事件的唯一。
  3. 由于保存的时候只会出现单一数据变化,所以只需要维护同一个localStorage对象即可。
  4. 父页面接受数据的时候,也需要校验子页面传输的数据是否属于自己。
  5. 最终的数据是否关联成功,由父页面的保存决定,子页面的数据是无状态的。

实现原理

localStorage中支持监听storage变化时的事件,并且只有在不同标签页面,同源网页的时候才会触发,这里恰好解决的我们的需求:
window.addEventListener('storage', callback);

代码实现

由于localStorage的API比较简单, 所以这里就不在这里介绍。
为了后续的拓展和方便调用,我这里就将localStorage一些操作做了简单的封装。

function generateUUID() {
  let d = new Date().getTime();
  if (window.performance && typeof window.performance.now === 'function') {
    d += performance.now(); // use high-precision timer if available
  }
  const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
    // eslint-disable-next-line no-bitwise
    const r = (d + Math.random() * 16) % 16 | 0;
    d = Math.floor(d / 16);
    // eslint-disable-next-line no-bitwise
    return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16);
  });
  return uuid;
}
export function initStorage(callback) {
  window.addEventListener('storage', callback);
}
export function removeStorage(callback) {
  window.removeEventListener('storage', callback);
}
export function setItem(key, value) {
  localStorage.setItem(
    key,
    JSON.stringify({
      storageId: generateUUID(),
      value,
    }),
  );
}
export function removeItem(key) {
  localStorage.removeItem(key);
}
export function getItem(key, remove = false) {
  try {
    const item = JSON.parse(localStorage.getItem(key));
    if (remove) {
      localStorage.removeItem(key);
    }
    return item;
  } catch (e) {
    const item = localStorage.getItem(key);
    if (remove) {
      localStorage.removeItem(key);
    }
    return item;
  }
}

由于很多时候我们进行VUE渲染的时候,需要获取到唯一的key值,我这里给每一次的设置添加了唯一的KEY值;除此之外,还有一个很关键的原因:

  1. 由于storage保存的数据都是字符串,监听事件的触发只有在跨页面值发生变化同源网站的时候触发的。
    我们打开2个页面,在页面加载完成之后,添加监听事件。
    在这里插入图片描述
    我们测试的时候可以在浏览器的控制台来修改localStorage
    在这里插入图片描述
    我们看看另外一个页面的控制台
    在这里插入图片描述
    这里事件监听的会把所有的数据传给你,连之前的旧值也可以获取到。
    在测试的时候,如果我们重复保存相同的值的时候,监听事件只能触发一次。
    在这里插入图片描述
    另外一个页面的控制台:
    在这里插入图片描述
    只输出了一次。

所以,我们在自己封装的API的时候,不用担心是否会出现相同的值触发不了的情况,因为我们每一次调用setItem的时候都会生成一个唯一随机不重复的KEY,这样就可以保证每次都能触发到。

事件的销毁

在页面或者dialog销毁的时候,记得要注销掉storage的事件,因为你绑定在window上,除了完全关闭页面之外,你的事件一定会一直存在的,并且在你第N次进入的时候,你就会发现监听事件会重复触发N次,因为你在window添加了N次相同的事件。

如果你在mounted上进行添加的话,你就要在destroed事件进行销毁,如果你在弹出框显示的时候进行注册,你就需要在弹出框消失的时候注销掉这个事件。

父页面传值给子页面

这里我使用的是vue-router来实现的,因为vue-router支持路由传值,我们只需要在路由上添加我们需要传的值即可。其实原理还是通过window.href来获取父页面的数据。
vue-router配置方法:

[
    {
      name: 'home',
      path: 'home',
      meta: {
        type: '父页面',
      },
      component: () => import('./home/index'),
    },
    {
      name: 'alignmentEditIssue',
      path: 'alignmentEditIssue/:id/:issueId',
      meta: {
        type: '子页面',
      },
      component: () => import('./alignmentEditIssue/index'),
    },

];
	const misionId = '123456'
	const issueId = '563555'
  	window.open(`#/alignmentEditIssue/${misionId}/${issueId}`);

总结

storage的兼容性基本全部平台的都支持了,除了使用storage的方法之外,还可以使用websoket,但是这个还需要在服务器进行管理,对于我们这个需求而言有点浪费,因为这里并不需要跨浏览器、跨用户通信。

Logo

前往低代码交流专区

更多推荐