ng-cw-v12
Version:
Angular UI component library
273 lines (267 loc) • 12.5 kB
JavaScript
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