使用 Angular Observable 订阅 Session Storage key

Using Angular Observable to subscribe to Session Storage key

我正在尝试完成我希望的简单“查看会话存储中的密钥并在它发生变化时更新它”的场景,但 Observables 真的让我失望。

message$ = new Observable(observer => {
    observer.next(window.sessionStorage.getItem('message'));
});
    
ngOnInit() {
    this.message$.subscribe();
}

并且消息 $ 绑定到 HTML,非常简单:

<p id="message">{{message$ | async}}</p>

如果 'message' 中已经存储了值,那么 Observable 会将文本输出到 HTML,但是如果在 init 上没有消息然后它被添加,或者消息值确实存在并已更新,没有任何反应。我显然做错了什么,我很感激 Observables.

知识渊博的人的见解

因为你使用的是异步管道,所以你不需要在你的组件中订阅,你可以把它去掉。 AsyncPipe 将在幕后处理订阅/取消订阅。

尝试改用主题。

// This is what will help you broadcast your message and push updates to subscribers.
message$ = new Subject();

// Anytime the "message" changes, you'll want to call this.
updateTheSubject() {
    this.message$.next(window.sessionStorage.getItem('message'));
}

您的 html 模板可以保持不变。

https://rxjs-dev.firebaseapp.com/guide/subject

https://angular.io/api/common/AsyncPipe

我想你要找的是 StorageEvent

您可以使用 fromEvent 从该事件创建您的可观察对象,如下所示:

const message$ = fromEvent<StorageEvent>(window, "storage").pipe(
  filter(event => event.storageArea === sessionStorage),
  filter(event => event.key === "message"),
  map(event => event.newValue)
);

请注意,我添加了过滤器以专门查找 sessionStorage 的更新,并且我指定了密钥 === "message",但您也可以使用 localStorage 和任何您想要的密钥

此外,与 一样,如果您打算仅在模板中使用它,则无需订阅此 observable。

已编辑: 上述解决方案仅在您打开多个选项卡并希望同步存储更改时有效。检查 this answer

我认为你必须改变一个地方,你将你的值设置为sessionStorage。我的建议是使用您自己的 StorageService (my example),您可以在其中将您的值设置为存储并保留一个可观察对象,它应该在您设置 key/value.

时发出

我做了一个example on stackblitz

https://stackblitz.com/edit/angular-3szmzd

这个帖子有点旧,但我刚遇到同样的问题。

正如@quake 所指出的,在同一 window.

内的更改不会引发 storageEvent

要实现所需的“设置拦截”,您必须修补 localSorage 或 sessionStorage 的存储功能。例如:

   // somewhere in a Class...

  private setStorageItemFunc: (key: string, value: string) => void;
  private getStorageItemFunc: (key: string) => string;
  private subject$: Subject<string>;

  applySettingsInterception() {
    // define a Subject
    this.subject$ = new Subject();

    // just for demonstation purposes. Don't subscribe to the subject, use async pipe instead
    this.subject$.subscribe(e => {
      console.log('value changed', e);
    });

    // save original functions
    this.setStorageItemFunc = window.localStorage.setItem;
    this.getStorageItemFunc = window.localStorage.getItem;

    // set storage functions to the newly created interceptor functions
    // bind to this to get access to the current object and it's values in interceptor function
    window.localStorage.setItem = this.setStorageItem.bind(this);
    window.localStorage.getItem = this.getStorageItem.bind(this);
  }

  private setStorageItem(key: string, value: string): void {
    console.log('setStorageItem', key, value);

    this.subject$.next(`${key}: ${value}`);

    this.setStorageItemFunc.call(localStorage, key, value);
  }

  private getStorageItem(key: string): string {
    const value = this.getStorageItemFunc.call(localStorage, key);

    console.log('getStorageItem', key, value);

    return value;
  }

如您所见,在截获的函数中,您可以调用@damian-c.

提到的Subject的next()函数