初始化

This commit is contained in:
yuding
2025-12-24 19:02:34 +08:00
parent 4b5eb78bbb
commit 04a5e74284
51 changed files with 8576 additions and 5334 deletions

View File

@@ -183,6 +183,32 @@ export class BimButtonGroup implements IBimComponent {
if (this.options.iconActiveColor) style.setProperty('--bim-icon-active-color', this.options.iconActiveColor);
if (this.options.textColor) style.setProperty('--bim-btn-text-color', this.options.textColor);
if (this.options.textActiveColor) style.setProperty('--bim-btn-text-active-color', this.options.textActiveColor);
// 同步更新所有已存在的dropdown元素的CSS变量dropdown被添加到body无法继承容器的CSS变量
const dropdowns = document.querySelectorAll('.opt-btn-dropdown');
dropdowns.forEach(dropdown => {
const dropdownStyle = (dropdown as HTMLElement).style;
if (this.options.iconColor) dropdownStyle.setProperty('--bim-icon-color', this.options.iconColor);
if (this.options.iconActiveColor) dropdownStyle.setProperty('--bim-icon-active-color', this.options.iconActiveColor);
if (this.options.textColor) dropdownStyle.setProperty('--bim-btn-text-color', this.options.textColor);
if (this.options.textActiveColor) dropdownStyle.setProperty('--bim-btn-text-active-color', this.options.textActiveColor);
if (this.options.btnBackgroundColor) dropdownStyle.setProperty('--bim-btn-bg', this.options.btnBackgroundColor);
if (this.options.btnHoverColor) dropdownStyle.setProperty('--bim-btn-hover-bg', this.options.btnHoverColor);
if (this.options.btnActiveColor) dropdownStyle.setProperty('--bim-btn-active-bg', this.options.btnActiveColor);
});
}
/**
* 设置主题的primary颜色用于边框等
*/
private setPrimaryColor(color: string): void {
this.container.style.setProperty('--bim-primary-color', color);
// 同步更新所有dropdowndropdown被添加到body无法继承容器的CSS变量
const dropdowns = document.querySelectorAll('.opt-btn-dropdown');
dropdowns.forEach(dropdown => {
(dropdown as HTMLElement).style.setProperty('--bim-primary-color', color);
});
}
/**
@@ -210,6 +236,7 @@ export class BimButtonGroup implements IBimComponent {
});
this.applyStyles();
this.setPrimaryColor(theme.primary);
}
/**
@@ -339,6 +366,10 @@ export class BimButtonGroup implements IBimComponent {
const hasLabel = this.options.showLabel && button.label;
if (!hasLabel) {
btnEl.classList.add('no-label');
// 当不显示 label 时,添加 title 属性作为 tooltip
if (button.label) {
btnEl.title = t(button.label);
}
}
// 应用按钮的自定义样式
@@ -412,13 +443,64 @@ export class BimButtonGroup implements IBimComponent {
if (button.disabled) return;
if (!button.children || button.children.length === 0) {
if (button.keepActive) {
this.setBtnActive(button.id);
// 1) 先切换自身激活状态onClick 里通常会根据 isActive 决定“打开/关闭”逻辑)
const wasActive = this.activeBtnIds.has(button.id);
const newState = !wasActive;
this.setBtnActive(button.id, newState);
// 2) 互斥逻辑:仅在“本次切换为激活”时触发
// - 一级按钮:同 groupId 下其它一级按钮互斥
// - 二级按钮:同 groupId + 同 parentId 下其它二级按钮互斥
// - 被关闭的按钮需要触发 onClick用于执行关闭逻辑
if (newState && button.exclusive && button.groupId) {
this.deactivateExclusiveSiblings(button);
}
}
this.closeDropdown();
if (button.onClick) button.onClick(button);
}
}
/**
* 互斥关闭同范围内的其它已激活按钮,并触发它们的 onClick
* @param button 当前被激活的按钮
*/
private deactivateExclusiveSiblings(button: OptButton): void {
const group = this.groups.find(g => g.id === button.groupId);
if (!group) return;
// 二级按钮:同 groupId + 同 parentId
if (button.parentId) {
const parent = this.findButton(group.buttons, button.parentId);
const siblings = parent?.children || [];
for (const sib of siblings) {
if (!sib) continue;
if (sib.id === button.id) continue;
if (sib.parentId !== button.parentId) continue;
if (sib.groupId !== button.groupId) continue;
if (this.activeBtnIds.has(sib.id)) {
this.setBtnActive(sib.id, false);
// 触发被关闭按钮的 onClick此时 sib.isActive 已经同步为 false
if (sib.onClick) sib.onClick(sib);
}
}
return;
}
// 一级按钮:同 groupId 下其它一级按钮(不包含二级)
for (const sib of group.buttons) {
if (sib.id === button.id) continue;
if (sib.groupId !== button.groupId) continue;
if (sib.parentId) continue; // 只处理一级按钮
if (this.activeBtnIds.has(sib.id)) {
this.setBtnActive(sib.id, false);
if (sib.onClick) sib.onClick(sib);
}
}
}
private handleMouseEnter(button: OptButton, btnEl: HTMLElement): void {
if (this.hoverTimeout) clearTimeout(this.hoverTimeout);
if (button.children && button.children.length > 0) {
@@ -440,6 +522,16 @@ export class BimButtonGroup implements IBimComponent {
dropdown.className = 'opt-btn-dropdown';
if (this.options.backgroundColor) dropdown.style.setProperty('--bim-toolbar-bg', this.options.backgroundColor);
// 将主题CSS变量复制到dropdown元素上因为dropdown被添加到body无法继承容器的CSS变量
const dropdownStyle = dropdown.style;
if (this.options.iconColor) dropdownStyle.setProperty('--bim-icon-color', this.options.iconColor);
if (this.options.iconActiveColor) dropdownStyle.setProperty('--bim-icon-active-color', this.options.iconActiveColor);
if (this.options.textColor) dropdownStyle.setProperty('--bim-btn-text-color', this.options.textColor);
if (this.options.textActiveColor) dropdownStyle.setProperty('--bim-btn-text-active-color', this.options.textActiveColor);
if (this.options.btnBackgroundColor) dropdownStyle.setProperty('--bim-btn-bg', this.options.btnBackgroundColor);
if (this.options.btnHoverColor) dropdownStyle.setProperty('--bim-btn-hover-bg', this.options.btnHoverColor);
if (this.options.btnActiveColor) dropdownStyle.setProperty('--bim-btn-active-bg', this.options.btnActiveColor);
// 获取按钮的位置信息
const btnRect = btnEl.getBoundingClientRect();
const expand = this.options.expand || 'down';
@@ -503,6 +595,14 @@ export class BimButtonGroup implements IBimComponent {
item.classList.add('align-vertical');
}
// 二级菜单项的 active 状态渲染(修复 keepActive 在二级按钮“看起来不生效”的问题)
// 说明:
// - keepActive 的状态会记录在 activeBtnIds / button.isActive 上
// - 下拉菜单每次打开都会重新渲染,因此必须在这里同步一次 active 样式
if (this.activeBtnIds.has(button.id) || button.isActive) {
item.classList.add('active');
}
// 应用按钮的自定义样式
const iconSize = button.iconSize || 32; // 二级菜单默认图标更小
const minWidth = button.minWidth; // 不设置默认值,让下拉菜单项保持紧凑
@@ -523,6 +623,9 @@ export class BimButtonGroup implements IBimComponent {
label.className = 'opt-btn-dropdown-label';
label.textContent = t(button.label);
item.appendChild(label);
} else if (button.label) {
// 当不显示 label 时,添加 title 属性作为 tooltip
item.title = t(button.label);
}
item.addEventListener('click', (e) => { e.stopPropagation(); this.handleClick(button); });
@@ -572,11 +675,17 @@ export class BimButtonGroup implements IBimComponent {
const hasLabel = this.options.showLabel && button.label;
// 只需要更新 no-label 类CSS 会处理显示/隐藏
// 更新 no-label 类和 title 属性
if (hasLabel) {
btnEl.classList.remove('no-label');
// 显示标签时,移除 title避免重复显示
btnEl.removeAttribute('title');
} else {
btnEl.classList.add('no-label');
// 隐藏标签时,添加 title 作为 tooltip
if (button.label) {
btnEl.title = t(button.label);
}
}
});
}