UNPKG

ng-devui

Version:

DevUI components based on Angular

417 lines (410 loc) 33.5 kB
import * as i4 from '@angular/common'; import { DOCUMENT, CommonModule } from '@angular/common'; import * as i0 from '@angular/core'; import { Injectable, Component, Inject, HostBinding, EventEmitter, Directive, Input, Output, NgModule } from '@angular/core'; import * as i2$1 from 'ng-devui/overlay-container'; import { OverlayContainerRef } from 'ng-devui/overlay-container'; import * as i2 from 'ng-devui/position'; import { PositioningModule } from 'ng-devui/position'; import * as i5 from 'ng-devui/utils'; import { IsTemplateModule, SafePipeModule } from 'ng-devui/utils'; import * as i3 from 'ng-devui/i18n'; import { ReplaySubject, BehaviorSubject, fromEvent, Subscription } from 'rxjs'; import { debounceTime, throttleTime } from 'rxjs/operators'; import { throttle } from 'lodash-es'; class StepsGuideService { constructor() { this.showGuideSource = new ReplaySubject(1); this.currentIndexSource = new BehaviorSubject(0); this.showGuideObs = this.showGuideSource.asObservable(); this.currentIndex = this.currentIndexSource.asObservable(); // 引导步骤 this.steps = []; this.currentStep = 0; } // 切换向导的显示和销毁 showGuide(visible) { this.showGuideSource.next(visible); } setCurrentIndex(index) { this.currentStep = index; this.currentIndexSource.next(index); } getCurrentStep() { return this.currentStep; } setSteps(steps) { this.steps = steps; } getSteps() { return this.steps; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StepsGuideService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StepsGuideService }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StepsGuideService, decorators: [{ type: Injectable }] }); class StepsGuideComponent { get class() { return 'devui-step-item ' + this.position; } get display() { return 'block'; } constructor(stepService, renderer, positionService, elm, i18n, doc) { this.stepService = stepService; this.renderer = renderer; this.positionService = positionService; this.elm = elm; this.i18n = i18n; this.doc = doc; this.position = 'top'; this.zIndex = 1100; this.dots = []; this.SCROLL_REFRESH_INTERVAL = 100; this.DOT_HORIZONTAL_MARGIN = 27; this.DOT_VERTICAL_MARGIN = 22; this.document = this.doc; } ngOnInit() { this.dots = new Array(this.stepsCount); this.elm.nativeElement.style.zIndex = this.zIndex; this.i18nCommonText = this.i18n.getI18nText().stepsGuide; const i18nSubscription = this.i18n.langChange().subscribe((data) => { this.i18nCommonText = data.stepsGuide; }); this.subScriber = fromEvent(window, 'resize') .pipe(debounceTime(this.SCROLL_REFRESH_INTERVAL)) .subscribe(() => { this.updatePosition(); }); this.subScriber.add(i18nSubscription); } ngAfterViewInit() { this.updatePosition(); if (!this.scrollElement) { const currentScrollElement = this.positionService.getScrollParent(this.triggerElement); this.scrollElement = currentScrollElement === this.document.body ? window : currentScrollElement; } const scrollSubscriber = fromEvent(this.scrollElement, 'scroll') .pipe(throttleTime(this.SCROLL_REFRESH_INTERVAL, undefined, { leading: true, trailing: true })) .subscribe(() => { this.updatePosition(); }); this.subScriber.add(scrollSubscriber); } ngOnDestroy() { if (this.subScriber) { this.subScriber.unsubscribe(); } } updatePosition() { const resPosition = this.position === 'right' ? 'right-top' : this.position; const calcPosition = this.position === 'left' ? 'left-top' : resPosition; const rect = this.positionService.positionElements(this.triggerElement, this.elm.nativeElement, calcPosition, true); const targetRect = this.triggerElement.getBoundingClientRect(); let left = rect.left; let top = rect.top; switch (rect.placementPrimary) { case 'top': left = targetRect.left + this.triggerElement.clientWidth / 2 - this.elm.nativeElement.clientWidth / 2; top = top + this.triggerElement.clientHeight / 2 - this.DOT_HORIZONTAL_MARGIN; break; case 'bottom': left = targetRect.left + this.triggerElement.clientWidth / 2 - this.elm.nativeElement.clientWidth / 2; top = top + this.DOT_HORIZONTAL_MARGIN / 2; break; case 'left': left = left + this.triggerElement.clientWidth / 2 - this.DOT_HORIZONTAL_MARGIN; top = top + this.triggerElement.clientHeight / 2 - this.DOT_VERTICAL_MARGIN; break; case 'right': left = left - this.triggerElement.clientWidth / 2 + this.DOT_HORIZONTAL_MARGIN; top = top + this.triggerElement.clientHeight / 2 - this.DOT_VERTICAL_MARGIN; break; default: } switch (rect.placementSecondary) { case 'left': left = targetRect.left; break; case 'right': left = targetRect.left - this.elm.nativeElement.clientWidth + this.triggerElement.clientWidth; break; default: } this.renderer.setStyle(this.elm.nativeElement, 'left', `${left}px`); this.renderer.setStyle(this.elm.nativeElement, 'top', `${top}px`); if (this.leftFix) { this.renderer.setStyle(this.elm.nativeElement, 'marginLeft', `${this.leftFix}px`); } if (this.topFix) { this.renderer.setStyle(this.elm.nativeElement, 'marginTop', `${this.topFix}px`); } } next() { const newStep = (this.stepIndex + 1 < this.stepsCount && this.stepIndex + 1) || this.stepsCount - 1; this.stepService.setCurrentIndex(newStep); this.close(newStep, 'next'); } prev() { const newStep = (this.stepIndex - 1 > 0 && this.stepIndex - 1) || 0; this.stepService.setCurrentIndex(newStep); this.close(newStep, 'prev'); } closeAll() { try { localStorage.setItem(`devui_guide_${this.pageName}`, '0'); } catch (error) { console.error(error); } this.close(this.stepService.getCurrentStep(), 'close'); } close(step, type) { } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StepsGuideComponent, deps: [{ token: StepsGuideService }, { token: i0.Renderer2 }, { token: i2.PositionService }, { token: i0.ElementRef }, { token: i3.I18nService }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: StepsGuideComponent, selector: "ng-component", host: { properties: { "class": "this.class", "style.display": "this.display" } }, ngImport: i0, template: "<div class=\"devui-shining-dot\"></div>\n<div class=\"devui-shining-plus\"></div>\n<div class=\"devui-arrow\"></div>\n<div class=\"devui-guide-container\">\n <p class=\"devui-title\">{{ title }}</p>\n <div class=\"icon icon-close\" (click)=\"closeAll()\"></div>\n <ng-template [ngTemplateOutlet]=\"content | dIsTemplatePipe : plainText\"></ng-template>\n <ng-template #plainText>\n <div class=\"devui-content\" [innerHTML]=\"content | safe : 'html'\"></div>\n </ng-template>\n <div class=\"devui-ctrl\">\n <div *ngIf=\"dots.length > 1 && !extraConfig?.hideStepNav\" class=\"devui-dots\">\n <em *ngFor=\"let dot of dots; index as i\" class=\"icon icon-dot-status {{ i === stepIndex ? 'devui-active' : '' }}\"></em>\n </div>\n <div class=\"devui-guide-btn\">\n <div *ngIf=\"stepIndex > 0 && !extraConfig?.hidePreStep\" class=\"devui-prev-step\" (click)=\"prev()\">{{ i18nCommonText.previous }}</div>\n <div *ngIf=\"stepIndex + 1 < stepsCount\" (click)=\"next()\">{{ i18nCommonText.next }}</div>\n <div *ngIf=\"stepIndex === stepsCount - 1\" (click)=\"closeAll()\">{{ i18nCommonText.finish }}</div>\n </div>\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";.devui-font-size-base{font-size:var(--devui-font-size, 12px)}.devui-font-base{font-size:var(--devui-font-size, 12px);font-weight:var(--devui-font-content-weight, normal);line-height:var(--devui-line-height-base, 1.5)}.devui-font-size-modal-title{font-size:var(--devui-font-size-modal-title, 18px)}.devui-font-modal-title{font-size:var(--devui-font-size-modal-title, 18px);font-weight:var(--devui-font-title-weight, bold);line-height:var(--devui-line-height-base, 1.5)}.devui-font-size-page-title{font-size:var(--devui-font-size-page-title, 16px)}.devui-font-page-title{font-size:var(--devui-font-size-page-title, 16px);font-weight:var(--devui-font-title-weight, bold);line-height:var(--devui-line-height-base, 1.5)}.devui-font-size-secondary-title{font-size:var(--devui-font-size-card-title, 14px)}.devui-font-secondary-title{font-size:var(--devui-font-size-card-title, 14px);font-weight:var(--devui-font-title-weight, bold);line-height:var(--devui-line-height-base, 1.5)}:host.devui-step-item{width:400px;min-height:160px;background:var(--devui-brand, #0a59f7);box-shadow:var(--devui-shadow-length-feedback-overlay, 0 8px 24px 0) var(--devui-light-shadow, rgba(0, 0, 0, .08));border-radius:var(--devui-border-radius-feedback, 4px);font-size:var(--devui-font-size, 12px);color:var(--devui-light-text, #ffffff);padding:20px;position:absolute}:host.devui-step-item .devui-title{font-size:var(--devui-font-size-page-title, 16px);opacity:1;margin:0 0 20px;padding:0}:host.devui-step-item>.devui-arrow,:host.devui-step-item>.devui-arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}:host.devui-step-item>.devui-arrow{border-width:8px}:host.devui-step-item.left>.devui-arrow{top:23px;right:-6px;margin-top:-3px;border-right-width:0;transform:rotate(-135deg);border-left-color:var(--devui-brand, #0a59f7)}:host.devui-step-item.top>.devui-arrow,:host.devui-step-item.top-left>.devui-arrow,:host.devui-step-item.top-right>.devui-arrow{bottom:-6px;border-bottom-width:0;border-top-color:var(--devui-brand, #0a59f7);transform:rotate(135deg)}:host.devui-step-item.top>.devui-arrow{left:calc(50% - 4px)}:host.devui-step-item.top-left>.devui-arrow{left:23px}:host.devui-step-item.top-right>.devui-arrow{right:23px;transform:rotate(-135deg)}:host.devui-step-item.right>.devui-arrow{top:23px;left:-6px;margin-top:-3px;border-left-width:0;transform:rotate(135deg);border-right-color:var(--devui-brand, #0a59f7)}:host.devui-step-item.bottom>.devui-arrow,:host.devui-step-item.bottom-left>.devui-arrow,:host.devui-step-item.bottom-right>.devui-arrow{top:-6px;margin-left:3px;border-top-width:0;border-bottom-color:var(--devui-brand, #0a59f7)}:host.devui-step-item.bottom>.devui-arrow{left:calc(50% - 4px);transform:rotate(-135deg)}:host.devui-step-item.bottom-right>.devui-arrow{right:23px;transform:rotate(135deg)}:host.devui-step-item.bottom-left>.devui-arrow{left:23px;transform:rotate(-135deg)}:host.devui-step-item>.devui-shining-dot,:host.devui-step-item .devui-shining-plus{position:absolute;background:var(--devui-brand, #0a59f7);width:6px;height:6px;border-radius:var(--devui-border-radius-feedback, 4px)}:host.devui-step-item.left>.devui-shining-dot,:host.devui-step-item.left>.devui-shining-plus{top:21px;right:-30px}:host.devui-step-item.right>.devui-shining-dot,:host.devui-step-item.right>.devui-shining-plus{top:21px;left:-30px}:host.devui-step-item.top>.devui-shining-dot,:host.devui-step-item.top>.devui-shining-plus{left:calc(50% - 3px);bottom:-30px}:host.devui-step-item.top-left>.devui-shining-dot,:host.devui-step-item.top-left>.devui-shining-plus{left:21px;bottom:-30px}:host.devui-step-item.top-right>.devui-shining-dot,:host.devui-step-item.top-right>.devui-shining-plus{right:21px;bottom:-30px}:host.devui-step-item.bottom>.devui-shining-dot,:host.devui-step-item.bottom>.devui-shining-plus{left:calc(50% - 3px);top:-30px}:host.devui-step-item.bottom-right>.devui-shining-dot,:host.devui-step-item.bottom-right>.devui-shining-plus{top:-30px;right:21px}:host.devui-step-item.bottom-left>.devui-shining-dot,:host.devui-step-item.bottom-left>.devui-shining-plus{top:-30px;left:21px}:host.devui-step-item .devui-shining-plus{animation:devui-glow 2s 0s infinite}:host.devui-step-item .devui-guide-container{position:relative}:host.devui-step-item .devui-guide-container>.icon-close{position:absolute;top:0;right:0;cursor:pointer}:host.devui-step-item .devui-guide-container .devui-ctrl{display:flex;flex-wrap:wrap}:host.devui-step-item .devui-guide-container .devui-ctrl .devui-dots{color:var(--devui-light-text, #ffffff);position:relative;top:25px;font-size:var(--devui-font-size, 12px);height:30px}:host.devui-step-item .devui-guide-container .devui-ctrl .devui-dots>em{opacity:.2;margin:0 5px 0 2px}:host.devui-step-item .devui-guide-container .devui-ctrl .devui-dots>em.devui-active{opacity:1}:host.devui-step-item .devui-guide-container .devui-ctrl .devui-guide-btn{display:flex;flex-flow:row nowrap;flex-grow:1;justify-content:flex-end;padding:20px 0 0;white-space:nowrap}:host.devui-step-item .devui-guide-container .devui-ctrl .devui-guide-btn>div{color:var(--devui-light-text, #ffffff);background:#ffffff1a;border-radius:var(--devui-border-radius, 2px);padding:5px 15px;cursor:pointer;margin-left:10px}:host.devui-step-item .devui-guide-container .devui-ctrl .devui-guide-btn>div.devui-prev-step{background:none;border:solid 1px rgba(255,255,255,.1)}@keyframes devui-glow{0%{transform:scale(1);opacity:.5}25%{transform:scale(2);opacity:.3}50%{transform:scale(3);opacity:.1}75%{transform:scale(2);opacity:.3}to{transform:scale(1);opacity:.5}}\n"], dependencies: [{ kind: "directive", type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i5.IsTemplatePipe, name: "dIsTemplatePipe" }, { kind: "pipe", type: i5.SafePipe, name: "safe" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StepsGuideComponent, decorators: [{ type: Component, args: [{ preserveWhitespaces: false, template: "<div class=\"devui-shining-dot\"></div>\n<div class=\"devui-shining-plus\"></div>\n<div class=\"devui-arrow\"></div>\n<div class=\"devui-guide-container\">\n <p class=\"devui-title\">{{ title }}</p>\n <div class=\"icon icon-close\" (click)=\"closeAll()\"></div>\n <ng-template [ngTemplateOutlet]=\"content | dIsTemplatePipe : plainText\"></ng-template>\n <ng-template #plainText>\n <div class=\"devui-content\" [innerHTML]=\"content | safe : 'html'\"></div>\n </ng-template>\n <div class=\"devui-ctrl\">\n <div *ngIf=\"dots.length > 1 && !extraConfig?.hideStepNav\" class=\"devui-dots\">\n <em *ngFor=\"let dot of dots; index as i\" class=\"icon icon-dot-status {{ i === stepIndex ? 'devui-active' : '' }}\"></em>\n </div>\n <div class=\"devui-guide-btn\">\n <div *ngIf=\"stepIndex > 0 && !extraConfig?.hidePreStep\" class=\"devui-prev-step\" (click)=\"prev()\">{{ i18nCommonText.previous }}</div>\n <div *ngIf=\"stepIndex + 1 < stepsCount\" (click)=\"next()\">{{ i18nCommonText.next }}</div>\n <div *ngIf=\"stepIndex === stepsCount - 1\" (click)=\"closeAll()\">{{ i18nCommonText.finish }}</div>\n </div>\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";.devui-font-size-base{font-size:var(--devui-font-size, 12px)}.devui-font-base{font-size:var(--devui-font-size, 12px);font-weight:var(--devui-font-content-weight, normal);line-height:var(--devui-line-height-base, 1.5)}.devui-font-size-modal-title{font-size:var(--devui-font-size-modal-title, 18px)}.devui-font-modal-title{font-size:var(--devui-font-size-modal-title, 18px);font-weight:var(--devui-font-title-weight, bold);line-height:var(--devui-line-height-base, 1.5)}.devui-font-size-page-title{font-size:var(--devui-font-size-page-title, 16px)}.devui-font-page-title{font-size:var(--devui-font-size-page-title, 16px);font-weight:var(--devui-font-title-weight, bold);line-height:var(--devui-line-height-base, 1.5)}.devui-font-size-secondary-title{font-size:var(--devui-font-size-card-title, 14px)}.devui-font-secondary-title{font-size:var(--devui-font-size-card-title, 14px);font-weight:var(--devui-font-title-weight, bold);line-height:var(--devui-line-height-base, 1.5)}:host.devui-step-item{width:400px;min-height:160px;background:var(--devui-brand, #0a59f7);box-shadow:var(--devui-shadow-length-feedback-overlay, 0 8px 24px 0) var(--devui-light-shadow, rgba(0, 0, 0, .08));border-radius:var(--devui-border-radius-feedback, 4px);font-size:var(--devui-font-size, 12px);color:var(--devui-light-text, #ffffff);padding:20px;position:absolute}:host.devui-step-item .devui-title{font-size:var(--devui-font-size-page-title, 16px);opacity:1;margin:0 0 20px;padding:0}:host.devui-step-item>.devui-arrow,:host.devui-step-item>.devui-arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}:host.devui-step-item>.devui-arrow{border-width:8px}:host.devui-step-item.left>.devui-arrow{top:23px;right:-6px;margin-top:-3px;border-right-width:0;transform:rotate(-135deg);border-left-color:var(--devui-brand, #0a59f7)}:host.devui-step-item.top>.devui-arrow,:host.devui-step-item.top-left>.devui-arrow,:host.devui-step-item.top-right>.devui-arrow{bottom:-6px;border-bottom-width:0;border-top-color:var(--devui-brand, #0a59f7);transform:rotate(135deg)}:host.devui-step-item.top>.devui-arrow{left:calc(50% - 4px)}:host.devui-step-item.top-left>.devui-arrow{left:23px}:host.devui-step-item.top-right>.devui-arrow{right:23px;transform:rotate(-135deg)}:host.devui-step-item.right>.devui-arrow{top:23px;left:-6px;margin-top:-3px;border-left-width:0;transform:rotate(135deg);border-right-color:var(--devui-brand, #0a59f7)}:host.devui-step-item.bottom>.devui-arrow,:host.devui-step-item.bottom-left>.devui-arrow,:host.devui-step-item.bottom-right>.devui-arrow{top:-6px;margin-left:3px;border-top-width:0;border-bottom-color:var(--devui-brand, #0a59f7)}:host.devui-step-item.bottom>.devui-arrow{left:calc(50% - 4px);transform:rotate(-135deg)}:host.devui-step-item.bottom-right>.devui-arrow{right:23px;transform:rotate(135deg)}:host.devui-step-item.bottom-left>.devui-arrow{left:23px;transform:rotate(-135deg)}:host.devui-step-item>.devui-shining-dot,:host.devui-step-item .devui-shining-plus{position:absolute;background:var(--devui-brand, #0a59f7);width:6px;height:6px;border-radius:var(--devui-border-radius-feedback, 4px)}:host.devui-step-item.left>.devui-shining-dot,:host.devui-step-item.left>.devui-shining-plus{top:21px;right:-30px}:host.devui-step-item.right>.devui-shining-dot,:host.devui-step-item.right>.devui-shining-plus{top:21px;left:-30px}:host.devui-step-item.top>.devui-shining-dot,:host.devui-step-item.top>.devui-shining-plus{left:calc(50% - 3px);bottom:-30px}:host.devui-step-item.top-left>.devui-shining-dot,:host.devui-step-item.top-left>.devui-shining-plus{left:21px;bottom:-30px}:host.devui-step-item.top-right>.devui-shining-dot,:host.devui-step-item.top-right>.devui-shining-plus{right:21px;bottom:-30px}:host.devui-step-item.bottom>.devui-shining-dot,:host.devui-step-item.bottom>.devui-shining-plus{left:calc(50% - 3px);top:-30px}:host.devui-step-item.bottom-right>.devui-shining-dot,:host.devui-step-item.bottom-right>.devui-shining-plus{top:-30px;right:21px}:host.devui-step-item.bottom-left>.devui-shining-dot,:host.devui-step-item.bottom-left>.devui-shining-plus{top:-30px;left:21px}:host.devui-step-item .devui-shining-plus{animation:devui-glow 2s 0s infinite}:host.devui-step-item .devui-guide-container{position:relative}:host.devui-step-item .devui-guide-container>.icon-close{position:absolute;top:0;right:0;cursor:pointer}:host.devui-step-item .devui-guide-container .devui-ctrl{display:flex;flex-wrap:wrap}:host.devui-step-item .devui-guide-container .devui-ctrl .devui-dots{color:var(--devui-light-text, #ffffff);position:relative;top:25px;font-size:var(--devui-font-size, 12px);height:30px}:host.devui-step-item .devui-guide-container .devui-ctrl .devui-dots>em{opacity:.2;margin:0 5px 0 2px}:host.devui-step-item .devui-guide-container .devui-ctrl .devui-dots>em.devui-active{opacity:1}:host.devui-step-item .devui-guide-container .devui-ctrl .devui-guide-btn{display:flex;flex-flow:row nowrap;flex-grow:1;justify-content:flex-end;padding:20px 0 0;white-space:nowrap}:host.devui-step-item .devui-guide-container .devui-ctrl .devui-guide-btn>div{color:var(--devui-light-text, #ffffff);background:#ffffff1a;border-radius:var(--devui-border-radius, 2px);padding:5px 15px;cursor:pointer;margin-left:10px}:host.devui-step-item .devui-guide-container .devui-ctrl .devui-guide-btn>div.devui-prev-step{background:none;border:solid 1px rgba(255,255,255,.1)}@keyframes devui-glow{0%{transform:scale(1);opacity:.5}25%{transform:scale(2);opacity:.3}50%{transform:scale(3);opacity:.1}75%{transform:scale(2);opacity:.3}to{transform:scale(1);opacity:.5}}\n"] }] }], ctorParameters: () => [{ type: StepsGuideService }, { type: i0.Renderer2 }, { type: i2.PositionService }, { type: i0.ElementRef }, { type: i3.I18nService }, { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT] }] }], propDecorators: { class: [{ type: HostBinding, args: ['class'] }], display: [{ type: HostBinding, args: ['style.display'] }] } }); class StepsGuideDirective { set dStepsGuidePosition(pos) { this._dStepsGuidePosition = pos; } get dStepsGuidePosition() { return this._dStepsGuidePosition || 'top'; } /** * @deprecated Use dStepsGuidePosition to replace. */ set position(pos) { if (!this._dStepsGuidePosition) { this.dStepsGuidePosition = pos; } } // 允许用户指定一个dom反馈页面变化,通过MutationObserver监听该dom所属节点树变化触发resize事件使引导弹窗自动修正位置 set observerDom(dom) { if (dom) { this._observerDom = dom; // 创建监听实例,并限制回调方法在500ms内只响应一次,避免多次响应dom变化造成性能负担 this.observer = new MutationObserver(throttle(this.mutationCallBack, this.MUTATION_OBSERVER_TIME, { 'leading': false, 'trailing': true })); this.observer.observe(this._observerDom, this.MUTATION_OBSERVER_CONFIG); } else { this.destroyMutationObserver(true); } } constructor(stepService, elm, componentFactoryResolver, overlayContainerRef, doc) { this.stepService = stepService; this.elm = elm; this.componentFactoryResolver = componentFactoryResolver; this.overlayContainerRef = overlayContainerRef; this.doc = doc; this.steps = []; // 可选,用于修正引导位置 this.leftFix = 0; this.topFix = 0; this.zIndex = 1100; // 是否自动滚动页面至目标 this.scrollToTargetSwitch = true; // 点击引导操作触发,返回当前步骤和当前操作,比如上一步、下一步、关闭 this.operateChange = new EventEmitter(); this.sub = new Subscription(); // 监听dom变化的设置,监听属性变化和dom所属节点树变化 this.MUTATION_OBSERVER_CONFIG = { attributes: true, subtree: true }; this.MUTATION_OBSERVER_TIME = 500; // 监听dom变化的回调方法,即dom发生变化时触发resize事件 this.mutationCallBack = () => { if (typeof window === 'undefined') { return; } const resizeEvt = this.document.createEvent('Event'); resizeEvt.initEvent('resize', true, true); window.dispatchEvent(resizeEvt); }; this.document = this.doc; } ngOnInit() { // 监听当前索引变化,决定显示步骤 this.sub.add(this.stepService.currentIndex.subscribe(index => { this.canChange(index).then((change) => { if (!change) { return; } }); // 防止服务中的步骤被置空或默认为空 const serviceSteps = this.stepService.getSteps() || []; this.steps = serviceSteps.length > 0 ? serviceSteps : this.steps; const state = localStorage.getItem(`devui_guide_${this.pageName}`) || '1'; this.toggle = Number(state); this.currentIndex = index; const currentStep = this.steps.length > 0 && this.steps[this.currentIndex]; // 当前步骤内容存在且未被屏蔽显示且为当前索引时插入操作指引弹窗 if (currentStep && this.toggle && this.stepIndex === this.currentIndex) { const targetDom = this.targetElement || this.elm.nativeElement; if (this.scrollToTargetSwitch) { targetDom.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'nearest' }); } // 如果该步骤设置了监听dom和监听实例,重启监听 if (this._observerDom && this.observer) { this.observer.disconnect(); this.observer.observe(this._observerDom, this.MUTATION_OBSERVER_CONFIG); } setTimeout(() => { this.insert({ triggerElement: targetDom, scrollElement: this.scrollElement, pageName: this.pageName, title: currentStep.title, content: currentStep.content, stepsCount: this.steps.length, stepIndex: this.stepIndex, position: this.dStepsGuidePosition, leftFix: this.leftFix, topFix: this.topFix, zIndex: this.zIndex, }); }); } })); // 监听切换显示和隐藏 this.sub.add(this.stepService.showGuideObs.subscribe(visible => { if (visible) { const currentIndex = this.stepService.getCurrentStep() || 0; localStorage.removeItem(`devui_guide_${this.pageName}`); this.stepService.setCurrentIndex(currentIndex); } else { try { localStorage.setItem(`devui_guide_${this.pageName}`, '0'); } catch (error) { console.error(error); } this.destroyView(); } })); } ngOnDestroy() { this.sub.unsubscribe(); this.destroyView(); } destroyView() { if (this.stepRef) { this.stepRef.hostView.destroy(); } this.destroyMutationObserver(); } insert(option) { const hasGuide = this.document.querySelector('body>.devui-step-item'); if (!hasGuide) { this.stepRef = this.overlayContainerRef.createComponent(this.componentFactoryResolver.resolveComponentFactory(StepsGuideComponent)); Object.assign(this.stepRef.instance, option, { extraConfig: this.extraConfig }); this.stepRef.instance.close = (step, type) => { this.operateChange.emit({ clickType: type, currentIndex: step }); this.destroyView(); }; } } // 断开监听, 清空监听dom和实例 destroyMutationObserver(destroyAll) { if (this.observer) { this.observer.disconnect(); } if (destroyAll) { this._observerDom = undefined; this.observer = undefined; } } canChange(index) { let changeResult = Promise.resolve(true); const currentIndex = this.currentIndex >= 0 ? this.currentIndex : this.stepIndex; if (currentIndex === index && this.beforeChange) { const result = this.beforeChange(currentIndex, index); if (typeof result !== 'undefined') { if (result.then) { changeResult = result; } else if (result.subscribe) { changeResult = result.toPromise(); } else { changeResult = Promise.resolve(result); } } } return changeResult; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StepsGuideDirective, deps: [{ token: StepsGuideService }, { token: i0.ElementRef }, { token: i0.ComponentFactoryResolver }, { token: i2$1.OverlayContainerRef }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.13", type: StepsGuideDirective, selector: "[dStepsGuide]", inputs: { pageName: "pageName", steps: "steps", stepIndex: "stepIndex", dStepsGuidePosition: "dStepsGuidePosition", position: "position", leftFix: "leftFix", topFix: "topFix", zIndex: "zIndex", targetElement: "targetElement", scrollElement: "scrollElement", scrollToTargetSwitch: "scrollToTargetSwitch", extraConfig: "extraConfig", observerDom: "observerDom", beforeChange: "beforeChange" }, outputs: { operateChange: "operateChange" }, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StepsGuideDirective, decorators: [{ type: Directive, args: [{ selector: '[dStepsGuide]', }] }], ctorParameters: () => [{ type: StepsGuideService }, { type: i0.ElementRef }, { type: i0.ComponentFactoryResolver }, { type: i2$1.OverlayContainerRef }, { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT] }] }], propDecorators: { pageName: [{ type: Input }], steps: [{ type: Input }], stepIndex: [{ type: Input }], dStepsGuidePosition: [{ type: Input }], position: [{ type: Input }], leftFix: [{ type: Input }], topFix: [{ type: Input }], zIndex: [{ type: Input }], targetElement: [{ type: Input }], scrollElement: [{ type: Input }], scrollToTargetSwitch: [{ type: Input }], extraConfig: [{ type: Input }], observerDom: [{ type: Input }], beforeChange: [{ type: Input }], operateChange: [{ type: Output }] } }); class StepsGuideModule { static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StepsGuideModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); } static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.13", ngImport: i0, type: StepsGuideModule, declarations: [StepsGuideComponent, StepsGuideDirective], imports: [CommonModule, IsTemplateModule, SafePipeModule, PositioningModule], exports: [StepsGuideDirective] }); } static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StepsGuideModule, providers: [OverlayContainerRef, StepsGuideService], imports: [CommonModule, IsTemplateModule, SafePipeModule, PositioningModule] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StepsGuideModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule, IsTemplateModule, SafePipeModule, PositioningModule], declarations: [StepsGuideComponent, StepsGuideDirective], exports: [StepsGuideDirective], providers: [OverlayContainerRef, StepsGuideService], }] }] }); /** * Generated bundle index. Do not edit. */ export { StepsGuideComponent, StepsGuideDirective, StepsGuideModule, StepsGuideService }; //# sourceMappingURL=ng-devui-steps-guide.mjs.map