湖心雁影 發表於 2019-10-22 11:49:00

Angular实现类似vuex状态管理功能、全局数据管理与同步更新

<p>自定义实现angular中数据的状态管理,如有不妥请指正</p>
<p>一、先介绍一下rxjs中subject;</p>
<p>Subject 数据的订阅与分发,结合报刊的发布与订阅进行功能的模拟,subject即是observeable对象也是observer对象,<br>subject对于后期没有数据更新时所添加的订阅者是不怎么友好的,因为不跟新数据时订阅者就不在收到返回的数值</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">    import {subject}from’rxjs’
    const interval$ </span>= interval(1000).pipe(take(10<span style="color: rgba(0, 0, 0, 1)">));
    const subject </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Subject();

    const observerA </span>=<span style="color: rgba(0, 0, 0, 1)"> {
      next: value </span>=&gt; console.log('Observer A get value: ' +<span style="color: rgba(0, 0, 0, 1)"> value),
      error: error </span>=&gt; console.log('Observer A error: ' +<span style="color: rgba(0, 0, 0, 1)"> error),
      complete: () </span>=&gt; console.log('Observer A complete!'<span style="color: rgba(0, 0, 0, 1)">),
    };

    const observerB </span>=<span style="color: rgba(0, 0, 0, 1)"> {
      next: value </span>=&gt; console.log('Observer B get value: ' +<span style="color: rgba(0, 0, 0, 1)"> value),
      error: error </span>=&gt; console.log('Observer B error: ' +<span style="color: rgba(0, 0, 0, 1)"> error),
      complete: () </span>=&gt; console.log('Observer B complete!'<span style="color: rgba(0, 0, 0, 1)">),
    };

    subject.subscribe(observerA); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 添加观察者A</span>
    interval$.subscribe(subject); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 订阅interval$对象</span>
    setTimeout(() =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
      subject.subscribe(observerB); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 添加观察者B</span>
    }, 1000<span style="color: rgba(0, 0, 0, 1)">);

  import{BehaviorSubject}from’rxjs’;
  //<span style="color: rgba(0, 128, 0, 1)">behaviorSubject 是subject的变种,最大的区别就是 behaviorSubject是用于保存最新的数值,而不是单纯的发送事件,会将最后一次发送的值作为当前值保存在内部属性中。</span>

    const subject </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> BehaviorSubject(0);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">BehaviorSubject小括号0代表的是状态</span>
    const observerA =<span style="color: rgba(0, 0, 0, 1)"> {
      next: value </span>=&gt; console.log('Observer A get value: ' +<span style="color: rgba(0, 0, 0, 1)"> value),
      error: error </span>=&gt; console.log('Observer A error: ' +<span style="color: rgba(0, 0, 0, 1)"> error),
      complete: () </span>=&gt; console.log('Observer A complete!'<span style="color: rgba(0, 0, 0, 1)">),
    };

    const observerB </span>=<span style="color: rgba(0, 0, 0, 1)"> {
      next: value </span>=&gt; console.log('Observer B get value: ' +<span style="color: rgba(0, 0, 0, 1)"> value),
      error: error </span>=&gt; console.log('Observer B error: ' +<span style="color: rgba(0, 0, 0, 1)"> error),
      complete: () </span>=&gt; console.log('Observer B complete!'<span style="color: rgba(0, 0, 0, 1)">),
    };

    subject.subscribe(observerA); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 添加观察者A</span>
    <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> interval$.subscribe(subject); // 订阅interval$对象</span>
    subject.next(1<span style="color: rgba(0, 0, 0, 1)">);
    subject.next(</span>2<span style="color: rgba(0, 0, 0, 1)">);
    subject.next(</span>3<span style="color: rgba(0, 0, 0, 1)">);
    setTimeout(() </span>=&gt;<span style="color: rgba(0, 0, 0, 1)"> {
      subject.subscribe(observerB); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 添加观察者B</span>
    }, 1000<span style="color: rgba(0, 0, 0, 1)">);

  import {ReplaySubject}from’rxjs’;
  <span style="color: rgba(0, 128, 0, 1)">// ReplaySubject 用于重复发送最近几次的值给订阅者</span>
    const subject </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> ReplaySubject(2); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">ReplaySubject后的2为最后两次发送的数值</span>
    const observerA =<span style="color: rgba(0, 0, 0, 1)"> {
      next: value </span>=&gt; console.log('Observer A get value: ' +<span style="color: rgba(0, 0, 0, 1)"> value),
      error: error </span>=&gt; console.log('Observer A error: ' +<span style="color: rgba(0, 0, 0, 1)"> error),
      complete: () </span>=&gt; console.log('Observer A complete!'<span style="color: rgba(0, 0, 0, 1)">),
    };

    const observerB </span>=<span style="color: rgba(0, 0, 0, 1)"> {
      next: value </span>=&gt; console.log('Observer B get value: ' +<span style="color: rgba(0, 0, 0, 1)"> value),
      error: error </span>=&gt; console.log('Observer B error: ' +<span style="color: rgba(0, 0, 0, 1)"> error),
      complete: () </span>=&gt; console.log('Observer B complete!'<span style="color: rgba(0, 0, 0, 1)">),
    };

    subject.subscribe(observerA); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 添加观察者A</span>
    <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> interval$.subscribe(subject); // 订阅interval$对象</span>
    subject.next(1<span style="color: rgba(0, 0, 0, 1)">);
    subject.next(</span>2<span style="color: rgba(0, 0, 0, 1)">);
    subject.next(</span>3<span style="color: rgba(0, 0, 0, 1)">);
    setTimeout(() </span>=&gt;<span style="color: rgba(0, 0, 0, 1)"> {
      subject.subscribe(observerB); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 添加观察者B</span>
    }, 1000<span style="color: rgba(0, 0, 0, 1)">);

  import{AsyncSubject}from’rxjs’;
  <span style="color: rgba(0, 128, 0, 1)">// AsyncSubject他会在subject完成后才返回一个值</span>
    const subject </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> AsyncSubject();
    const observerA </span>=<span style="color: rgba(0, 0, 0, 1)"> {
      next: value </span>=&gt; console.log('Observer A get value: ' +<span style="color: rgba(0, 0, 0, 1)"> value),
      error: error </span>=&gt; console.log('Observer A error: ' +<span style="color: rgba(0, 0, 0, 1)"> error),
      complete: () </span>=&gt; console.log('Observer A complete!'<span style="color: rgba(0, 0, 0, 1)">),
    };

    const observerB </span>=<span style="color: rgba(0, 0, 0, 1)"> {
      next: value </span>=&gt; console.log('Observer B get value: ' +<span style="color: rgba(0, 0, 0, 1)"> value),
      error: error </span>=&gt; console.log('Observer B error: ' +<span style="color: rgba(0, 0, 0, 1)"> error),
      complete: () </span>=&gt; console.log('Observer B complete!'<span style="color: rgba(0, 0, 0, 1)">),
    };

    subject.subscribe(observerA); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 添加观察者A</span>
    <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> interval$.subscribe(subject); // 订阅interval$对象</span>
    subject.next(1<span style="color: rgba(0, 0, 0, 1)">);
    subject.next(</span>2<span style="color: rgba(0, 0, 0, 1)">);
    subject.next(</span>3<span style="color: rgba(0, 0, 0, 1)">);
    subject.complete();
    setTimeout(() </span>=&gt;<span style="color: rgba(0, 0, 0, 1)"> {
      subject.subscribe(observerB); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 添加观察者B</span>
    }, 1000);</pre>
