大家好,这里是符华~
查看前三篇:
【Go】excelize库实现excel导入导出封装(一),自定义导出样式、隔行背景色、自适应行高、动态导出指定列、动态更改表头
【Go】excelize库实现excel导入导出封装(二),基于map、多个sheet、多级表头、树形结构表头导出,横向、纵向合并单元格导出
【Go】excelize库实现excel导入导出封装(三),基于excel模板导出excel
背景
前两篇文章中,导出时的样式都有设置统一的基础样式的。但是有些时候,我们需要对特定的某一列或某几列设置单独的样式。比如某一列单元格的值都是数值类型,我们需要让这一列右对齐,其它列不变(基础样式是居中对齐);又或者是把某一列文字标红或背景色填充为红色,其它列不变(保持基础样式)。
这篇文章就是来实现:在基础样式的基础上,对特定的列设置单独的自定义样式,且这些特定的列每列都可以设置单独的样式。
实现
修改 tag
因为我们是对一整列设置样式,因此我们可以直接将自定义的样式,放在需要设置样式的那个字段的tag里面。
如下图:
我们解析excel这个tag的时候,是通过正则表达式来解析的,因此在之前的正则表达式基础上,需要再加上style的解析:
同时对应的tag结构体,也需要再加上Style属性:
然后根据正则表达式解析tag值时,将解析到的style值设置到tag结构体的Style属性中:
设置
tag和tag解析部分修改完后,我们需要考虑下在tag里面添加样式的时候,我们应该按什么格式来设置,到后面解析这些样式的时候更方便。
然后我目前想到的设置格式是这样的:
样式类名和样式名,对应excelize库下的xmlStyles.go里面的Style结构体里的属性名:
样式类名是必须的,这样方便我们判断这个样式是属于哪个样式类(对应的结构体)的,然后将Alignment{Horizontal:left},Font{Color:#ff0000,Size:16.0,Family:黑体},Fill{Color:#f9cb9c,Type:pattern,Pattern:1}
这一段字符串根据样式类名分隔,分隔后处理成 json 字符串,再转成对应的样式类结构体。
代码如下:
go
// customStyle就是 Alignment{Horizontal:left},Font{Color:#ff0000,Size:16.0,Family:黑体},Fill{Color:#f9cb9c,Type:pattern,Pattern:1} 这一串字符
// 设置自定义样式:customStyle 定义的样式、 baseStyle 基础样式
func (e *Excel) SetCustomCellStyle(customStyle string, baseStyle int) int {
style, _ := e.F.GetStyle(baseStyle)
if style == nil {
style = &excelize.Style{}
}
patt := ".*?{.*?}" // 使用正则解析每一个样式类和它的大括号里面包含的样式
re := regexp.MustCompile(patt)
matches := re.FindAllStringSubmatch(customStyle, -1)
for i := range matches {
s := matches[i][0]
if strings.HasPrefix(s, ",") {
s = strings.TrimPrefix(s, ",")
}
s = strings.ReplaceAll(s, "{", "")
s = strings.ReplaceAll(s, "}", "")
if strings.HasPrefix(s, "Alignment") { // 对齐样式
result := stringBuilder("Alignment", s) // 处理成json字符串
json.Unmarshal([]byte(result), &style.Alignment) // 将json字符串转成对应的结构体
} else if strings.HasPrefix(s, "Font") { // 字体样式
result := stringBuilder("Font", s)
json.Unmarshal([]byte(result), &style.Font)
} else if strings.HasPrefix(s, "Fill") { // 背景填充样式
result := stringBuilder("Fill", s)
json.Unmarshal([]byte(result), &style.Fill)
}
}
i, _ := e.F.NewStyle(style)
return i
}
// 字符串处理拼接(处理成结构体json字符串)replaceStr 需要替换的字符
func stringBuilder(replaceStr, str string) string {
var builder strings.Builder
builder.WriteString("{")
str = strings.ReplaceAll(str, replaceStr, "")
split := strings.Split(str, ",")
for v := range split {
split1 := strings.Split(split[v], ":")
if v > 0 {
builder.WriteString(",")
}
builder.WriteString("\"")
builder.WriteString(split1[0])
builder.WriteString("\"")
// 如果是数值或bool类型,不需要拼接引号
if IsNumeric(split1[1]) || IsBool(split1[1]) {
builder.WriteString(":")
builder.WriteString(split1[1])
} else {
// 因为Fill下面的Color属性是字符串数组的,因此需要拼接中括号
if replaceStr == "Fill" && split1[0] == "Color" {
builder.WriteString(":[\"")
builder.WriteString(split1[1])
builder.WriteString("\"]")
} else {
// 字符串需要拼接引号
builder.WriteString(":\"")
builder.WriteString(split1[1])
builder.WriteString("\"")
}
}
}
builder.WriteString("}")
return builder.String()
}
// 是否是数字:包含正负整数和正负小数
func IsNumeric(s string) bool {
// 正则表达式匹配整数和小数
b, _ := regexp.MatchString(`^-?\d+(\.\d+)?$`, s)
return b
}
// 是否是bool值
func IsBool(s string) bool {
return strings.EqualFold(s, "true") || strings.EqualFold(s, "false")
}
样式解析并且设置完成后,在导出excel时,将在tag里设置了的样式,应用到对应的列中。因此我们还需要对构建数据行的代码进行修改:
测试
效果图:
最后
完整代码:点这里
ok以上就是今天的全部内容了,大家看完顺便给我点个Star、加关注呗~🥰🥳