diff --git a/packages/abc/reuse-tab/index.en-US.md b/packages/abc/reuse-tab/index.en-US.md index 044c5b40f5..07a0eaaa44 100644 --- a/packages/abc/reuse-tab/index.en-US.md +++ b/packages/abc/reuse-tab/index.en-US.md @@ -5,6 +5,7 @@ title: reuse-tab subtitle: Reuse Route Tab cols: 1 module: import { ReuseTabModule } from '@delon/abc/reuse-tab'; +standalone: true --- Reuse route tab are extremely common for admin interfaces, and the problem of component data is not lost when switching routes. @@ -13,51 +14,20 @@ The newly opened is always the current page, and the route reuse means that when ## Usage -The default `ReuseTabModule` does not register `RouteReuseStrategy`. If you need route reuse, the first step is to register it: +1. Provide `provideReuseTabConfig()` configuration in `app.config.ts` file +2. Add `` in the `src/app/layout/basic/basic.component.ts` file, like this: -**Register** - -> How to use in ng-alain, pls refer to [global-config.module.ts](https://github.com/ng-alain/ng-alain/blob/master/src/app/global-config.module.ts#L32). - -```ts -// global-config.module.ts -import { RouteReuseStrategy } from '@angular/router'; -import { ReuseTabService, ReuseTabStrategy } from '@delon/abc/reuse-tab'; -alainProvides.push({ - provide: RouteReuseStrategy, - useClass: ReuseTabStrategy, - deps: [ReuseTabService], -} as any); -``` - -**Add Component** - -> In `src/app/layout/basic/basic.component.ts` - -```html - - +```diff +- ++ ++ ``` > **Note: If you do not specify the `(activate)` event, you cannot refresh current tab when uncached.** -> In `src/app/layout/layout.module.ts` - -```ts -import { ReuseTabModule } from '@delon/abc/reuse-tab'; // add -@NgModule({ - imports: [ - // ... - ReuseTabModule, // add - ], - // ... -}) -export class LayoutModule {} -``` - ## Matching Mode -Inject the `ReuseTabService` class anywhere in the project (recommended: `startup.service.ts`) and set the `mode` property, or pass ` ` Reset values. +Inject the `ReuseTabService` class anywhere in the project and set the `mode` property, or pass `` Reset values. **0. Menu (Default)** @@ -310,4 +280,4 @@ Route reuse preserves uses URLs to distinguish whether the same page, and QueryS ### Multi-application cache processing -Allows overriding `REUSE_TAB_CACHED_MANAGER` to change the cache storage, for example when using a micro-frontend (similar to [ngx-planet](https://github.com/worktile/ngx-planet)) can rewrite cached data to `window` guaranteed data sharing. +Use `provideReuseTabConfig(storeKey: 'newKey')` Or overriding `REUSE_TAB_CACHED_MANAGER` to change the cache storage, for example when using a micro-frontend (similar to [ngx-planet](https://github.com/worktile/ngx-planet)) can rewrite cached data to `window` guaranteed data sharing. diff --git a/packages/abc/reuse-tab/index.zh-CN.md b/packages/abc/reuse-tab/index.zh-CN.md index cae8415b5c..be819e4186 100644 --- a/packages/abc/reuse-tab/index.zh-CN.md +++ b/packages/abc/reuse-tab/index.zh-CN.md @@ -5,6 +5,7 @@ title: reuse-tab subtitle: 路由复用标签 cols: 1 module: import { ReuseTabModule } from '@delon/abc/reuse-tab'; +standalone: true --- 复用标签在中台系统非常常见,本质是解决不同路由页切换时组件数据不丢失问题。 @@ -13,52 +14,20 @@ module: import { ReuseTabModule } from '@delon/abc/reuse-tab'; ## 如何使用 -默认 `ReuseTabModule` 并不会注册 `RouteReuseStrategy`,这是因为若默认在模块内注册会导致所有引入 `@delon/abc` 模块都会强制使用路由复用(不管是否模板是否包括 ``)。因此: +1. 在 `app.config.ts` 下提供 `provideReuseTabConfig()` 配置 +2. 在需要展示标签的地方调用 ``,一般在 `src/app/layout/basic/basic.component.ts`,例如: -**注册RouteReuseStrategy** - -> ng-alain 使用方式参考:[global-config.module.ts](https://github.com/ng-alain/ng-alain/blob/master/src/app/global-config.module.ts#L32)。 - -```ts -// global-config.module.ts -import { RouteReuseStrategy } from '@angular/router'; -import { ReuseTabService, ReuseTabStrategy } from '@delon/abc/reuse-tab'; -alainProvides.push({ - provide: RouteReuseStrategy, - useClass: ReuseTabStrategy, - deps: [ReuseTabService], -} as any); -``` - -**添加组件** - -> 位置 `src/app/layout/basic/basic.component.ts` - -```html - - +```diff +- ++ ++ ``` > **注意:若不指定 `(activate)` 事件,无法刷新未缓存过的当前标签页。** -> 位置 `src/app/layout/layout.module.ts` - -```ts -import { ReuseTabModule } from '@delon/abc/reuse-tab'; // 新增 import - -@NgModule({ - imports: [ - // ... - ReuseTabModule, // 导入模块 - ], - // ... -}) -export class LayoutModule {} -``` - ## 匹配模式 -在项目的任何位置(建议:`startup.service.ts`)注入 `ReuseTabService` 类,并设置 `mode` 属性,或通过 `` 重新设置值,包括: +在项目的任何位置注入 `ReuseTabService` 类,并设置 `mode` 属性,或通过 `` 重新设置值,包括: **0、Menu(推荐,默认值)** @@ -311,4 +280,4 @@ export class DemoComponent implements OnReuseInit, OnReuseDestroy { ### 多应用缓存处理 -允许覆盖 `REUSE_TAB_CACHED_MANAGER` 改变缓存存储,例如在使用微前端(类似[ngx-planet](https://github.com/worktile/ngx-planet))可以重写缓存数据到 `window` 下来实现数据共享。 +使用 `provideReuseTabConfig(storeKey: 'newKey')` 或通过覆盖 `REUSE_TAB_CACHED_MANAGER` 改变缓存存储 ,例如在使用微前端(类似[ngx-planet](https://github.com/worktile/ngx-planet))可以重写缓存数据到 `window` 下来实现数据共享。 diff --git a/packages/abc/reuse-tab/provide.ts b/packages/abc/reuse-tab/provide.ts new file mode 100644 index 0000000000..a41dde6a7d --- /dev/null +++ b/packages/abc/reuse-tab/provide.ts @@ -0,0 +1,94 @@ +import { + ENVIRONMENT_INITIALIZER, + EnvironmentProviders, + Provider, + inject, + makeEnvironmentProviders +} from '@angular/core'; +import { RouteReuseStrategy } from '@angular/router'; + +import { REUSE_TAB_CACHED_MANAGER, ReuseTabCachedManagerFactory } from './reuse-tab.cache'; +import { ReuseTabMatchMode, ReuseTabRouteParamMatchMode } from './reuse-tab.interfaces'; +import { ReuseTabService } from './reuse-tab.service'; +import { REUSE_TAB_STORAGE_KEY, REUSE_TAB_STORAGE_STATE, ReuseTabLocalStorageState } from './reuse-tab.state'; +import { ReuseTabStrategy } from './reuse-tab.strategy'; + +export enum ReuseTabFeatureKind { + CacheManager, + Store +} + +export interface ReuseTabFeature { + ɵkind: KindT; + ɵproviders: Provider[]; +} + +function makeFeature(kind: KindT, providers: Provider[]): ReuseTabFeature { + return { + ɵkind: kind, + ɵproviders: providers + }; +} + +/** + * Configures reuse-tab to be available for injection. + * + * @see {@link withLocalStorage} + * @see {@link withCacheManager} + */ +export function provideReuseTabConfig(options?: { + debug?: boolean; + mode?: ReuseTabMatchMode; + routeParamMatchMode?: ReuseTabRouteParamMatchMode; + max?: number; + excludes?: RegExp[]; + storeKey?: string; + cacheManager?: ReuseTabFeature; + store?: ReuseTabFeature; +}): EnvironmentProviders { + const providers: Provider[] = [ + { + provide: REUSE_TAB_STORAGE_KEY, + useValue: options?.storeKey ?? '_reuse-tab-state' + }, + (options?.cacheManager ?? withCacheManager()).ɵproviders, + (options?.store ?? withLocalStorage()).ɵproviders, + { + provide: RouteReuseStrategy, + useClass: ReuseTabStrategy, + deps: [ReuseTabService] + }, + { + provide: ENVIRONMENT_INITIALIZER, + multi: true, + useValue: () => { + const srv = inject(ReuseTabService); + if (options?.debug) srv.debug = options.debug; + if (options?.mode) srv.mode = options.mode; + if (options?.routeParamMatchMode) srv.routeParamMatchMode = options.routeParamMatchMode; + if (options?.max) srv.max = options.max; + if (options?.excludes) srv.excludes = options.excludes; + } + } + ]; + + return makeEnvironmentProviders(providers); +} + +export function withCacheManager(): ReuseTabFeature { + return makeFeature(ReuseTabFeatureKind.CacheManager, [ + { + provide: REUSE_TAB_CACHED_MANAGER, + useFactory: () => new ReuseTabCachedManagerFactory() + } + ]); +} + +export function withLocalStorage(): ReuseTabFeature { + return makeFeature(ReuseTabFeatureKind.Store, [ + { + provide: REUSE_TAB_STORAGE_STATE, + useFactory: () => new ReuseTabLocalStorageState() + } + ]); +} diff --git a/packages/abc/reuse-tab/public_api.ts b/packages/abc/reuse-tab/public_api.ts index e935bed501..c6577500f8 100644 --- a/packages/abc/reuse-tab/public_api.ts +++ b/packages/abc/reuse-tab/public_api.ts @@ -10,3 +10,4 @@ export * from './reuse-tab.interfaces'; export * from './lifecycle_hooks'; export * from './reuse-tab.state'; export { REUSE_TAB_CACHED_MANAGER, ReuseTabCachedManager } from './reuse-tab.cache'; +export * from './provide'; diff --git a/packages/abc/reuse-tab/reuse-tab-context-menu.component.html b/packages/abc/reuse-tab/reuse-tab-context-menu.component.html index 8cf552746e..4e2518d11d 100644 --- a/packages/abc/reuse-tab/reuse-tab-context-menu.component.html +++ b/packages/abc/reuse-tab/reuse-tab-context-menu.component.html @@ -1,11 +1,7 @@
    -
  • + @if (item.active) { +
  • + }
  • - -
  • -
  • -
    + @if (customContextMenu!.length > 0) { +
  • + @for (i of customContextMenu; track $index) { +
  • + } }
