@duoduo-oba/ng-devui
Version:
DevUI components based on Angular
359 lines (353 loc) • 12.9 kB
JavaScript
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