【问题标题】:Listen for changes with localStorage on the same window在同一个窗口中使用 localStorage 监听变化
【发布时间】:2015-01-14 10:43:56
【问题描述】:

我想在同一页面上监听 localStorage API 中发生的更改(而不是像规范所说的那样在多个选项卡中)。

我目前正在使用此代码:

var storageHandler = function () {
    alert('storage event 1');
  };

  window.addEventListener("storage", storageHandler, false);

localStorage.setItem('foo', 'bar');

有谁知道一种原生的 JavaScript 方法来在一页上监听 localStorage 上的事件(没有 jQuery)

【问题讨论】:

    标签: javascript events local-storage


    【解决方案1】:

    由于 JS 是动态语言,只需重写原始函数即可。

    var originalSetItem = localStorage.setItem; 
    localStorage.setItem = function(){
        document.createEvent('Event').initEvent('itemInserted', true, true);
        originalSetItem.apply(this, arguments);
    }
    

    【讨论】:

    • 为 JavaScript 和重写原始函数万岁!
    • @f.lorenzo,没错,但也许留下来思考为什么 W3C 合作者决定将事件仅用于不同页面是一个好点。
    • 如果同一事件传播到所有窗口,包括setting 窗口,就会出现问题。在这里,您介绍了一种独特的事件类型,可以避免很多问题
    • 如果您在一个组件中设置值并想从另一个组件中收听呢?
    • 请注意,如果 localStorage 设置为数组、localStorage["foo"]="bar"localStorage.foo="bar",这将不起作用
    【解决方案2】:

    更新了上面的答案,因为 document.createEvent 现在是旧的、已弃用的 API 的一部分。

    const originalSetItem = localStorage.setItem;
    
    localStorage.setItem = function(key, value) {
      const event = new Event('itemInserted');
    
      event.value = value; // Optional..
      event.key = key; // Optional..
    
      document.dispatchEvent(event);
    
      originalSetItem.apply(this, arguments);
    };
    
    const localStorageSetHandler = function(e) {
      alert('localStorage.set("' + e.key + '", "' + e.value + '") was called');
    };
    
    document.addEventListener("itemInserted", localStorageSetHandler, false);
    
    localStorage.setItem('foo', 'bar'); // Pops an alert
    

    https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events

    【讨论】:

    • 这个策略在 Firefox 中似乎不起作用。至少在 61.0.1 版本中没有。也许您不允许在 Firefox 中覆盖本机函数?很难说,因为我无法在 Firefox 控制台中检查该功能。
    • 嗯,这很不幸。不知道为什么。但是您总是可以编写一个自定义函数并调用它,而不是直接使用和修改 localStorage.setItem。
    • 这就是我最终所做的。
    • @BrandonFranklin - 是的,您可以将属性分配给您创建的 Event 对象,我已将其添加到示例中。我选择了“值”和“键”作为属性名称,但您可以选择任何您喜欢的名称。
    • @Devops-Paddy - 是的!我更新了示例以展示如何将道具添加到 Event 对象。
    【解决方案3】:

    这个问题的答案对我不起作用。我得到了Uncaught TypeError: Illegal invocation,所以我编写了自己的代码,该代码适用于大多数环境。它使用Proxy,更安全。

    Storage.prototype.setItem = new Proxy(Storage.prototype.setItem, {
        apply(target, thisArg, argumentList) {
            const event = new CustomEvent('localstorage', {
                detail: {
                    key: argumentList[0],
                    oldValue: thisArg.getItem(argumentList[0]),
                    newValue: argumentList[1],
                },
            });
            window.dispatchEvent(event);
            return Reflect.apply(target, thisArg, argumentList);
        },
    });
    
    Storage.prototype.removeItem = new Proxy(Storage.prototype.removeItem, {
        apply(target, thisArg, argumentList) {
            const event = new CustomEvent('localstorage', {
                detail: {
                    key: argumentList[0],
                },
            });
            window.dispatchEvent(event);
            return Reflect.apply(target, thisArg, argumentList);
        },
    });
    
    Storage.prototype.clear = new Proxy(Storage.prototype.clear, {
        apply(target, thisArg, argumentList) {
            const event = new CustomEvent('localstorage', {
                detail: {
                    key: '__all__',
                },
            });
            window.dispatchEvent(event);
            return Reflect.apply(target, thisArg, argumentList);
        },
    });
    

    【讨论】:

    猜你喜欢
    • 2013-04-18
    • 2011-08-17
    • 2022-10-05
    • 2019-11-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-13
    • 2018-06-15
    • 1970-01-01
    相关资源
    最近更新 更多