ng-devui
Version:
DevUI components based on Angular
248 lines (243 loc) • 15.4 kB
JavaScript
import * as i1 from '@angular/common';
import { DOCUMENT, CommonModule } from '@angular/common';
import * as i0 from '@angular/core';
import { EventEmitter, Component, ChangeDetectionStrategy, Inject, Input, Output, HostListener, NgModule } from '@angular/core';
import { Subscription, fromEvent } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
class BackTopComponent {
constructor(cdr, el, doc) {
this.cdr = cdr;
this.el = el;
this.doc = doc;
this.visibleHeight = 300;
this.bottom = '50px';
this.right = '30px';
this.draggable = false;
this.backTopEvent = new EventEmitter();
this.dragEvent = new EventEmitter();
this.currScrollTop = 0;
this.duration = 0;
this.moveCursor = false;
this.moveToggle = false;
this.isVisible = false;
this.subs = new Subscription();
this.SCROLL_REFRESH_INTERVAL = 100;
this.MOUSEDOWN_DELAY = 180;
this.RESIZE_DELAY = 300;
this.document = this.doc;
}
ngOnChanges(changes) {
if (changes.scrollTarget) {
if (this.subs) {
this.subs.unsubscribe();
}
this.subs = new Subscription();
this.addScrollEvent();
}
}
ngOnInit() {
this.addScrollEvent();
this.showButton();
}
ngAfterViewInit() {
if (this.draggable) {
// 窗口大小改变时,如缩放比例或组件超出显示范围重置到默认位置
this.subs.add(fromEvent(window, 'resize')
.pipe(debounceTime(this.RESIZE_DELAY))
.subscribe(() => {
const dom = this.dragBoundary?.dom || this.el.nativeElement.querySelector('div.devui-backtop');
if (dom) {
// 不显示时无法获取getBoundingClientRect,使用style获取
const style = getComputedStyle(dom);
const left = parseInt(style.left, 10) || 0;
const top = parseInt(style.top, 10) || 0;
if (window.devicePixelRatio !== 1 || left > window.innerWidth || top > window.innerHeight) {
this.onMouseUp();
this.duration = 0;
dom.style.left = 'unset';
dom.style.top = 'unset';
}
}
}));
}
}
ngOnDestroy() {
if (this.subs) {
this.subs.unsubscribe();
}
}
addScrollEvent() {
this.subs.add(fromEvent(this.getScrollTarget(), 'scroll')
.pipe(debounceTime(this.SCROLL_REFRESH_INTERVAL))
.subscribe(() => {
this.showButton();
this.cdr.detectChanges();
}));
}
getScrollTarget() {
if (this.scrollTarget) {
this.el.nativeElement.querySelector('.devui-backtop').style.position = 'absolute';
this.scrollTarget.parentElement.style.position = 'relative';
}
this.target = this.scrollTarget || window;
return this.target;
}
showButton() {
this.currScrollTop =
this.target === window
? window.pageYOffset || this.document.documentElement.scrollTop || this.document.body.scrollTop
: this.scrollTarget.scrollTop;
if (this.isVisible !== this.currScrollTop >= this.visibleHeight) {
this.isVisible = !this.isVisible;
}
}
goTop() {
if (this.draggable && this.duration > this.MOUSEDOWN_DELAY) {
this.duration = 0;
return;
}
if (this.target === window) {
this.document.documentElement.scrollIntoView({ behavior: 'smooth', block: 'start', inline: 'nearest' });
this.document.body.scrollIntoView({ behavior: 'smooth', block: 'start', inline: 'nearest' });
}
else {
this.scrollTarget.style.scrollBehavior = 'smooth';
this.scrollTarget.scrollTop = 0;
}
this.duration = 0;
this.backTopEvent.emit(true);
}
setDragBoundary() {
const dom = this.el.nativeElement.querySelector('div.devui-backtop');
let boxRect;
let minLeft;
let minTop;
let maxLeft;
let maxTop;
if (dom) {
const { width, height } = dom.getBoundingClientRect();
if (this.scrollTarget) {
boxRect = this.scrollTarget.getBoundingClientRect();
minLeft = -1 * boxRect.x;
minTop = -1 * boxRect.y;
maxLeft = window.innerWidth - boxRect.x - width;
maxTop = window.innerHeight - boxRect.y - height;
}
else {
boxRect = { x: 0, y: 0 };
minLeft = 0;
minTop = 0;
maxLeft = window.innerWidth - width;
maxTop = window.innerHeight - height;
}
this.dragBoundary = { dom, boxRect, minLeft, minTop, maxLeft, maxTop };
}
}
// mousedown mouseup click 按顺序触发且前一个结束触发下一个
mousedownEvent(event) {
if (this.draggable) {
event.preventDefault();
this.setDragBoundary();
this.duration = new Date().getTime();
this.moveToggle = true;
this.cursorTimer = setTimeout(() => {
this.moveCursor = true;
this.dragEvent.emit(true);
}, this.MOUSEDOWN_DELAY);
}
}
mouseleaveEvent() {
if (this.draggable && this.cursorTimer) {
clearTimeout(this.cursorTimer);
}
}
onMouseUp() {
if (this.draggable) {
if (this.cursorTimer) {
clearTimeout(this.cursorTimer);
}
if (this.moveToggle) {
this.moveToggle = false;
this.moveCursor = false;
this.dragEvent.emit(false);
}
this.duration = this.duration && new Date().getTime() - this.duration;
}
}
onMouseMove(event) {
if (this.draggable && this.moveToggle && this.dragBoundary) {
// 先判断再执行阻止默认事件,否则可能影响鼠标拖选功能
event.preventDefault();
this.moveCursor = true;
const posX = event.movementX;
const posY = event.movementY;
const rect = this.dragBoundary.dom.getBoundingClientRect();
const left = rect.x - this.dragBoundary.boxRect.x + posX;
const top = rect.y - this.dragBoundary.boxRect.y + posY;
const isLeft = left < this.dragBoundary.minLeft;
const isRight = left > this.dragBoundary.maxLeft;
const isTop = top < this.dragBoundary.minTop;
const isBottom = top > this.dragBoundary.maxTop;
const leftResult = isLeft ? this.dragBoundary.minLeft : left;
const topResult = isTop ? this.dragBoundary.minTop : top;
this.dragBoundary.dom.style.left = `${isRight ? this.dragBoundary.maxLeft : leftResult}px`;
this.dragBoundary.dom.style.top = `${isBottom ? this.dragBoundary.maxTop : topResult}px`;
// 如到达边界释放拖拽动作,避免鼠标偏移较大距离后返回主视窗仍可拖拽
if ([isLeft, isRight, isTop, isBottom].includes(true)) {
this.onMouseUp();
this.duration = 0;
}
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BackTopComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: BackTopComponent, selector: "d-back-top", inputs: { customTemplate: "customTemplate", visibleHeight: "visibleHeight", bottom: "bottom", right: "right", scrollTarget: "scrollTarget", draggable: "draggable" }, outputs: { backTopEvent: "backTopEvent", dragEvent: "dragEvent" }, host: { listeners: { "document:mouseup": "onMouseUp()", "document:mousemove": "onMouseMove($event)" } }, usesOnChanges: true, ngImport: i0, template: "<div\n class=\"devui-backtop\"\n [ngStyle]=\"{\n display: isVisible ? 'block' : 'none',\n bottom: bottom,\n right: right,\n cursor: moveCursor && draggable ? 'move' : 'pointer'\n }\"\n (click)=\"goTop()\"\n>\n <div class=\"devui-backtop-drag-handle\" (mousedown)=\"mousedownEvent($event)\" (mouseleave)=\"mouseleaveEvent()\">\n <ng-template [ngTemplateOutlet]=\"customTemplate ? customTemplate : default\"></ng-template>\n <ng-template #default>\n <div class=\"devui-backtop-content\">\n <svg\n width=\"16px\"\n height=\"16px\"\n viewBox=\"0 0 16 16\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n >\n <g stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\n <path\n d=\"M8.71335931,15.2865297 C8.61179683,16.2090609 7.32293758,16.1267953 7.27304695,15.2865297 C7.27175008,14.6475142 7.27175008,5.26479636 7.27175008,5.26479636 L2.83675052,9.54548344 C2.14185995,10.1440615 1.3143288,9.18731159 1.83135998,8.55773353 C3.79557855,6.65310872 7.3202657,3.24515592 7.40179694,3.16632781 C7.72696878,2.81306222 8.23887498,2.79476534 8.58495308,3.16632781 C9.23193739,3.7919215 14.0334057,8.42146792 14.1791557,8.58804603 C14.66614,9.19338972 13.8787807,10.0892021 13.2066089,9.58451469 C13.0329683,9.43717095 8.71468744,5.26462448 8.71468744,5.26462448 L8.71335931,15.2865297 Z M1.81868811,-8.54871729e-14 L14.1075619,-8.54871729e-14 L14.1075619,1.39509361 L1.81868811,1.39509361 L1.81868811,-8.54871729e-14 Z\"\n fill=\"#FFFFFF\"\n fill-rule=\"nonzero\"\n ></path>\n </g>\n </svg>\n </div>\n </ng-template>\n </div>\n</div>\n", styles: [".devui-backtop{width:40px;height:40px;position:fixed;z-index:1}.devui-backtop .devui-backtop-drag-handle{cursor:unset!important}.devui-backtop-content{width:40px;height:40px;background-color:var(--devui-text-weak, #333333);opacity:.4;border-radius:50%;display:flex;align-items:center;justify-content:center}.devui-backtop-content:hover{opacity:1}\n"], dependencies: [{ kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BackTopComponent, decorators: [{
type: Component,
args: [{ selector: 'd-back-top', changeDetection: ChangeDetectionStrategy.OnPush, preserveWhitespaces: false, template: "<div\n class=\"devui-backtop\"\n [ngStyle]=\"{\n display: isVisible ? 'block' : 'none',\n bottom: bottom,\n right: right,\n cursor: moveCursor && draggable ? 'move' : 'pointer'\n }\"\n (click)=\"goTop()\"\n>\n <div class=\"devui-backtop-drag-handle\" (mousedown)=\"mousedownEvent($event)\" (mouseleave)=\"mouseleaveEvent()\">\n <ng-template [ngTemplateOutlet]=\"customTemplate ? customTemplate : default\"></ng-template>\n <ng-template #default>\n <div class=\"devui-backtop-content\">\n <svg\n width=\"16px\"\n height=\"16px\"\n viewBox=\"0 0 16 16\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n >\n <g stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\n <path\n d=\"M8.71335931,15.2865297 C8.61179683,16.2090609 7.32293758,16.1267953 7.27304695,15.2865297 C7.27175008,14.6475142 7.27175008,5.26479636 7.27175008,5.26479636 L2.83675052,9.54548344 C2.14185995,10.1440615 1.3143288,9.18731159 1.83135998,8.55773353 C3.79557855,6.65310872 7.3202657,3.24515592 7.40179694,3.16632781 C7.72696878,2.81306222 8.23887498,2.79476534 8.58495308,3.16632781 C9.23193739,3.7919215 14.0334057,8.42146792 14.1791557,8.58804603 C14.66614,9.19338972 13.8787807,10.0892021 13.2066089,9.58451469 C13.0329683,9.43717095 8.71468744,5.26462448 8.71468744,5.26462448 L8.71335931,15.2865297 Z M1.81868811,-8.54871729e-14 L14.1075619,-8.54871729e-14 L14.1075619,1.39509361 L1.81868811,1.39509361 L1.81868811,-8.54871729e-14 Z\"\n fill=\"#FFFFFF\"\n fill-rule=\"nonzero\"\n ></path>\n </g>\n </svg>\n </div>\n </ng-template>\n </div>\n</div>\n", styles: [".devui-backtop{width:40px;height:40px;position:fixed;z-index:1}.devui-backtop .devui-backtop-drag-handle{cursor:unset!important}.devui-backtop-content{width:40px;height:40px;background-color:var(--devui-text-weak, #333333);opacity:.4;border-radius:50%;display:flex;align-items:center;justify-content:center}.devui-backtop-content:hover{opacity:1}\n"] }]
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: undefined, decorators: [{
type: Inject,
args: [DOCUMENT]
}] }], propDecorators: { customTemplate: [{
type: Input
}], visibleHeight: [{
type: Input
}], bottom: [{
type: Input
}], right: [{
type: Input
}], scrollTarget: [{
type: Input
}], draggable: [{
type: Input
}], backTopEvent: [{
type: Output
}], dragEvent: [{
type: Output
}], onMouseUp: [{
type: HostListener,
args: ['document:mouseup', []]
}], onMouseMove: [{
type: HostListener,
args: ['document:mousemove', ['$event']]
}] } });
class BackTopModule {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BackTopModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.13", ngImport: i0, type: BackTopModule, declarations: [BackTopComponent], imports: [CommonModule], exports: [BackTopComponent] }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BackTopModule, imports: [CommonModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BackTopModule, decorators: [{
type: NgModule,
args: [{
imports: [
CommonModule
],
exports: [BackTopComponent],
declarations: [BackTopComponent]
}]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { BackTopComponent, BackTopModule };
//# sourceMappingURL=ng-devui-back-top.mjs.map