import { Directive, ElementRef, Renderer2, Input, NgZone, OnDestroy, AfterViewInit, OnChanges, SimpleChanges } from '@angular/core'; import ResizeObserver from 'resize-observer-polyfill'; @Directive({ selector: '[f-area-response]' }) export class FAreaResponseDirective implements AfterViewInit, OnDestroy, OnChanges { private ro: ResizeObserver | null = null; // 顺序不一致,不用object,用数组 private breakPoints = [ { size: 'sm', width: 576 }, { size: 'md', width: 768 }, { size: 'lg', width: 888 }, { size: 'xl', width: 1200 }, { size: 'el', width: 1690 } ]; private clsNames = []; /** * 是否处理宽度不固定 */ @Input() autoResponse = true; /** * 只处理固定宽度; */ @Input('f-area-response') enableResponse = true; constructor(private el: ElementRef, public ngzone: NgZone, private render: Renderer2) { } ngAfterViewInit() { this.supportResponse(); this.bindEvent(); } ngOnChanges(changes: SimpleChanges): void { if (changes.hasOwnProperty('enableResponse')) { this.supportResponse(); } if (changes.hasOwnProperty('autoResponse')) { this.bindEvent(); } } private bindEvent() { if (this.enableResponse && this.autoResponse) { // 已绑定过 if (this.ro) { return; } else { this.ngzone.runOutsideAngular(() => { this.ro = new ResizeObserver((entries, observer) => { this.widthInterval(entries[0].contentRect.width); }); this.ro.observe(this.el.nativeElement); }); } } else { if (this.ro) { this.ro.unobserve(this.el.nativeElement); this.ro = null; } } } private supportResponse() { // 启用响应 if (this.enableResponse) { this.render.addClass(this.el.nativeElement, 'f-area-response'); this.widthInterval(); } else { // 移除对应的样式 this.render.removeClass(this.el.nativeElement, 'f-area-response'); for (let m = this.clsNames.length; m > 0; m--) { this.render.addClass(this.el.nativeElement, 'f-area-response--' + this.clsNames[m]); this.clsNames = []; } } this.bindEvent(); } private widthInterval(tWidth = 0) { this.ngzone.runOutsideAngular(() => { setTimeout(() => { let result = []; if (!this.el) { return; } const areaWidth = tWidth ? tWidth : this.el.nativeElement.getBoundingClientRect().width; let width = parseFloat(areaWidth); for (let k = 0; k < this.breakPoints.length; k++) { if (this.breakPoints[k]['width'] <= width) { result.push(this.breakPoints[k]['size']); } } if (this.clsNames.join(',') != result.join(',')) { // 旧的比新的多,应该移除class let distance = this.clsNames.length - result.length; if (distance > 0) { for (let m = result.length; m < this.clsNames.length; m++) { this.render.removeClass(this.el.nativeElement, 'f-area-response--' + this.clsNames[m]); } } else { for (let m = this.clsNames.length; m < result.length; m++) { this.render.addClass(this.el.nativeElement, 'f-area-response--' + result[m]); } } this.clsNames = [...result]; } }, 0); }); } ngOnDestroy(): void { if (this.ro) { this.ro.unobserve(this.el.nativeElement); this.ro = null; } } }