UNPKG

@duoduo-oba/ng-devui

Version:

DevUI components based on Angular

583 lines (574 loc) 18.2 kB
import { Directive, ElementRef, Input, HostListener, ContentChildren, Inject, forwardRef, HostBinding, NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { ReplaySubject, Subject } from 'rxjs'; /** * @fileoverview added by tsickle * Generated from: anchor.directive.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class AnchorDirective { /** * @param {?} el */ constructor(el) { this.el = el; this.anchorActive = 'active'; this.activeChangeSubject = new ReplaySubject(1); this.REACH_TOP_VISION_OFFSET = 50; this.THROTTLE_DELAY = 100; this.THROTTLE_TRIGGER = 600; this.throttle = (/** * @return {?} */ () => { /** @type {?} */ const fn = this.checkActiveStatus; /** @type {?} */ const time = Date.now(); if (this.scrollTimer) { clearTimeout(this.scrollTimer); } if (!this.scrollPreStart) { this.scrollPreStart = time; } if (time - this.scrollPreStart > this.THROTTLE_TRIGGER) { fn(); this.scrollPreStart = null; this.scrollTimer = null; } else { this.scrollTimer = setTimeout((/** * @return {?} */ () => { fn(); this.scrollPreStart = null; this.scrollTimer = null; }), this.THROTTLE_DELAY); } }); this.checkActiveStatus = (/** * @param {?=} activeChangeBy * @return {?} */ (activeChangeBy) => { /** @type {?} */ const top = this.element.getBoundingClientRect().top - (this.boxElement.view && this.boxElement.view.top || 0); /** @type {?} */ const bottom = this.element.getBoundingClientRect().bottom - (this.boxElement.view && this.boxElement.view.top || 0); // 首个个特殊处理 if (this.anchor === this.boxElement.defaultAnchor) { this.activeChangeBy = activeChangeBy || 'scroll'; this.isActive = bottom > this.REACH_TOP_VISION_OFFSET ? true : false; return; } // 默认处理 this.activeChangeBy = activeChangeBy || 'scroll'; this.isActive = bottom > this.REACH_TOP_VISION_OFFSET && top < this.REACH_TOP_VISION_OFFSET ? true : false; }); this.element = this.el.nativeElement; } /** * @param {?} active * @return {?} */ set isActive(active) { this._isActive = active; this.activeChangeSubject.next(active); } /** * @return {?} */ get isActive() { return this._isActive; } /** * @param {?} box * @return {?} */ set boxElement(box) { this._boxElement = box; this.updateScrollListenTarget(); } /** * @return {?} */ get boxElement() { return this._boxElement; } /** * @return {?} */ ngAfterViewInit() { this.activeChangeSubscription = this.activeChangeSubject.asObservable().subscribe((/** * @param {?} active * @return {?} */ active => { if (this.lastActiveBy) { this.element.classList.remove(this.lastActiveBy); } if (active) { this.element.classList.add(this.anchorActive); this.lastActiveBy = 'anchor-active-by-' + this.activeChangeBy; // setTimeout是为了this.lastActiveBy每次都能被再次触发 setTimeout((/** * @return {?} */ () => { this.element.classList.add(this.lastActiveBy); }), 0); } else { this.element.classList.remove(this.anchorActive); } })); setTimeout((/** * @return {?} */ () => { this.checkActiveStatus('initial'); })); } /** * @return {?} */ ngOnDestroy() { this.scrollListenTarget.removeEventListener('scroll', this.throttle); if (this.activeChangeSubscription) { this.activeChangeSubscription.unsubscribe(); } } /** * @return {?} */ beFocused() { this.boxElement.forceActiveAnchor(this.anchor, 'click-inside'); } /** * @return {?} */ updateScrollListenTarget() { if (this.scrollListenTarget) { return; } if (this.boxElement) { this.scrollListenTarget = this.boxElement.scrollTarget || window; // window有scroll事件,document.documentElement没有scroll事件 } this.scrollListenTarget.addEventListener('scroll', this.throttle, { passive: true }); } } AnchorDirective.decorators = [ { type: Directive, args: [{ selector: '[dAnchor]' },] } ]; /** @nocollapse */ AnchorDirective.ctorParameters = () => [ { type: ElementRef } ]; AnchorDirective.propDecorators = { anchor: [{ type: Input, args: ['dAnchor',] }], anchorActive: [{ type: Input }], beFocused: [{ type: HostListener, args: ['click',] }] }; if (false) { /** @type {?} */ AnchorDirective.prototype.anchor; /** @type {?} */ AnchorDirective.prototype.anchorActive; /** @type {?} */ AnchorDirective.prototype._isActive; /** @type {?} */ AnchorDirective.prototype.activeChangeBy; /** @type {?} */ AnchorDirective.prototype.activeChangeSubscription; /** @type {?} */ AnchorDirective.prototype.activeChangeSubject; /** @type {?} */ AnchorDirective.prototype.lastActiveBy; /** @type {?} */ AnchorDirective.prototype.element; /** @type {?} */ AnchorDirective.prototype._boxElement; /** @type {?} */ AnchorDirective.prototype.scrollListenTarget; /** @type {?} */ AnchorDirective.prototype.REACH_TOP_VISION_OFFSET; /** * @type {?} * @private */ AnchorDirective.prototype.THROTTLE_DELAY; /** * @type {?} * @private */ AnchorDirective.prototype.THROTTLE_TRIGGER; /** * @type {?} * @private */ AnchorDirective.prototype.scrollPreStart; /** * @type {?} * @private */ AnchorDirective.prototype.scrollTimer; /** @type {?} */ AnchorDirective.prototype.throttle; /** @type {?} */ AnchorDirective.prototype.checkActiveStatus; /** * @type {?} * @private */ AnchorDirective.prototype.el; } /** * @fileoverview added by tsickle * Generated from: anchor-box.directive.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class AnchorBoxDirective { constructor() { this.refreshAnchorMap = new Subject(); } /** * @param {?} list * @return {?} */ set anchorList(list) { this.anchorMap = {}; this._anchorList = list; this._anchorList.toArray().forEach((/** * @param {?} targetAnchor * @return {?} */ targetAnchor => { this.anchorMap[targetAnchor.anchor] = targetAnchor; targetAnchor.boxElement = this; })); this.refreshAnchorMap.next(); } /** * @return {?} */ get anchorList() { return this._anchorList; } /** * @param {?} anchorName * @param {?=} forceActiveSource * @param {?=} deactivateOtherAnchor * @return {?} */ forceActiveAnchor(anchorName, forceActiveSource = 'scroll', deactivateOtherAnchor = true) { this.anchorMap[anchorName].activeChangeBy = forceActiveSource; this.anchorMap[anchorName].isActive = true; if (deactivateOtherAnchor) { Object.keys(this.anchorMap) .filter((/** * @param {?} name * @return {?} */ name => name !== anchorName)) .map((/** * @param {?} name * @return {?} */ name => this.anchorMap[name])) .forEach((/** * @param {?} anchor * @return {?} */ anchor => { anchor.activeChangeBy = forceActiveSource; anchor.isActive = false; })); } } } AnchorBoxDirective.decorators = [ { type: Directive, args: [{ selector: '[dAnchorBox]' },] } ]; /** @nocollapse */ AnchorBoxDirective.ctorParameters = () => []; AnchorBoxDirective.propDecorators = { view: [{ type: Input }], defaultAnchor: [{ type: Input }], scrollTarget: [{ type: Input }], anchorList: [{ type: ContentChildren, args: [AnchorDirective, { descendants: true },] }] }; if (false) { /** @type {?} */ AnchorBoxDirective.prototype.view; /** @type {?} */ AnchorBoxDirective.prototype.defaultAnchor; /** @type {?} */ AnchorBoxDirective.prototype.scrollTarget; /** @type {?} */ AnchorBoxDirective.prototype.refreshAnchorMap; /** @type {?} */ AnchorBoxDirective.prototype.anchorMap; /** @type {?} */ AnchorBoxDirective.prototype._anchorList; } /** * @fileoverview added by tsickle * Generated from: anchor-link.directive.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class AnchorLinkDirective { /** * @param {?} box */ constructor(box) { this.bindAnchorAfterBoxReady = (/** * @return {?} */ () => { if (this.boxElement.anchorMap) { setTimeout((/** * @return {?} */ () => { this.anchorBlock = this.boxElement.anchorMap[this.anchorName]; }), 0); } else { this.bindingAnchorTimer = setTimeout(this.bindAnchorAfterBoxReady, 500); } }); this.boxElement = box; } /** * @return {?} */ get anchorActiveClass() { return (this.anchorBlock && this.anchorBlock.isActive) ? (this.anchorActive || '') : ''; } /** * @param {?} anchor * @return {?} */ set anchorName(anchor) { this._anchorName = anchor; this.bindAnchorAfterBoxReady(); } /** * @return {?} */ get anchorName() { return this._anchorName; } /** * @return {?} */ ngOnInit() { this.subscribeAnchorMapChange(); } /** * @return {?} */ ngOnDestroy() { if (this.subscription) { this.subscription.unsubscribe(); } } /** * @return {?} */ subscribeAnchorMapChange() { if (this.boxElement) { this.subscription = this.boxElement.refreshAnchorMap.subscribe((/** * @return {?} */ () => { if (this.bindingAnchorTimer) { clearTimeout(this.bindingAnchorTimer); this.bindingAnchorTimer = undefined; } this.bindAnchorAfterBoxReady(); })); } } /** * @return {?} */ scrollToAnchor() { if (!this.anchorBlock) { return; } /** @type {?} */ const callback = (/** * @return {?} */ () => { setTimeout((/** * @return {?} */ () => { this.boxElement.forceActiveAnchor(this.anchorName, 'anchor-link'); }), 120); }); ((/** * @param {?} container * @param {?} anchor * @return {?} */ (container, anchor) => { /** @type {?} */ let containerScrollTop = container.scrollTop; if (container === document.documentElement) { containerScrollTop += document.body.scrollTop; } this.scrollAnimate(container, containerScrollTop, (containerScrollTop + anchor.getBoundingClientRect().top - (this.boxElement.view && this.boxElement.view.top || 0)), undefined, undefined, callback); }))(this.boxElement.scrollTarget || document.documentElement, this.anchorBlock.element); } /** * @param {?} target * @param {?} currentTopValue * @param {?} targetTopValue * @param {?=} timeGap * @param {?=} scrollTime * @param {?=} callback * @return {?} */ scrollAnimate(target, currentTopValue, targetTopValue, timeGap = 40, scrollTime = 450, callback) { /** @type {?} */ const startTimeStamp = Date.now(); /** @type {?} */ const drawAnimateFrame = (/** * @return {?} */ () => { /** @type {?} */ const currentTime = Date.now() - startTimeStamp; if (currentTime - timeGap > scrollTime) { target.scrollTop = targetTopValue; if (target === document.documentElement) { // 兼容写法,老浏览器/老API模式需要document.body滚动,新的需要documentElement滚动 document.body.scrollTop = targetTopValue; } if (callback) { callback(); } } else { /** @type {?} */ const tempTopValue = this.easeInOutCubic(currentTime, currentTopValue, targetTopValue, scrollTime); target.scrollTop = tempTopValue; if (target === document.documentElement) { document.body.scrollTop = tempTopValue; } setTimeout((/** * @return {?} */ () => { requestAnimationFrame(drawAnimateFrame); }), timeGap); } }); requestAnimationFrame(drawAnimateFrame); } /** * @param {?} t * @param {?} b * @param {?} c * @param {?} d * @return {?} */ easeInOutCubic(t, b, c, d) { /** @type {?} */ const cc = c - b; /** @type {?} */ let tt = t / (d / 2); if (tt < 1) { return cc / 2 * tt * tt * tt + b; } else { return cc / 2 * ((tt -= 2) * tt * tt + 2) + b; } } } AnchorLinkDirective.decorators = [ { type: Directive, args: [{ selector: '[dAnchorLink]', },] } ]; /** @nocollapse */ AnchorLinkDirective.ctorParameters = () => [ { type: AnchorBoxDirective, decorators: [{ type: Inject, args: [forwardRef((/** * @return {?} */ () => AnchorBoxDirective)),] }] } ]; AnchorLinkDirective.propDecorators = { anchorActiveClass: [{ type: HostBinding, args: ['class',] }], anchorName: [{ type: Input, args: ['dAnchorLink',] }], anchorActive: [{ type: Input }], scrollToAnchor: [{ type: HostListener, args: ['click',] }] }; if (false) { /** * @type {?} * @private */ AnchorLinkDirective.prototype._anchorName; /** @type {?} */ AnchorLinkDirective.prototype.anchorActive; /** @type {?} */ AnchorLinkDirective.prototype.boxElement; /** @type {?} */ AnchorLinkDirective.prototype.anchorBlock; /** @type {?} */ AnchorLinkDirective.prototype.bindingAnchorTimer; /** @type {?} */ AnchorLinkDirective.prototype.subscription; /** @type {?} */ AnchorLinkDirective.prototype.bindAnchorAfterBoxReady; } /** * @fileoverview added by tsickle * Generated from: anchor.module.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class AnchorModule { } AnchorModule.decorators = [ { type: NgModule, args: [{ imports: [ CommonModule ], declarations: [ AnchorLinkDirective, AnchorBoxDirective, AnchorDirective ], exports: [ AnchorLinkDirective, AnchorBoxDirective, AnchorDirective ], },] } ]; /** * @fileoverview added by tsickle * Generated from: anchor.type.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * @record */ function IAnchorBox() { } if (false) { /** @type {?} */ IAnchorBox.prototype.scrollTarget; /** @type {?} */ IAnchorBox.prototype.defaultAnchor; /** @type {?} */ IAnchorBox.prototype.forceActiveAnchor; /** @type {?} */ IAnchorBox.prototype.view; } /** * @fileoverview added by tsickle * Generated from: public-api.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * @fileoverview added by tsickle * Generated from: ng-devui-anchor.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ export { AnchorBoxDirective, AnchorDirective, AnchorLinkDirective, AnchorModule }; //# sourceMappingURL=ng-devui-anchor.js.map