</div>
<p>  我们要用angular实现类似vuex的全局数据管理就需要用到 <span style="color: rgba(156, 220, 254, 1); background-color: rgba(30, 30, 30, 1); font-family: Consolas, &quot;Courier New&quot;, monospace; white-space: pre">BehaviorSubject</span><span style="background-color: rgba(255, 255, 255, 1)">广播模式</span></p>
<p>二、angular服务文件</p>
<p>在app.module.ts中注册服务文件</p>
<div class="cnblogs_code">
<pre>import { SomeSharedService } from '@shared/window-service/window.service'<span style="color: rgba(0, 0, 0, 1)">;
providers: [
    ...
    SomeSharedService,
],</span></pre>
</div>
<p>&nbsp;</p>
<p>TS文件:</p>
<p>service.module.ts文件</p>
<div class="cnblogs_code">
<pre>import { NgModule, ModuleWithProviders } from '@angular/core'<span style="color: rgba(0, 0, 0, 1)">;
import { SomeSharedService } from </span>'./window.service'<span style="color: rgba(0, 0, 0, 1)">;
export { SomeSharedService };

@NgModule()
export class ServicesModule {
static forRoot(): ModuleWithProviders {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> {
      ngModule: ServicesModule,
      providers: ,
    };
}
}</span></pre>
</div>
<p>&nbsp;</p>
<p>TS服务文件名:</p>
<p class="brush:javascript;gutter:true;">window.service.ts文件</p>
<div class="cnblogs_code">
<pre>import { Injectable } from '@angular/core'<span style="color: rgba(0, 0, 0, 1)">;
import { BehaviorSubject } from </span>'rxjs'<span style="color: rgba(0, 0, 0, 1)">;
@Injectable()
export class SomeSharedService {
public globalVar: BehaviorSubject</span>&lt;any&gt; = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> BehaviorSubject({
    dataCount1: </span>0<span style="color: rgba(0, 0, 0, 1)">,
    dataCount2: </span>0<span style="color: rgba(0, 0, 0, 1)">,
    dataCount3: </span>0<span style="color: rgba(0, 0, 0, 1)">,
    dataSum: </span>0<span style="color: rgba(0, 0, 0, 1)">,
});
settingKey(key, sumKey) {
    const globalVar </span>= <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.globalVar.getValue();
    globalVar </span>-= 1<span style="color: rgba(0, 0, 0, 1)">;
    globalVar </span>-= 1<span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(255, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(255, 0, 255, 1)">.globalVar.next(globalVar);</span>
}
}</span></pre>
</div>
<p>&nbsp;</p>
<p>三、全局数据初始化</p>
<p>在全局公用组件中进行全局数据的初始化,具体怎么用看自己怎么考虑,页面刷新时数据都会重新向后台拿取数据;</p>
<div class="cnblogs_code">
<pre>ngOnInit(): <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> {
   const source </span>= timer(0, 30000<span style="color: rgba(0, 0, 0, 1)">);
   const data </span>=<span style="color: rgba(0, 0, 0, 1)"> source.pipe(
       mergeMap(val </span>=&gt;<span style="color: rgba(0, 0, 0, 1)"> {
         </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">this</span>.http.get('/admin'<span style="color: rgba(0, 0, 0, 1)">);
       }),
       distinctUntilChanged(),
   );
   </span><span style="color: rgba(0, 0, 255, 1)">this</span>.distinctSub = data.subscribe(res =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
       </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.someSharedService$.globalVar.next(res.data);
      });
}

