UNPKG

@duoduo-oba/ng-devui

Version:

DevUI components based on Angular

359 lines (353 loc) 12.9 kB
import { EventEmitter, Component, ElementRef, HostBinding, Input, Output, ViewChild, HostListener, NgModule } from '@angular/core'; /** * @fileoverview added by tsickle * Generated from: sticky.component.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class StickyComponent { /** * @param {?} el */ constructor(el) { this.el = el; this.hostPosition = 'relative'; this.statusChange = new EventEmitter(); this._prevStatus = undefined; this._status = 'normal'; // 用于监听是否是横向滚动 this.THROTTLE_DELAY = 16; this.THROTTLE_TRIGGER = 100; this.throttle = (/** * @return {?} */ () => { /** @type {?} */ const fn = this.scrollAndResizeHock; /** @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.scrollAndResizeHock = (/** * @return {?} */ () => { if (this.container.getBoundingClientRect().left - (this.containerLeft || 0) !== 0) { this.status = 'stay'; this.containerLeft = this.container.getBoundingClientRect().left; } else { this.scrollHandler(); } }); this.scrollHandler = (/** * @return {?} */ () => { /** @type {?} */ const computedStyle = window.getComputedStyle(this.container); if (this.parentNode.getBoundingClientRect().top > (this.view && this.view.top || 0)) { this.status = 'normal'; // 全局滑动(container!==parentNode)时候增加预判 } else if (this.container.getBoundingClientRect().top + parseInt(computedStyle.paddingTop, 10) + parseInt(computedStyle.borderTopWidth, 10) >= (this.view && this.view.top || 0)) { this.status = 'normal'; } else if (this.container.getBoundingClientRect().bottom - parseInt(computedStyle.paddingBottom, 10) - parseInt(computedStyle.borderBottomWidth, 10) - this.wrapper.nativeElement.getBoundingClientRect().height < (this.view && this.view.top || 0) + (this.view && this.view.bottom || 0)) { this.status = 'remain'; } else if ((this.container.getBoundingClientRect().top + parseInt(computedStyle.paddingTop, 10) < (this.view && this.view.top || 0))) { this.status = 'follow'; } }); } /** * @param {?} status * @return {?} */ set status(status) { if (status !== this._status) { this._prevStatus = this._status; this._status = status; this.statusProcess(this._status); } } /** * @return {?} */ get status() { return this._status; } /** * @return {?} */ ngOnInit() { this.parentNode = this.el.nativeElement.parentNode; if (!this.container) { this.container = this.parentNode; } } /** * @return {?} */ ngAfterViewInit() { this.scrollTarget = this.scrollTarget || window; // window有scroll事件,document.documentElement没有scroll事件 this.scrollTarget.addEventListener('scroll', this.throttle); this.initScrollStatus(this.scrollTarget); } /** * @return {?} */ ngOnDestroy() { this.scrollTarget.removeEventListener('scroll', this.throttle); } /** * @param {?} status * @return {?} */ statusProcess(status) { switch (status) { case 'normal': this.wrapper.nativeElement.style.top = 'auto'; this.wrapper.nativeElement.style.left = 'auto'; this.wrapper.nativeElement.style.position = 'static'; break; case 'follow': this.wrapper.nativeElement.style.top = (this.view && this.view.top || 0) + 'px'; this.wrapper.nativeElement.style.left = this.wrapper.nativeElement.getBoundingClientRect().left + 'px'; this.wrapper.nativeElement.style.position = 'fixed'; break; case 'stay': this.wrapper.nativeElement.style.top = this.calculateRelativePosition(this.wrapper.nativeElement, this.parentNode, 'top') + 'px'; this.wrapper.nativeElement.style.left = 'auto'; this.wrapper.nativeElement.style.position = 'relative'; break; case 'remain': if (this.wrapper.nativeElement.style.position !== 'fixed' || this.wrapper.nativeElement.style.position !== 'absolute') { this.wrapper.nativeElement.style.top = this.calculateRelativePosition(this.wrapper.nativeElement, this.parentNode, 'top') + 'px'; this.wrapper.nativeElement.style.left = 'auto'; this.wrapper.nativeElement.style.position = 'absolute'; // 要先转为absolute再计算,否则如果处于非fixed影响计算 } this.wrapper.nativeElement.style.top = this.calculateRemainPosition(this.wrapper.nativeElement, this.parentNode, this.container) + 'px'; this.wrapper.nativeElement.style.left = this.calculateRelativePosition(this.wrapper.nativeElement, this.parentNode, 'left') + 'px'; this.wrapper.nativeElement.style.position = 'relative'; break; default: break; } } /** * @param {?} element * @param {?} relativeElement * @param {?} direction * @return {?} */ calculateRelativePosition(element, relativeElement, direction) { /** @type {?} */ const key = { 'left': ['left', 'Left'], 'top': ['top', 'Top'] }; if (window && window.getComputedStyle) { /** @type {?} */ const computedStyle = window.getComputedStyle(relativeElement); return element.getBoundingClientRect()[key[direction][0]] - relativeElement.getBoundingClientRect()[key[direction][0]] - parseInt(computedStyle['padding' + key[direction][1]], 10) - parseInt(computedStyle['border' + key[direction][1] + 'Width'], 10); } } /** * @param {?} element * @param {?} relativeElement * @param {?} container * @return {?} */ calculateRemainPosition(element, relativeElement, container) { if (window && window.getComputedStyle) { /** @type {?} */ const computedStyle = window.getComputedStyle(container); /** @type {?} */ const result = container.getBoundingClientRect().height - element.getBoundingClientRect().height + container.getBoundingClientRect().top - relativeElement.getBoundingClientRect().top - parseInt(computedStyle['paddingTop'], 10) - parseInt(computedStyle['borderTopWidth'], 10) - parseInt(computedStyle['paddingBottom'], 10) - parseInt(computedStyle['borderBottomWidth'], 10); return result < 0 ? 0 : result; } } /** * @param {?} target * @return {?} */ initScrollStatus(target) { /** @type {?} */ const scrollTargets = target === window ? [document.documentElement, document.body] : [target]; /** @type {?} */ let flag = false; scrollTargets.forEach((/** * @param {?} scrollTarget * @return {?} */ scrollTarget => { if (scrollTarget.scrollTop && scrollTarget.scrollTop > 0) { flag = true; } })); if (flag) { setTimeout(this.scrollHandler); } } /** * 提供给业务自己触发 * 用法: * 1.捕获所有sticky:```\@ViewChildren(StickyComponent) stickies;``` * 2.触发刷新:当需要手动触发更新的时候,比如订阅数据返回后页面高度发生变化可以调用 ```stickies.forEach(sticky => sticky.recalculatePosition());``` * 慎用,少用, 使用太多会影响性能。 * @return {?} */ recalculatePosition() { this.initScrollStatus(this.scrollTarget); } } StickyComponent.decorators = [ { type: Component, args: [{ selector: 'd-sticky', template: ` <div #stickyWrapper [style.zIndex]="zIndex"> <ng-content></ng-content> </div> ` }] } ]; /** @nocollapse */ StickyComponent.ctorParameters = () => [ { type: ElementRef } ]; StickyComponent.propDecorators = { hostPosition: [{ type: HostBinding, args: ['style.position',] }], zIndex: [{ type: Input }], container: [{ type: Input }], view: [{ type: Input }], scrollTarget: [{ type: Input }], statusChange: [{ type: Output }], wrapper: [{ type: ViewChild, args: ['stickyWrapper', { static: true },] }], throttle: [{ type: HostListener, args: ['window:resize',] }] }; if (false) { /** @type {?} */ StickyComponent.prototype.hostPosition; /** @type {?} */ StickyComponent.prototype.zIndex; /** @type {?} */ StickyComponent.prototype.container; /** @type {?} */ StickyComponent.prototype.view; /** @type {?} */ StickyComponent.prototype.scrollTarget; /** @type {?} */ StickyComponent.prototype.statusChange; /** @type {?} */ StickyComponent.prototype.wrapper; /** @type {?} */ StickyComponent.prototype._prevStatus; /** @type {?} */ StickyComponent.prototype._status; /** @type {?} */ StickyComponent.prototype.parentNode; /** @type {?} */ StickyComponent.prototype.containerLeft; /** * @type {?} * @private */ StickyComponent.prototype.THROTTLE_DELAY; /** * @type {?} * @private */ StickyComponent.prototype.THROTTLE_TRIGGER; /** * @type {?} * @private */ StickyComponent.prototype.scrollPreStart; /** * @type {?} * @private */ StickyComponent.prototype.scrollTimer; /** @type {?} */ StickyComponent.prototype.throttle; /** @type {?} */ StickyComponent.prototype.scrollAndResizeHock; /** @type {?} */ StickyComponent.prototype.scrollHandler; /** * @type {?} * @private */ StickyComponent.prototype.el; } /** * @fileoverview added by tsickle * Generated from: sticky.module.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class StickyModule { } StickyModule.decorators = [ { type: NgModule, args: [{ imports: [], declarations: [ StickyComponent ], exports: [ StickyComponent, ], },] } ]; /** * @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-sticky.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ export { StickyComponent, StickyModule }; //# sourceMappingURL=ng-devui-sticky.js.map