挂载卸载
javascript
/**
* 接口 OnDetach,定义 ngOnDetach 方法。
*/
export interface OnDetach {
ngOnDetach: () => void;
}
/**
* 接口 OnAttach,定义 ngOnAttach 方法。
*/
export interface OnAttach {
ngOnAttach: () => void;
}
@Injectable({
providedIn: 'root',
})
/**
* SplitCellsService 服务,用于管理组件的挂载和卸载。
*/
export class SplitCellsService {
// 实例缓存-还原
instances = new Map<number, ComponentRef<OnAttach & OnDetach>>();
// 视图缓存
views = new Map<number, ViewRef>();
// 滚动位置缓存
scrollTop = new WeakMap<ViewRef, number>();
/**
* 挂载组件到容器中。
*
* @param container - 要挂载组件的 ViewContainerRef 容器。
* @param wid - 组件的唯一标识符。
*/
attach(container: ViewContainerRef, wid: number) {
const viewCache = this.views.get(wid);
if (viewCache) {
// 如果存在视图缓存,则插入到容器中并恢复滚动位置
container?.insert(viewCache);
this.getScrollContainer(wid)?.scrollTo(0, this.scrollTop.get(viewCache));
this.instances.get(wid)?.instance?.ngOnAttach?.();
this.views.delete(wid);
this.scrollTop.delete(viewCache);
} else {
// 如果不存在视图缓存,则创建新的组件实例并保存
const instance = container?.createComponent<OnDetach & OnAttach>(ChatComponent);
instance?.setInput('wid', wid);
this.instances.set(wid, instance);
}
}
/**
* 从容器中卸载组件。
*
* @param container - 要卸载组件的 ViewContainerRef 容器。
* @param wid - 组件的唯一标识符。
*/
detach(container: ViewContainerRef, wid: number) {
if (!container) return;
// 调用组件实例的 ngOnDetach 方法
this.instances.get(wid)?.instance?.ngOnDetach?.();
const view = container?.detach();
if (view) {
// 缓存视图和滚动位置
this.views.set(wid, view);
const scrollContainer = this.getScrollContainer(wid);
this.scrollTop.set(view, scrollContainer?.scrollTop);
}
}
/**
* 将组件从一个容器移动到另一个容器。
*
* @param fromContainer - 当前容器。
* @param toContainer - 目标容器。
* @param wid - 组件的唯一标识符。
*/
move(fromContainer: ViewContainerRef, toContainer: ViewContainerRef, wid: number) {
this.detach(fromContainer, wid);
this.attach(toContainer, wid);
}
/**
* 获取滚动容器元素。
*
* @param wid - 组件的唯一标识符。
* @returns 滚动容器元素或 null。
*/
getScrollContainer(wid: number) {
return this.instances.get(wid)?.location.nativeElement.querySelector('.conv-container');
}
}