// ==UserScript==
// @name SideBarButtonLibrary
// @namespace
// @version 2.0.0
// @description SideBarButtonLibrary 是一个轻量级的 JavaScript 库,用于创建可展开和收起的侧边栏按钮容器,支持自定义吸附方向(左、右、上、下)、按钮排列方式(水平或垂直)以及样式,适用于快速构建侧边栏工具栏或导航菜单。
// @author otc
// @match *
// @license MIT
// ==/UserScript==
const SideBarButtonLibrary = (function() {
// 默认配置
const defaultConfig = {
// 容器默认样式
container: {
width: '5px', // 收起时宽度/高度
expandedWidth: '150px', // 展开时宽度
backgroundColor: 'rgba(0, 0, 0, 0.1)',
transition: 'width 0.3s ease',
className: 'sidebar-button-container', // 默认类名
position: 'left', // 吸附位置:left/right/top/bottom
flexDirection: 'column' // 排列方向:row/column
},
// 按钮默认样式
buttonStyles: {
width: '140px',
background: '#007bff',
color: '#fff',
borderRadius: '4px',
fontSize: '14px',
cursor: 'pointer',
transition: 'background 0.2s ease',
hoverBackground: '#0056b3', // 悬停背景颜色
defaultBackground: '#007bff' // 默认背景颜色
},
// 删除按钮默认样式
deleteButtonStyles: {
right: '-30px', // 收起时位置
expandedRight: '10px', // 展开时位置
background: 'rgba(222, 55, 48, 0.8)',
color: '#fff',
borderRadius: '5px',
cursor: 'pointer',
transition: 'right 0.3s ease',
padding: '5px 10px', // 默认内边距
fontSize: '14px', // 默认字体大小
border: 'none' // 默认边框样式
},
// 动作延迟
hoverDelay: 500, // 悬停后展开延迟
hideDelay: 1000 // 移出后收起延迟
};
// 私有函数:获取默认容器样式
function getDefaultContainerStyles(config) {
const baseStyles = {
position: 'fixed',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
overflow: 'hidden',
zIndex: 10000,
backgroundColor: config.container.backgroundColor,
transition: config.container.transition
};
// 根据吸附位置调整样式
switch (config.container.position) {
case 'left':
baseStyles.left = '0';
baseStyles.top = '0';
baseStyles.height = '100%';
baseStyles.width = config.container.width;
break;
case 'right':
baseStyles.right = '0';
baseStyles.top = '0';
baseStyles.height = '100%';
baseStyles.width = config.container.width;
break;
case 'top':
baseStyles.top = '0';
baseStyles.left = '0';
baseStyles.width = '100%';
baseStyles.height = config.container.width;
break;
case 'bottom':
baseStyles.bottom = '0';
baseStyles.left = '0';
baseStyles.width = '100%';
baseStyles.height = config.container.width;
break;
}
return baseStyles;
}
// 私有函数:创建或获取容器
function getOrCreateButtonContainer(config) {
let container = document.querySelector(`.${config.container.className}`);
if (!container) {
container = document.createElement('div');
container.className = config.container.className;
const styles = getDefaultContainerStyles(config);
for (const [key, value] of Object.entries(styles)) {
container.style[key] = value;
}
// 设置按钮排列方向
container.style.flexDirection = config.container.flexDirection;
// 创建删除按钮
const deleteButton = document.createElement('button');
deleteButton.className = 'delete-button';
deleteButton.innerHTML = '<span class="button-text">×</span>';
deleteButton.style.position = 'absolute';
// 根据吸附位置调整删除按钮的位置
switch (config.container.position) {
case 'left':
case 'right':
deleteButton.style.top = '10px';
deleteButton.style.right = config.deleteButtonStyles.right;
break;
case 'top':
deleteButton.style.right = '10px';
deleteButton.style.bottom = config.deleteButtonStyles.expandedRight;
break;
case 'bottom':
deleteButton.style.right = '10px';
deleteButton.style.top = config.deleteButtonStyles.expandedRight;
break;
}
// 应用用户自定义的删除按钮样式
const deleteStyles = { ...defaultConfig.deleteButtonStyles, ...config.deleteButtonStyles };
for (const [key, value] of Object.entries(deleteStyles)) {
deleteButton.style[key] = value;
}
deleteButton.addEventListener('click', () => {
container.remove();
});
container.appendChild(deleteButton);
// 鼠标悬停事件
container.addEventListener('mouseenter', () => {
clearTimeout(container.expandTimeout);
clearTimeout(container.hideTimeout);
container.expandTimeout = setTimeout(() => {
if (config.container.position === 'left' || config.container.position === 'right') {
container.style.width = config.container.expandedWidth;
} else {
container.style.height = config.container.expandedWidth;
}
deleteButton.style.right = config.deleteButtonStyles.expandedRight;
container.querySelectorAll('.button-text').forEach(text => {
text.style.opacity = 1;
});
}, config.hoverDelay);
});
// 鼠标移出事件
container.addEventListener('mouseleave', () => {
clearTimeout(container.expandTimeout);
container.hideTimeout = setTimeout(() => {
if (config.container.position === 'left' || config.container.position === 'right') {
container.style.width = config.container.width;
} else {
container.style.height = config.container.width;
}
deleteButton.style.right = config.deleteButtonStyles.right;
container.querySelectorAll('.button-text').forEach(text => {
text.style.opacity = 0;
});
}, config.hideDelay);
});
document.body.appendChild(container);
}
return container;
}
// 公开接口:创建按钮
function createButtons(buttons, config = {}) {
const finalConfig = { ...defaultConfig, ...config };
const container = getOrCreateButtonContainer(finalConfig);
buttons.forEach((button, index) => {
const buttonElement = document.createElement('button');
buttonElement.innerHTML = `<span class="button-text">${button.name}</span>`;
buttonElement.style.margin = '2px 0';
buttonElement.style.width = finalConfig.buttonStyles.width;
buttonElement.style.border = 'none';
buttonElement.style.background = finalConfig.buttonStyles.defaultBackground;
buttonElement.style.color = finalConfig.buttonStyles.color;
buttonElement.style.borderRadius = finalConfig.buttonStyles.borderRadius;
buttonElement.style.fontSize = finalConfig.buttonStyles.fontSize;
buttonElement.style.cursor = finalConfig.buttonStyles.cursor;
buttonElement.style.transition = finalConfig.buttonStyles.transition;
const buttonText = buttonElement.querySelector('.button-text');
buttonText.style.opacity = 0;
buttonText.style.transition = 'opacity 0.3s ease';
// 使用配置中的悬停和默认样式
buttonElement.addEventListener('mouseover', () => {
buttonElement.style.background = finalConfig.buttonStyles.hoverBackground;
});
buttonElement.addEventListener('mouseout', () => {
buttonElement.style.background = finalConfig.buttonStyles.defaultBackground;
});
buttonElement.addEventListener('click', button.func);
container.appendChild(buttonElement);
});
}
// 暴露公共接口
return {
createButtons: createButtons
};
})();
// 使用示例
// SideBarButtonLibrary.createButtons([
// { name: 'Button 1', func: () => alert('Button 1 clicked') },
// { name: 'Button 2', func: () => alert('Button 2 clicked') }
// ], {
// container: {
// width: '5px', // 自定义收起宽度/高度
// expandedWidth: '200px', // 自定义展开宽度
// backgroundColor: 'rgba(0, 0, 0, 0.2)', // 自定义背景颜色
// className: 'my-custom-sidebar-container', // 自定义容器类名
// position: 'top', // 吸附到顶部
// flexDirection: 'row' // 按钮水平排列
// },
// buttonStyles: {
// width: '180px', // 自定义按钮宽度
// background: '#ff5722', // 自定义按钮默认背景
// hoverBackground: '#cc4400', // 自定义按钮悬停背景
// defaultBackground: '#ff5722' // 自定义按钮默认背景
// },
// deleteButtonStyles: {
// right: '-40px', // 自定义收起时删除按钮位置
// expandedRight: '20px', // 自定义展开时删除按钮位置
// background: 'rgba(255, 0, 0, 0.8)', // 自定义删除按钮背景颜色
// color: '#000' // 自定义删除按钮字体颜色
// },
// hoverDelay: 300, // 自定义悬停延迟
// hideDelay: 800 // 自定义隐藏延迟
// });