在现代Web应用中,主题切换已经成为提升用户体验的重要功能。本文将详细介绍如何在基于AntV X6的图编辑器中实现主题切换功能
我正在做的开源项目:du-editor,一个基于X6的图编辑器
切换主题效果

主题系统设计
1. 主题配置结构
首先,我们需要设计一个灵活的主题配置结构,包含画布、节点、边和文本等各个方面的样式定义:
typescript
themes = {
default: {
name: '默认主题',
grid: {
visible: true,
type: 'dot',
size: 10,
color: '#e5e5e5',
thickness: 1,
},
background: {
color: '#ffffff',
},
nodeStyles: {
stroke: '#1890ff',
strokeWidth: 1,
fill: '#f0f8ff',
rx: 4,
ry: 4,
},
edgeStyles: {
stroke: '#1890ff',
strokeWidth: 2,
strokeDasharray: '',
},
textStyles: {
fontSize: 12,
fill: '#262626',
fontFamily: 'Arial, sans-serif',
}
},
// 其他主题配置...
}
2. 四种主题风格
我暂时设计了四种不同风格的主题,后续还会持续添加主题风格:
天空蓝主题

手绘风格主题

深色主题

极简主题

核心实现
1. 主题切换方法
切换主题后: 更新画布背景和网格、更新所有现有节点和边的样式、重新加载节点库以应用新主题
typescript
switchTheme(themeName: string) {
if (!this.themes[themeName]) {
console.warn(`主题 ${themeName} 不存在`)
return
}
this.currentTheme = themeName
const theme = this.themes[themeName]
// 更新画布背景和网格
this.updateCanvasTheme(theme)
// 更新所有现有节点和边的样式
this.updateExistingCellsTheme(theme)
// 重新加载节点库以应用新主题
this.loadCustomNode()
}
2. 画布主题更新
画布根据最新主题进行样式修改
typescript
updateCanvasTheme(theme: any) {
// 更新网格
this.graph.setGridSize(theme.grid.size)
this.graph.showGrid(theme.grid.visible)
// 更新背景色
this.graph.drawBackground({
color: theme.background.color,
})
}
3. 现有元素主题更新
画布中的现有的元素根据最新主题进行样式修改
typescript
updateExistingCellsTheme(theme: any) {
const cells = this.graph.getCells()
cells.forEach(cell => {
if (cell.isNode()) {
cell.setAttrs({
body: { ...theme.nodeStyles },
label: { ...theme.textStyles }
})
} else if (cell.isEdge()) {
cell.setAttrs({
line: { ...theme.edgeStyles },
label: { ...theme.textStyles }
})
}
})
}
使用方法
实现完成后,使用主题切换功能非常简单:
javascript
// 切换到手绘风格
canvas.switchTheme('sketch')
// 切换到深色主题
canvas.switchTheme('dark')
// 获取当前主题
const currentTheme = canvas.getCurrentTheme()
// 获取所有可用主题
const themes = canvas.getAvailableThemes()
扩展性考虑
1. 主题配置外部化
可以将主题配置提取到独立的JSON文件中,便于维护和扩展:
typescript
// themes.json
{
"custom": {
"name": "自定义主题",
"nodeStyles": {
"stroke": "#ff6b6b",
"fill": "#ffe0e0"
}
}
}
2. 动态主题生成
支持用户自定义主题颜色,动态生成主题配置:
typescript
generateCustomTheme(primaryColor: string) {
return {
name: '自定义主题',
nodeStyles: {
stroke: primaryColor,
fill: this.lightenColor(primaryColor, 0.9)
}
// ...
}
}
3. 主题预览功能
在切换前提供主题预览,提升用户体验:
typescript
previewTheme(themeName: string) {
// 创建预览画布
// 应用主题样式
// 显示预览效果
}
性能优化
批量更新
在切换主题时,使用批量更新减少重绘次数:
typescript
this.graph.batchUpdate(() => {
// 批量更新所有元素样式
})