何大哥 發表於 2019-11-1 14:17:00

使用 Angular RouteReuseStrategy 缓存(路由)组件

<h1 id="使用-angular-routereusestrategy-缓存组件">使用 Angular RouteReuseStrategy 缓存组件</h1>
<h2 id="cache-components-with-angular-routereusestrategy">Cache components with Angular RouteReuseStrategy</h2>
<p>RouteReuseStrategy provider 允许我们控制 Angular 路由和组件生命周期的行为。</p>
<p>当我们在组件间切换的时候,Angular都会销毁上一个组件,并且创建一个新的组件。在大多数情况下,我们可能不想让它这样工作,因为每次加载一个组件,可能会有很多类似HTTP请求一样的昂贵的操作。</p>
<p>这时候就需要RouteReuseStrategy了。</p>
<h3 id="routereusestrategy是什么">RouteReuseStrategy是什么</h3>
<p>RouteReuseStrategy接口声明了5个方法。</p>
<h4 id="shouldreuseroute">shouldReuseRoute</h4>
<p>这个方法每次切换路由时都会被调用。<code>future</code>参数是将要离开的路由,<code>curr</code>参数是将要加载的路由。如果这个方法返回<code>true</code>,路由将不会跳转(意味着路由没有发生变化)。如果它返回<code>false</code>,则路由发生变化并且其余方法会被调用。</p>
<pre><code class="language-typescript">shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
    // 默认行为
    return future.routeConfig === curr.routeConfig;
}
</code></pre>
<h4 id="shouldattach">shouldAttach</h4>
<p>路由刚刚被打开,当我们加载到这个路由的组件上时,<code>shouldAttach</code>会被调用。一旦组件被加载这个方法都会被调用。如果这个方法返回<code>true</code>,<code>retrieve</code>方法将会被调用。否则这个组件将会被重新创建。</p>
<pre><code class="language-typescript">shouldAttach(route: ActivatedRouteSnapshot): boolean;
</code></pre>
<h4 id="retrieve">retrieve</h4>
<p>当<code>shouldAttach</code>方法返回<code>true</code>时这个方法会被调用。提供当前路由的参数(刚打开的路由),并且返回一个缓存的<code>RouteHandle</code>。如果返回<code>null</code>表示没有效果。我们可以使用这个方法手动获取任何已被缓存的<code>RouteHandle</code>。框架不会自动管理它,需要我们手动实现。</p>
<pre><code class="language-typescript">retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null;
</code></pre>
<h4 id="shoulddetach">shouldDetach</h4>
<p>当离开当前路由时这个方法会被调用。如果返回<code>true</code>,<code>store</code>方法会被调用。</p>
<pre><code class="language-typescript">shouldDetach(route: ActivatedRouteSnapshot): boolean;
</code></pre>
<h4 id="store">store</h4>
<p>这个方法当且仅当<code>shouldDetach</code>方法返回<code>true</code>时被调用。我们可以在这里具体实现如何缓存<code>RouteHandle</code>。在这个方法中缓存的内容将会被用在<code>retrieve</code>方法中。它提供了我们离开的路由和<code>RouteHandle</code>。</p>
<pre><code class="language-typescript">store(route: ActivatedRouteSnapshot, detachedTree: DetachedRouteHandle): void;
</code></pre>
<h3 id="示例">示例</h3>
<p><code>src/services/route-strategy.service.ts</code>:</p>
<pre><code class="language-typescript">
import&nbsp;{&nbsp;RouteReuseStrategy,&nbsp;DetachedRouteHandle,&nbsp;ActivatedRouteSnapshot&nbsp;}&nbsp;from&nbsp;'@angular/router';
export&nbsp;class&nbsp;RouteStrategyService&nbsp;implements&nbsp;RouteReuseStrategy&nbsp;{
&nbsp;&nbsp;public&nbsp;static&nbsp;handlers:&nbsp;{&nbsp;:&nbsp;DetachedRouteHandle&nbsp;}&nbsp;=&nbsp;{};
&nbsp;&nbsp;public&nbsp;static&nbsp;deleteRouteSnapshot(path:&nbsp;string):&nbsp;void&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;name&nbsp;=&nbsp;path.replace(/\//g,&nbsp;'_');
&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(RouteStrategyService.handlers)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;RouteStrategyService.handlers;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;}
&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;*&nbsp;判断当前路由是否需要缓存
&nbsp;&nbsp;&nbsp;*&nbsp;这个方法返回false时则路由发生变化并且其余方法会被调用
&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;{ActivatedRouteSnapshot}&nbsp;future
&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;{ActivatedRouteSnapshot}&nbsp;curr
&nbsp;&nbsp;&nbsp;*&nbsp;@returns&nbsp;{boolean}
&nbsp;&nbsp;&nbsp;*&nbsp;@memberof&nbsp;CacheRouteReuseStrategy
&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;public&nbsp;shouldReuseRoute(future:&nbsp;ActivatedRouteSnapshot,&nbsp;curr:&nbsp;ActivatedRouteSnapshot):&nbsp;boolean&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;future.routeConfig&nbsp;===&nbsp;curr.routeConfig
&nbsp;&nbsp;&nbsp;&nbsp;&amp;&amp;&nbsp;JSON.stringify(future.params)&nbsp;===&nbsp;JSON.stringify(curr.params);
&nbsp;&nbsp;}
&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;*&nbsp;当离开当前路由时这个方法会被调用
&nbsp;&nbsp;&nbsp;*&nbsp;如果返回&nbsp;true&nbsp;则&nbsp;store&nbsp;方法会被调用
&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;{ActivatedRouteSnapshot}&nbsp;route
&nbsp;&nbsp;&nbsp;*&nbsp;@returns&nbsp;{boolean}
&nbsp;&nbsp;&nbsp;*&nbsp;@memberof&nbsp;CacheRouteReuseStrategy
&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;public&nbsp;shouldDetach(route:&nbsp;ActivatedRouteSnapshot):&nbsp;boolean&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;true;
&nbsp;&nbsp;}
&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;*&nbsp;将路由写入缓存
&nbsp;&nbsp;&nbsp;*&nbsp;在这里具体实现如何缓存&nbsp;RouteHandle
&nbsp;&nbsp;&nbsp;*&nbsp;提供了我们离开的路由和&nbsp;RouteHandle
&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;{ActivatedRouteSnapshot}&nbsp;route
&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;{DetachedRouteHandle}&nbsp;detachedTree
&nbsp;&nbsp;&nbsp;*&nbsp;@memberof&nbsp;CacheRouteReuseStrategy
&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;public&nbsp;store(route:&nbsp;ActivatedRouteSnapshot,&nbsp;detachedTree:&nbsp;DetachedRouteHandle):&nbsp;void&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;RouteStrategyService.handlers&nbsp;=&nbsp;detachedTree;
&nbsp;&nbsp;}
&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;*&nbsp;路由被导航&nbsp;如果此方法返回&nbsp;true&nbsp;则触发&nbsp;retrieve&nbsp;方法
&nbsp;&nbsp;&nbsp;*&nbsp;如果返回&nbsp;false&nbsp;这个组件将会被重新创建
&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;{ActivatedRouteSnapshot}&nbsp;route
&nbsp;&nbsp;&nbsp;*&nbsp;@returns&nbsp;{boolean}
&nbsp;&nbsp;&nbsp;*&nbsp;@memberof&nbsp;CacheRouteReuseStrategy
&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;public&nbsp;shouldAttach(route:&nbsp;ActivatedRouteSnapshot):&nbsp;boolean&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;!!RouteStrategyService.handlers;
&nbsp;&nbsp;}
&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;*&nbsp;从缓存读取cached&nbsp;route
&nbsp;&nbsp;&nbsp;*&nbsp;提供当前路由的参数(刚打开的路由),并且返回一个缓存的&nbsp;RouteHandle
&nbsp;&nbsp;&nbsp;*&nbsp;可以使用这个方法手动获取任何已被缓存的&nbsp;RouteHandle
&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;{ActivatedRouteSnapshot}&nbsp;route
&nbsp;&nbsp;&nbsp;*&nbsp;@returns&nbsp;{(DetachedRouteHandle&nbsp;|&nbsp;null)}
&nbsp;&nbsp;&nbsp;*&nbsp;@memberof&nbsp;CacheRouteReuseStrategy
&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;public&nbsp;retrieve(route:&nbsp;ActivatedRouteSnapshot):&nbsp;DetachedRouteHandle&nbsp;|&nbsp;null&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;RouteStrategyService.handlers&nbsp;||&nbsp;null;
&nbsp;&nbsp;}
&nbsp;&nbsp;private&nbsp;getPath(route:&nbsp;ActivatedRouteSnapshot):&nbsp;string&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;tslint:disable-next-line:&nbsp;no-string-literal
&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;path&nbsp;=&nbsp;route['_routerState'].url.replace(/\//g,&nbsp;'_');
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;path;
&nbsp;&nbsp;}
}
</code></pre>
<p><code>src/app/app.module.ts</code>:</p>
<pre><code class="language-typescript">import&nbsp;{&nbsp;RouteReuseStrategy&nbsp;}&nbsp;from&nbsp;'@angular/router';
import&nbsp;{&nbsp;RouteStrategyService&nbsp;}&nbsp;from&nbsp;'../services/route-strategy.service';