diff --git a/packages/abc/reuse-tab/reuse-tab-context-menu.component.ts b/packages/abc/reuse-tab/reuse-tab-context-menu.component.ts index adca756d97..7d4bd85dfc 100644 --- a/packages/abc/reuse-tab/reuse-tab-context-menu.component.ts +++ b/packages/abc/reuse-tab/reuse-tab-context-menu.component.ts @@ -9,6 +9,7 @@ import { } from '@angular/core'; import { DelonLocaleService } from '@delon/theme'; +import { NzMenuModule } from 'ng-zorro-antd/menu'; import { CloseType, @@ -27,7 +28,9 @@ import { }, preserveWhitespaces: false, changeDetection: ChangeDetectionStrategy.OnPush, - encapsulation: ViewEncapsulation.None + encapsulation: ViewEncapsulation.None, + standalone: true, + imports: [NzMenuModule] }) export class ReuseTabContextMenuComponent implements OnInit { private _i18n!: ReuseContextI18n; diff --git a/packages/abc/reuse-tab/reuse-tab-context.component.ts b/packages/abc/reuse-tab/reuse-tab-context.component.ts index 3cf8c7c403..f5e2762671 100644 --- a/packages/abc/reuse-tab/reuse-tab-context.component.ts +++ b/packages/abc/reuse-tab/reuse-tab-context.component.ts @@ -6,7 +6,8 @@ import { ReuseContextCloseEvent, ReuseContextI18n } from './reuse-tab.interfaces @Component({ selector: 'reuse-tab-context', - template: `` + template: ``, + standalone: true }) export class ReuseTabContextComponent implements OnDestroy { private sub$: Subscription = new Subscription(); diff --git a/packages/abc/reuse-tab/reuse-tab-context.directive.ts b/packages/abc/reuse-tab/reuse-tab-context.directive.ts index ad685379b6..f44492ba7d 100644 --- a/packages/abc/reuse-tab/reuse-tab-context.directive.ts +++ b/packages/abc/reuse-tab/reuse-tab-context.directive.ts @@ -8,7 +8,8 @@ import { ReuseCustomContextMenu, ReuseItem } from './reuse-tab.interfaces'; exportAs: 'reuseTabContextMenu', host: { '(contextmenu)': '_onContextMenu($event)' - } + }, + standalone: true }) export class ReuseTabContextDirective { @Input('reuse-tab-context-menu') item!: ReuseItem; diff --git a/packages/abc/reuse-tab/reuse-tab.component.html b/packages/abc/reuse-tab/reuse-tab.component.html index 8027db9e87..72a6939e21 100644 --- a/packages/abc/reuse-tab/reuse-tab.component.html +++ b/packages/abc/reuse-tab/reuse-tab.component.html @@ -7,7 +7,8 @@ [nzTabBarGutter]="tabBarGutter" [nzTabBarStyle]="tabBarStyle" > - + @for (i of list; track $index) { +
- - {{ i.title }} + @if (titleRender) { + + } @else { + {{ i.title }} + }
- + @if (i.closable) { + + }
+ } diff --git a/packages/abc/reuse-tab/reuse-tab.component.spec.ts b/packages/abc/reuse-tab/reuse-tab.component.spec.ts index 0ba445f44d..22027021fc 100644 --- a/packages/abc/reuse-tab/reuse-tab.component.spec.ts +++ b/packages/abc/reuse-tab/reuse-tab.component.spec.ts @@ -9,6 +9,7 @@ import { ALAIN_I18N_TOKEN, DelonLocaleModule, DelonLocaleService, en_US, MenuSer import { ScrollService } from '@delon/util/browser'; import { NzSafeAny } from 'ng-zorro-antd/core/types'; +import { provideReuseTabConfig } from './provide'; import { ReuseTabComponent } from './reuse-tab.component'; import { ReuseCanClose, @@ -17,7 +18,6 @@ import { ReuseTabMatchMode, ReuseTabRouteParamMatchMode } from './reuse-tab.interfaces'; -import { ReuseTabModule } from './reuse-tab.module'; import { ReuseTabService } from './reuse-tab.service'; import { REUSE_TAB_STORAGE_STATE } from './reuse-tab.state'; import { ReuseTabStrategy } from './reuse-tab.strategy'; @@ -44,7 +44,7 @@ describe('abc: reuse-tab', () => { declarations: [AppComponent, LayoutComponent, AComponent, BComponent, CComponent, DComponent, EComponent], imports: [ DelonLocaleModule, - ReuseTabModule, + ReuseTabComponent, RouterTestingModule.withRoutes( [ { @@ -71,11 +71,7 @@ describe('abc: reuse-tab', () => { providers: [ { provide: RouteReuseStrategy, useClass: ReuseTabStrategy, deps: [ReuseTabService] }, MenuService, - { - provide: RouteReuseStrategy, - useClass: ReuseTabStrategy, - deps: [ReuseTabService] - }, + provideReuseTabConfig(), { provide: 'CanDeactivate', useValue: () => { diff --git a/packages/abc/reuse-tab/reuse-tab.component.ts b/packages/abc/reuse-tab/reuse-tab.component.ts index 99cc0bce6f..dfa2aa45b9 100644 --- a/packages/abc/reuse-tab/reuse-tab.component.ts +++ b/packages/abc/reuse-tab/reuse-tab.component.ts @@ -1,6 +1,6 @@ import { Direction, Directionality } from '@angular/cdk/bidi'; import { Platform } from '@angular/cdk/platform'; -import { DOCUMENT } from '@angular/common'; +import { DOCUMENT, NgTemplateOutlet } from '@angular/common'; import { ChangeDetectionStrategy, ChangeDetectorRef, @@ -27,8 +27,12 @@ import { debounceTime, filter, of } from 'rxjs'; import { AlainI18NService, ALAIN_I18N_TOKEN } from '@delon/theme'; import { BooleanInput, InputBoolean, InputNumber, NumberInput } from '@delon/util/decorator'; import type { NzSafeAny } from 'ng-zorro-antd/core/types'; -import { NzTabSetComponent } from 'ng-zorro-antd/tabs'; +import { NzIconModule } from 'ng-zorro-antd/icon'; +import { NzTabSetComponent, NzTabsModule } from 'ng-zorro-antd/tabs'; +import { ReuseTabContextMenuComponent } from './reuse-tab-context-menu.component'; +import { ReuseTabContextComponent } from './reuse-tab-context.component'; +import { ReuseTabContextDirective } from './reuse-tab-context.directive'; import { ReuseTabContextService } from './reuse-tab-context.service'; import { ReuseCanClose, @@ -59,7 +63,16 @@ import { ReuseTabStorageState, REUSE_TAB_STORAGE_KEY, REUSE_TAB_STORAGE_STATE } providers: [ReuseTabContextService], preserveWhitespaces: false, changeDetection: ChangeDetectionStrategy.OnPush, - encapsulation: ViewEncapsulation.None + encapsulation: ViewEncapsulation.None, + standalone: true, + imports: [ + NgTemplateOutlet, + NzTabsModule, + ReuseTabContextMenuComponent, + ReuseTabContextDirective, + ReuseTabContextComponent, + NzIconModule + ] }) export class ReuseTabComponent implements OnInit, OnChanges { static ngAcceptInputType_debug: BooleanInput; diff --git a/packages/abc/reuse-tab/reuse-tab.module.ts b/packages/abc/reuse-tab/reuse-tab.module.ts index 754ee85127..29fea0639b 100644 --- a/packages/abc/reuse-tab/reuse-tab.module.ts +++ b/packages/abc/reuse-tab/reuse-tab.module.ts @@ -19,8 +19,17 @@ const COMPONENTS = [ReuseTabComponent]; const NOEXPORTS = [ReuseTabContextMenuComponent, ReuseTabContextComponent, ReuseTabContextDirective]; @NgModule({ - imports: [CommonModule, RouterModule, DelonLocaleModule, NzMenuModule, NzTabsModule, NzIconModule, OverlayModule], - declarations: [...COMPONENTS, ...NOEXPORTS], + imports: [ + CommonModule, + RouterModule, + DelonLocaleModule, + NzMenuModule, + NzTabsModule, + NzIconModule, + OverlayModule, + ...COMPONENTS, + ...NOEXPORTS + ], providers: [ { provide: REUSE_TAB_STORAGE_KEY, diff --git a/src/app/app.config.ts b/src/app/app.config.ts index 39f8c5ebed..1fafecf636 100644 --- a/src/app/app.config.ts +++ b/src/app/app.config.ts @@ -132,5 +132,6 @@ export const appConfig: ApplicationConfig = { // Elements importProvidersFrom(ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production })), provideElements() + // provideReuseTabConfig({ max: 2 }) ] }; diff --git a/src/dev/layout.component.ts b/src/dev/layout.component.ts index 82321c8416..d4ac3f8e03 100644 --- a/src/dev/layout.component.ts +++ b/src/dev/layout.component.ts @@ -23,7 +23,7 @@ import { // #region icons -import { ReuseCustomContextMenu, ReuseTabModule } from '@delon/abc/reuse-tab'; +import { ReuseCustomContextMenu, ReuseTabComponent } from '@delon/abc/reuse-tab'; import { ALAIN_I18N_TOKEN, Menu, MenuService, RTLService, SettingsService, User } from '@delon/theme'; import { LayoutDefaultModule, LayoutDefaultOptions } from '@delon/theme/layout-default'; import { SettingDrawerModule } from '@delon/theme/setting-drawer'; @@ -110,7 +110,7 @@ const ICONS = [ NzDropDownModule, NzAvatarModule, NzMenuModule, - ReuseTabModule, + ReuseTabComponent, RouterOutlet, SettingDrawerModule ]