ngOnDestroy(): </span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> {
   </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.distinctSub.unsubscribe();
   }</span></pre>
</div>
<p>因为业务需要 定时向后台请求一次数据更新,所以简单写了一下 ,如果不需要就只要放一个http请求就行了;</p>
<p>使用&nbsp;<span style="color: rgba(212, 212, 212, 1); font-family: Consolas, &quot;Courier New&quot;, monospace; white-space: pre; background-color: rgba(30, 30, 30, 1)">&nbsp;</span><span style="font-family: Consolas, &quot;Courier New&quot;, monospace; white-space: pre; background-color: rgba(30, 30, 30, 1); color: rgba(86, 156, 214, 1)">this</span><span style="color: rgba(212, 212, 212, 1); font-family: Consolas, &quot;Courier New&quot;, monospace; white-space: pre; background-color: rgba(30, 30, 30, 1)">.</span><span style="font-family: Consolas, &quot;Courier New&quot;, monospace; white-space: pre; background-color: rgba(30, 30, 30, 1); color: rgba(156, 220, 254, 1)">someSharedService$</span><span style="color: rgba(212, 212, 212, 1); font-family: Consolas, &quot;Courier New&quot;, monospace; white-space: pre; background-color: rgba(30, 30, 30, 1)">.</span><span style="font-family: Consolas, &quot;Courier New&quot;, monospace; white-space: pre; background-color: rgba(30, 30, 30, 1); color: rgba(156, 220, 254, 1)">globalVar</span><span style="color: rgba(212, 212, 212, 1); font-family: Consolas, &quot;Courier New&quot;, monospace; white-space: pre; background-color: rgba(30, 30, 30, 1)">.</span><span style="font-family: Consolas, &quot;Courier New&quot;, monospace; white-space: pre; background-color: rgba(30, 30, 30, 1); color: rgba(220, 220, 170, 1)">next</span><span style="color: rgba(212, 212, 212, 1); font-family: Consolas, &quot;Courier New&quot;, monospace; white-space: pre; background-color: rgba(30, 30, 30, 1)">(</span><span style="font-family: Consolas, &quot;Courier New&quot;, monospace; white-space: pre; background-color: rgba(30, 30, 30, 1); color: rgba(156, 220, 254, 1)">res</span><span style="color: rgba(212, 212, 212, 1); font-family: Consolas, &quot;Courier New&quot;, monospace; white-space: pre; background-color: rgba(30, 30, 30, 1)">.</span><span style="font-family: Consolas, &quot;Courier New&quot;, monospace; white-space: pre; background-color: rgba(30, 30, 30, 1); color: rgba(156, 220, 254, 1)">data</span><span style="color: rgba(212, 212, 212, 1); font-family: Consolas, &quot;Courier New&quot;, monospace; white-space: pre; background-color: rgba(30, 30, 30, 1)">); </span>从全局服务<span style="color: rgba(156, 220, 254, 1); background-color: rgba(30, 30, 30, 1); font-family: Consolas, &quot;Courier New&quot;, monospace; white-space: pre">SomeSharedService</span>文件中分发文件;</p>
<p>四、订阅服务数据</p>
<p>在需要的页面订阅分发内容,且会保存最后一次的数据;</p>
<div class="cnblogs_code">
<pre>import { SomeSharedService } from '@shared/window-service/window.service'<span style="color: rgba(0, 0, 0, 1)">;
constructor(
  private someSharedService$: SomeSharedService,
   ) {}

