UNPKG

ng-cw-v12

Version:

Angular UI component library

273 lines (267 loc) 12.5 kB
import * as i0 from '@angular/core'; import { Directive, Input, NgModule } from '@angular/core'; class RibbonDirective { constructor(el, renderer) { this.el = el; this.renderer = renderer; this.ncContent = ''; this.ncContentColor = '#fff'; this.ncSize = 0.3; // 修改为百分比值,默认为容器宽高较小值的30% this.ncRibbonColor = '#ff6547'; this.ncPosition = 'top-left'; // 生成唯一ID this.uniqueId = `ribbon_${Math.random().toString(36).substring(2, 11)}`; } ngOnInit() { this.createRibbonContainer(); } createRibbonContainer() { const elementPosition = this.el.nativeElement.style.position; if (!elementPosition || elementPosition === 'static') { this.renderer.setStyle(this.el.nativeElement, 'position', 'relative'); } // 创建丝带容器 this.ribbonContainer = this.renderer.createElement('div'); this.renderer.addClass(this.ribbonContainer, this.uniqueId); this.renderer.setStyle(this.ribbonContainer, 'position', 'absolute'); this.renderer.setStyle(this.ribbonContainer, 'overflow', 'hidden'); this.renderer.setStyle(this.ribbonContainer, 'display', 'flex'); this.renderer.setStyle(this.ribbonContainer, 'justify-content', 'center'); this.renderer.setStyle(this.ribbonContainer, 'align-items', 'center'); // 添加到DOM this.renderer.appendChild(this.el.nativeElement, this.ribbonContainer); // 初始渲染 this.updateRibbonSize(); // 使用MutationObserver监听父容器尺寸变化 this.observeParentSize(); } updateRibbonSize() { // 获取父容器的尺寸 const parentWidth = this.el.nativeElement.offsetWidth; const parentHeight = this.el.nativeElement.offsetHeight; // 如果父容器尺寸为0,延迟重试 if (parentWidth === 0 || parentHeight === 0) { setTimeout(() => this.updateRibbonSize(), 100); return; } this.ribbonSize = Math.min(parentWidth, parentHeight) * this.ncSize; // 更新丝带容器尺寸 this.renderer.setStyle(this.ribbonContainer, 'width', `${this.ribbonSize}px`); this.renderer.setStyle(this.ribbonContainer, 'height', `${this.ribbonSize}px`); // 更新位置 const offset = -(this.ribbonSize * 0.06); switch (this.ncPosition) { case 'top-right': this.renderer.setStyle(this.ribbonContainer, 'top', `${offset}px`); this.renderer.setStyle(this.ribbonContainer, 'right', `${offset}px`); break; case 'bottom-left': this.renderer.setStyle(this.ribbonContainer, 'bottom', `${offset}px`); this.renderer.setStyle(this.ribbonContainer, 'left', `${offset}px`); break; case 'bottom-right': this.renderer.setStyle(this.ribbonContainer, 'bottom', `${offset}px`); this.renderer.setStyle(this.ribbonContainer, 'right', `${offset}px`); break; default: //top-left this.renderer.setStyle(this.ribbonContainer, 'top', `${offset}px`); this.renderer.setStyle(this.ribbonContainer, 'left', `${offset}px`); break; } // 更新CSS样式 this.updateRibbonStyles(); } updateRibbonStyles() { // 根据输入的颜色计算渐变色 const mainColor = this.ncRibbonColor; const lighterColor = this.adjustColor(this.ncRibbonColor, 45); const darkerColor = this.adjustColor(this.ncRibbonColor, -10); const cssText = ` .${this.uniqueId}::before { content: '${this.ncContent}'; position: absolute; width: 150%; height: ${this.ribbonSize * 0.3}px; background: linear-gradient(45deg, ${mainColor} 0%, ${lighterColor} 51%, ${darkerColor} 100%); transform: rotate(${this.getRotationDegree()}) translateY(${-this.ribbonSize * 0.16}px) ${this.getTextRotation()}; display: flex; align-items: center; justify-content: center; color: ${this.ncContentColor}; font-weight: 600; font-size: ${Math.ceil(this.ribbonSize * 0.18)}px; letter-spacing: 0.1em; box-shadow: ${this.getRibbonShadow()}; } .${this.uniqueId}::after { content: ''; position: absolute; width: ${this.ribbonSize * 0.1}px; height: ${this.ribbonSize * 0.1}px; z-index: -1; ${this.getShadowPosition()} background: linear-gradient(45deg, ${mainColor} 0%, ${lighterColor} 51%, ${mainColor} 100%); } `; // 移除旧样式(如果存在) const oldStyle = document.querySelector(`style[data-ribbon-id="${this.uniqueId}"]`); if (oldStyle) { oldStyle.remove(); } // 添加新样式 const styleElement = this.renderer.createElement('style'); this.renderer.setAttribute(styleElement, 'data-ribbon-id', this.uniqueId); this.renderer.appendChild(styleElement, this.renderer.createText(cssText)); this.renderer.appendChild(document.head, styleElement); } // 添加颜色调整方法 adjustColor(color, percent) { // 确保颜色值格式统一,移除可能存在的 # 号 const hex = color.replace(/^#/, ''); // 验证颜色值格式(6位或8位) if (!/^[0-9A-Fa-f]{6}([0-9A-Fa-f]{2})?$/.test(hex)) { console.warn('Invalid color format. Using default color.'); return '#ff6547'; } // 分离颜色值和透明度 const colorHex = hex.slice(0, 6); const alpha = hex.length === 8 ? hex.slice(6, 8) : ''; const r = parseInt(colorHex.substring(0, 2), 16); const g = parseInt(colorHex.substring(2, 4), 16); const b = parseInt(colorHex.substring(4, 6), 16); const adjustValue = (value) => { const newValue = value + (value * percent / 100); return Math.min(255, Math.max(0, Math.round(newValue))); }; const nr = adjustValue(r); const ng = adjustValue(g); const nb = adjustValue(b); // 如果原始颜色包含透明度,则在结果中也包含透明度 return `#${nr.toString(16).padStart(2, '0')}${ng.toString(16).padStart(2, '0')}${nb.toString(16).padStart(2, '0')}${alpha}`; } // 添加获取旋转角度的方法 getRotationDegree() { switch (this.ncPosition) { case 'top-right': return '45deg'; case 'bottom-left': return '-135deg'; case 'bottom-right': return '135deg'; default: // top-left return '-45deg'; } } // 添加获取文字旋转的方法 getTextRotation() { switch (this.ncPosition) { case 'bottom-left': case 'bottom-right': return 'rotate(180deg)'; default: return ''; } } // 添加获取丝带阴影的方法 getRibbonShadow() { switch (this.ncPosition) { case 'bottom-left': case 'bottom-right': return `0 -${this.ribbonSize * 0.05}px ${this.ribbonSize * 0.1}px rgba(0, 0, 0, 0.23)`; default: return `0 ${this.ribbonSize * 0.05}px ${this.ribbonSize * 0.1}px rgba(0, 0, 0, 0.23)`; } } // 添加获取阴影位置的方法 getShadowPosition() { const shadowSize = this.ribbonSize * 0.9 + 'px'; const shadowColor = this.adjustColor(this.ncRibbonColor, -20); switch (this.ncPosition) { case 'top-right': return `bottom: 0; right: 0; box-shadow: -${shadowSize} -${shadowSize} ${shadowColor};`; case 'bottom-left': return `top: 0; left: 0; box-shadow: ${shadowSize} ${shadowSize} ${shadowColor};`; case 'bottom-right': return `top: 0; right: 0; box-shadow: -${shadowSize} ${shadowSize} ${shadowColor};`; default: // top-left return `bottom: 0; left: 0; box-shadow: ${shadowSize} -${shadowSize} ${shadowColor};`; } } // 监听父容器尺寸变化 observeParentSize() { // 使用ResizeObserver监听尺寸变化(现代浏览器支持) if (typeof ResizeObserver !== 'undefined') { const resizeObserver = new ResizeObserver(() => { this.updateRibbonSize(); }); resizeObserver.observe(this.el.nativeElement); } else { // 降级方案:使用MutationObserver监听DOM变化 const observer = new MutationObserver(() => { this.updateRibbonSize(); }); observer.observe(this.el.nativeElement, { childList: true, subtree: true, attributes: true }); // 额外的安全措施:定期检查尺寸变化 let lastWidth = this.el.nativeElement.offsetWidth; let lastHeight = this.el.nativeElement.offsetHeight; const checkSizeInterval = setInterval(() => { const currentWidth = this.el.nativeElement.offsetWidth; const currentHeight = this.el.nativeElement.offsetHeight; if (currentWidth !== lastWidth || currentHeight !== lastHeight) { lastWidth = currentWidth; lastHeight = currentHeight; this.updateRibbonSize(); } }, 500); // 组件销毁时清除定时器 this.el.nativeElement.addEventListener('DOMNodeRemoved', () => { clearInterval(checkSizeInterval); }); } } } RibbonDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: RibbonDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive }); RibbonDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "12.1.5", type: RibbonDirective, selector: "[ncRibbon]", inputs: { ncContent: "ncContent", ncContentColor: "ncContentColor", ncSize: "ncSize", ncRibbonColor: "ncRibbonColor", ncPosition: "ncPosition" }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: RibbonDirective, decorators: [{ type: Directive, args: [{ selector: '[ncRibbon]' }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }]; }, propDecorators: { ncContent: [{ type: Input }], ncContentColor: [{ type: Input }], ncSize: [{ type: Input }], ncRibbonColor: [{ type: Input }], ncPosition: [{ type: Input }] } }); class NcRibbonModule { } NcRibbonModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcRibbonModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); NcRibbonModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcRibbonModule, declarations: [RibbonDirective], exports: [RibbonDirective] }); NcRibbonModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcRibbonModule, imports: [[]] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcRibbonModule, decorators: [{ type: NgModule, args: [{ declarations: [ RibbonDirective ], imports: [], exports: [ RibbonDirective ] }] }] }); /** * Generated bundle index. Do not edit. */ export { NcRibbonModule, RibbonDirective }; //# sourceMappingURL=ng-cw-v12-ribbon.js.map