@NgModule({
&nbsp;&nbsp;&nbsp;&nbsp;...
&nbsp;&nbsp;&nbsp;&nbsp;providers:&nbsp;[
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;provide:&nbsp;RouteReuseStrategy,&nbsp;useClass:&nbsp;RouteStrategyService&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;],
&nbsp;&nbsp;&nbsp;&nbsp;bootstrap:&nbsp;
})
export&nbsp;class&nbsp;AppModule&nbsp;{&nbsp;}
</code></pre>
<p>以上示例运行时会缓存所有路由组件。<br>
实现比如标签页效果时,关闭标签页,调用<code>RouteStrategyService</code>中的<code>deleteRouteSnapshot</code>方法删除已缓存的页面即可。</p>
<p><em>这里可能会有个问题,如果你不想用这个路由缓存了,请务必删除掉<code>app.module.ts</code>中的<code>providers</code>,而不是将<code>RouteStrategyService</code>的<code>shouldReuseRoute</code>始终<code>return true</code>;这样会出现路由跳转页面不跳转的问题,原因暂时未知。</em></p>
<p>以下是运行效果图:</p>
<p><img src="https://img2018.cnblogs.com/blog/1012606/201911/1012606-20191101141555875-1052021241.gif"></p>
<blockquote>
<p>The end...<br>
Last updated by Jehorn, 11/1/2019</p>
</blockquote><br><br>
来源:https://www.cnblogs.com/jimmyguu/p/11776730.html
頁: [1]
查看完整版本: 使用 Angular RouteReuseStrategy 缓存(路由)组件