...

</span><span style="color: rgba(0, 0, 255, 1)">this</span>.someSharedService.globalVar.subscribe(res =&gt;<span style="color: rgba(0, 0, 0, 1)"> {

      </span><span style="color: rgba(0, 0, 255, 1)">if</span> (!(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.cdr as ViewRef).destroyed) {
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.item =<span style="color: rgba(0, 0, 0, 1)"> res;
      </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.cdr.detectChanges();
       }
   });<br><span style="color: rgba(0, 128, 0, 1)">// 因为有一些数据渲染的问题 所以需要加一层判断,这就基本实现了从后台拿取数据,在多个页面进行展示;</span><br></span></pre>
</div>
<p>五、实现数据修改及同步更新</p>
<div class="cnblogs_code">
<pre>import { SomeSharedService } from '@shared/window-service/window.service'<span style="color: rgba(0, 0, 0, 1)">;
constructor(
  private someSharedService$: SomeSharedService,
) {}
...

</span><span style="color: rgba(0, 0, 255, 1)">this</span>.http.get(xxx).subscribe(res =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
      </span><span style="color: rgba(0, 0, 255, 1)">if</span> (res.code !== 200<span style="color: rgba(0, 0, 0, 1)">) {
          </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.msg.error(res.message);
          </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
      }
  </span><span style="color: rgba(0, 0, 255, 1)">this</span>.someSharedService$.settingKey('dataCount1', 'dataSum'<span style="color: rgba(0, 0, 0, 1)">);
})</span></pre>
</div>
<p>当完成数据请求、更新后,修改广播中心的数据,之后同步给接收者一份最新的数据,从而达到广播的的效果;</p>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/bomdeyada/p/11718943.html
頁: [1]
查看完整版本: Angular实现类似vuex状态管理功能、全局数据管理与同步更新