kk-utils-library
v1.2.1
Published
## 功能模块 - [bidirectional-mapping](#bidirectional-mapping) - [tree](#tree)
Readme
A Javascript Utils Library
功能模块
安装
npm install kk-utils-library -S
pnpm add kk-utils-library -Sbidirectional-mapping
bidirectional-mapping 是 kk-utils 里的工具之一,其作用是键值对双向映射
它可以把一个字符串、数字、对象、数组按我们的映射规则进行转换
BiMap:用来生成映射规则的一个工具
BiMapConversion:用来把目标数据转换成映射规则处理后的数据
使用方法
编写映射规则
const map = new BiMap([
['a', 'A'], // 把'a'转成'A',也可以反过来把'A'转成'a'
[
'b',
'B',
{
transformType: String // 把键名对应的value进行处理,比如转成字符串,转成数字,转成Boolean
}
],
[
'c',
'C', // 数组嵌套数组表示c是复杂对象,里面的数据还要继续转换,c.d会变成C.D
[
[
'd',
'D',
{
transformSourceType: 'object', // 转换数据的类型 object、map、array
transformType: Number,
transformInverted: true, // 是否可以反过来转换 如为true就会把原本值为'否'变成0
transform: {
0: '否',
1: '是'
}
}
],
[
'e',
'E',
{
transformType: Boolean
}
],
[
'f',
'F',
[
[
'g',
'G',
{
transformSourceType: 'map',
transformType: Number,
transformInverted: true,
transform: new Map([
[0, 'zero'],
[1, 'one']
])
}
],
[
'h',
'H',
{
transformSourceType: 'array',
transformType: Number,
transformInverted: true,
transformLabelKey: 'label',
transformValueKey: 'value',
transform: [
{
label: '否',
value: 0
},
{
label: '是',
value: 1
}
]
}
]
]
]
]
],
[
'children',
'CHILDREN',
{
recursion: true // 树结构 递归处理
}
],
[
'k',
'K',
new BiMap([
[0, '零'],
[1, '一']
]) // 深层对象映射可以使用数组嵌套也可以直接使用BiMap BiMap可以处理键名转换也可以处理值的转换
]
]);转换数据
写一个测试数据
const data = [
{
a: 1,
b: 1,
c: {
d: 1,
e: 1,
f: [
{
g: 1,
h: 1
}
]
},
children: [
{
a: 0,
b: 0,
c: {
d: 0,
e: 0,
f: [
{
g: 0,
h: 0
}
]
},
k: 0
},
{
a: 1,
b: 1,
c: {
d: 1,
e: 1,
f: [
{
g: 1,
h: 1
}
]
},
k: 1
}
],
k: 1
}
];使用映射规则转换数据
const mapData = BiMapConversion(data, map);
console.log(mapData);转换结果
[
{
A: 1,
B: '1',
C: {
D: '是',
E: true,
F: [
{
G: 'one',
H: '是'
}
]
},
CHILDREN: [
{
A: 0,
B: '0',
C: {
D: '否',
E: false,
F: [
{
G: 'zero',
H: '否'
}
]
},
K: '零'
},
{
A: 1,
B: '1',
C: {
D: '是',
E: true,
F: [
{
G: 'one',
H: '是'
}
]
},
K: '一'
}
],
K: '一'
}
];截图对比
可以看到测试数据已经按我定义好的映射规则进行了转换,无论是键名还是值,都转换成功了的
融入业务使用
比如和后端对接接口的时候,后端键名不规范,我们写逻辑的时候就要去重新命名,多处用同一接口的话,就要到处维护,不方便。再比如同一个字段的值一会是字符串,一会是数字,就会对我们的逻辑代码造成不易擦觉得影响,所以可以使用这个工具在接口处统一做出入数据管理
在接口处统一做出入数据管理
比如我要对接后端的反馈接口的 CURD
定义公共分页映射
// src/constants/bi-map/common/pagination/index.js
import { BiMap } from 'kk-utils-library/bidirectional-mapping';
// 分页参数
export const $paginationReqItemMap = new BiMap([
[
'pagination',
'pagination',
[
['page', 'pageNumber'],
['pageSize', 'pageSize']
]
]
]);定义接口映射
// src/constants/bi-map/feedback/index.js
import { BiMap } from 'kk-utils-library/bidirectional-mapping';
import { $paginationReqItemMap } from '../common/pagination';
// 意见反馈列表
export const $feedbackListReqItemMap = new BiMap([
['id', 'id'], // ID
['type', 'emergencyDegreeType'], // 紧急程度类型
['topic', 'theme'], // 主题
['content', 'content'] // 内容
]);
export const $feedbackListResItemMap = new BiMap([
['id', 'id'], // ID
['type', 'emergencyDegreeType'], // 紧急程度类型
['topic', 'theme'], // 主题
['content', 'content'] // 内容
]);
// 意见反馈分页
export const $feedbackPageReqItemMap = new BiMap([
...$feedbackListReqItemMap.sourceData, // 复用 避免多次定义
...$paginationReqItemMap.sourceData // 复用 避免多次定义
]);
export const $feedbackPageResItemMap = $feedbackListResItemMap; // 相同映射规则直接指向共用
// 意见反馈详情
export const $feedbackDetailReqItemMap = new BiMap([['id', 'id']]);
export const $feedbackDetailResItemMap = $feedbackListResItemMap;
// 意见反馈新建
export const $feedbackCreateReqItemMap = $feedbackListReqItemMap;
export const $feedbackCreateResItemMap = new BiMap([]);
// 意见反馈编辑
export const $feedbackUpdateReqItemMap = $feedbackListReqItemMap;
export const $feedbackUpdateResItemMap = new BiMap([]);
// 意见反馈删除
export const $feedbackDeleteReqItemMap = new BiMap([['id', 'id']]);
export const $feedbackDeleteResItemMap = new BiMap([]);接口处使用映射做出入口参数管理
// src/apis/feedback/index.js
import { BiMapConversion } from 'kk-utils-library/bidirectional-mapping';
import {
$feedbackCreateReqItemMap,
$feedbackCreateResItemMap,
$feedbackDeleteReqItemMap,
$feedbackDeleteResItemMap,
$feedbackDetailReqItemMap,
$feedbackDetailResItemMap,
$feedbackListReqItemMap,
$feedbackListResItemMap,
$feedbackPageReqItemMap,
$feedbackPageResItemMap,
$feedbackUpdateReqItemMap,
$feedbackUpdateResItemMap
} from '@/constants/bi-map/feedback';
// 分页获取意见反馈
export function getFeedbackPage(Service) {
return (params) =>
new Promise((resolve, reject) => {
params = BiMapConversion(params || {}, $feedbackPageReqItemMap);
Service.get('/api/feedbacks', params)
.then((res) => {
res.data = BiMapConversion(res.data || {}, $feedbackPageResItemMap);
resolve(res);
})
.catch((error) => reject(error));
});
}
// 获取意见反馈列表
export function getFeedbackList(Service) {
return (params) =>
new Promise((resolve, reject) => {
params = BiMapConversion(params || {}, $feedbackListReqItemMap);
Service.get('/api/feedbacks/list', params)
.then((res) => {
res.data = BiMapConversion(res.data || [], $feedbackListResItemMap);
resolve(res);
})
.catch((error) => reject(error));
});
}
// 查询意见反馈详情
export function getFeedbackDetail(Service) {
return (params) =>
new Promise((resolve, reject) => {
params = BiMapConversion(params || {}, $feedbackDetailReqItemMap);
Service.get(`/api/feedbacks/${params.id}`, { ...params, populate: '*' })
.then((res) => {
res.data = BiMapConversion(res.data || {}, $feedbackDetailResItemMap);
resolve(res);
})
.catch((error) => reject(error));
});
}
// 新建意见反馈
export function createFeedback(Service) {
return (params) =>
new Promise((resolve, reject) => {
params = BiMapConversion(params || {}, $feedbackCreateReqItemMap);
Service.post('/api/feedbacks', { data: params })
.then((res) => {
res.data = BiMapConversion(res.data || {}, $feedbackCreateResItemMap);
resolve(res);
})
.catch((error) => reject(error));
});
}
// 更新意见反馈
export function updateFeedback(Service) {
return (params) =>
new Promise((resolve, reject) => {
params = BiMapConversion(params || {}, $feedbackUpdateReqItemMap);
Service.put(`/api/feedbacks/${params.id}`, { data: params })
.then((res) => {
res.data = BiMapConversion(res.data || {}, $feedbackUpdateResItemMap);
resolve(res);
})
.catch((error) => reject(error));
});
}
// 删除意见反馈
export function deleteFeedback(Service) {
return (params) =>
new Promise((resolve, reject) => {
params = BiMapConversion(params || {}, $feedbackDeleteReqItemMap);
Service.delete(`/api/feedbacks/${params.id}`, params)
.then((res) => {
res.data = BiMapConversion(res.data || {}, $feedbackDeleteResItemMap);
resolve(res);
})
.catch((error) => reject(error));
});
}这样只需要在接口封装处对 params 出参做映射转换和接收到数据时对 res 里的 data 做映射转换,我们就可以在项目里直接使用自己定义的 key,出参给后台的时候也会反过来把我们的 key 根据映射规则转成后台原本的 key 再传递给后台的
其他
除了以上业务使用,我们还能用来对单个数据处理
// 我们用回上面定义的new BiMap
const mapping_a = map.get('A'); // a
const mapping_A = map.get('a'); // Atree
tree是kk-utils里的工具之一,其作用是有多个针对树结构的方法函数,是我在写项目时积累下来的,几乎可以覆盖日常所需
当然,初始的代码是借鉴GitHub上newarea0大佬的代码,基于此源码的基础上进行修改和新增适合我业务的功能
基础配置项
绝大部分函数的基础配置项都有以下选项可用
strategy
设置搜索策略,默认策略为pre
pre:深度优先,正序搜索
post:深度优先,反序搜索
breadth:广度优先
import { filter } from 'kk-utils-library/tree';
const result = filter(tree, node => node.id > 2, { strategy: 'post' })childrenKey
自定义子节点key名,默认值为children
import { filter } from 'kk-utils-library/tree';
const result = filter(tree, node => node.id > 2, { childrenKey: 'items' })getChildrenKey
设置一棵树上多种自定义子节点key名
const getChildrenKeyTree = [
{
key: '1',
children: [
{
key: '2',
subItems: [
{
key: '3'
}
]
}
]
},
{
key: '4'
}
];
const getChildrenKeyResult = filter(
getChildrenKeyTree,
(node) => node.id > 2,
{
getChildrenKey: (tree, meta) => {
if (meta.depth === 1) {
return 'subItems';
}
}
}
);可用方法
forEach
遍历树形数组/对象,对每个节点执行回调
forEach(tree, callback, [options])tree:树形数组/对象callback:回调函数,对每个节点执行回调options:配置项,可选,对象类型,支持基础配置项
import { forEach } from 'kk-utils-library/tree';
const data = [
{
key: 1,
children: [
{
key: 11,
children: [
{
key: 111
},
{
key: 112
}
]
},
{
key: 12,
children: [
{
key: 122,
children: [
{
key: 1221
},
{
key: 1222
}
]
}
]
}
]
}
];
forEach(data, (node) => {
console.log(node.key);
});
// 1
// 11
// 111
// 112
// 12
// 122
// 1221
// 1222filter
遍历树形数组/对象,并把返回非真值的节点剔除(不会影响原结构,返回的树是新生成的)
filter(tree, callback, [options])tree:树形数组/对象callback:回调函数,对每个节点执行回调options:配置项,可选,对象类型,支持基础配置项
import { filter } from 'kk-utils-library/tree';
const data = [
{
key: 1,
children: [
{
key: 11,
children: [
{
key: 99
},
{
key: 112
}
]
},
{
key: 12,
children: [
{
key: 122,
children: [
{
key: 1221
},
{
key: 1222
}
]
}
]
}
]
}
];
const result = filter(data, (node) => node.key < 100);
console.log('result', result);
// {
// "key": 1,
// "children": [
// {
// "key": 11,
// "children": [
// {
// "key": 99
// }
// ]
// },
// {
// "key": 12,
// "children": []
// }
// ]
// }conditionsFilter
遍历树形数组/对象,并把返回非真值的节点剔除
这个方法和上面的filter的区别在于:
conditionsFilter不支持基础配置项conditionsFilter在父级为true,而子级没数据的时候,可以选择携带出下一级的数据或者所有下级数据,这在比如区域列表过滤的时候,可以通过搜索省级带出所有市级或者所有子区域conditionsFilter在能搜索匹配到最后一级的时候,并不会携带出兄弟节点conditionsFilter支持函数过滤和对象/数组结构的值匹配过滤,但是值匹配过滤并不是全等,而是包含关系
conditionsFilter(tree, conditions, [options])tree:树形数组conditions:过滤条件,- 可以为函数
(item) => boolean - 也可以为对象
{ name: '名称搜索', code: '编码搜索‘ },多个条件是&&的关系,必须都满足
- 可以为函数
options:配置项,可选,对象类型,不支持基础配置项childrenKey:自定义子节点key名,默认值为childrenwithChildren:子级没数据的时候是否携带子级数据返回,默认值为trueallChildren:是否返回所有子级数据,默认值为false
import { conditionsFilter } from 'kk-utils-library/tree';
const data = [
{
key: 1,
children: [
{
key: 11,
children: [
{
key: 99
},
{
key: 112
}
]
},
{
key: 12,
children: [
{
key: 122,
children: [
{
key: 1221
},
{
key: 1222
}
]
}
]
}
]
}
];
const result = conditionsFilter(data, (node) => node.key === 122);
console.log('result', result);
// [
// {
// key: 1,
// children: [
// {
// key: 12,
// children: [
// {
// key: 122,
// children: [
// {
// key: 1221
// },
// {
// key: 1222
// }
// ]
// }
// ]
// }
// ]
// }
// ];map
遍历树形数组/对象,根据返回的对象,组成新的树
map(tree, callback, [options])tree:树形数组/对象callback:每次迭代调用的函数,需要返回一个对象,返回的对象上无需包括子节点options:配置项,可选,对象类型,支持基础配置项
import { map } from 'kk-utils-library/tree';
const data = [
{
key: 1,
children: [
{
key: 11,
children: [
{
key: 111
},
{
key: 112
}
]
},
{
key: 12,
children: [
{
key: 122,
children: [
{
key: 1221
},
{
key: 1222
}
]
}
]
}
]
}
];
const result = map(data, (node) => ({ name: `No.${node.key}` }));
console.log('result', result);
// {
// "name": "No.1",
// "children": [
// {
// "name": "No.11",
// "children": [
// { "name": "No.111" },
// { "name": "No.112" }
// ]
// },
// {
// "name": "No.12",
// "children": [
// {
// "name": "No.122",
// "children": [
// { "name": "No.1221" },
// { "name": "No.1222" }
// ]
// }
// ]
// }
// ]
// }find
遍历树形数组/对象,找到第一个返回非空值的节点
find(tree, callback, [options])tree:树形数组/对象callback:每次迭代调用的函数,需要返回一个对象,返回的对象上无需包括子节点options:配置项,可选,对象类型,支持基础配置项
import { find } from 'kk-utils-library/tree';
const data = [
{
key: 1,
children: [
{
key: 11,
children: [
{
key: 111
},
{
key: 112
}
]
},
{
key: 12,
children: [
{
key: 122,
children: [
{
key: 1221
},
{
key: 1222
}
]
}
]
}
]
}
];
const result = find(data, (node) => node.key < 100 && node.key > 10);
console.log('result', result);
// {
// "key": 11,
// "children": [
// {
// "key": 111
// },
// {
// "key": 112
// }
// ]
// }some
遍历树形数组/对象,判断是否存在符合条件的节点
some(tree, callback, [options])tree:树形数组/对象callback:每次迭代调用的函数,需要返回一个对象,返回的对象上无需包括子节点options:配置项,可选,对象类型,支持基础配置项
import { some } from 'kk-utils-library/tree';
const data = [
{
key: 1,
children: [
{
key: 11,
children: [
{
key: 111
},
{
key: 112
}
]
},
{
key: 12,
children: [
{
key: 122,
children: [
{
key: 1221
},
{
key: 1222
}
]
}
]
}
]
}
];
const result = some(data, (node) => node.key < 100 && node.key > 10);
console.log('result', result);
// truetoArray
将树形数组/对象转换为一维数组,数组会包含所有节点
toArray(tree, [options])tree:树形数组/对象options:配置项,可选,对象类型,支持基础配置项leafKey:叶子节点的key,默认为isLeafwithChildren:是否携带子级数据,默认为false
import { toArray } from 'kk-utils-library/tree';
const data = [
{
key: '1',
children: [
{
key: '2',
children: [
{
key: '3'
}
]
}
]
}
];
const result = toArray(data);
console.log('result', result);
// [
// {
// key: '1',
// isLeaf: false
// },
// {
// key: '2',
// isLeaf: false
// },
// {
// key: '3',
// isLeaf: true
// }
// ];fromArray
将数组转换为树形数组/对象
fromArray(array, [options])array:数组options:配置项,可选,对象类型,不支持基础配置项itemKey:指定节点key名,默认值为idchildrenKey:自定义子节点key名,默认值为childrenparentKey:自定义父节点key名,默认值为parentId
import { fromArray } from 'kk-utils-library/tree';
const data = [
{
id: '1',
name: '1'
},
{
id: '2',
name: '2',
parentId: '1'
},
{
id: '3',
name: '3',
parentId: '1'
},
{
id: '4',
name: '4',
parentId: '2'
},
{
id: '5',
name: '5'
}
];
const result = fromArray(data);
console.log('result', result);
// [
// {
// id: '1',
// name: '1',
// children: [
// {
// id: '2',
// name: '2',
// parentId: '1',
// children: [
// {
// id: '4',
// name: '4',
// parentId: '2'
// }
// ]
// },
// {
// id: '3',
// name: '3',
// parentId: '1'
// }
// ]
// },
// {
// id: '5',
// name: '5'
// }
// ];toTree
将数组转换为树形数组
这个方法和上面的fromArray的区别在于:
toTree支持root顶层标识配置toTree支持levelKey节点层级key配置toTree支持leafKey叶子节点key配置
toTree(tree, conditions, [options])tree:树形数组conditions:过滤条件,- 可以为函数
(item) => boolean - 也可以为对象
{ name: '名称搜索', code: '编码搜索‘ },多个条件是&&的关系,必须都满足
- 可以为函数
options:配置项,可选,对象类型,不支持基础配置项itemKey:指定节点key名,默认值为idchildrenKey:自定义子节点key名,默认值为childrenparentKey:自定义父节点key名,默认值为parentIdroot:顶层标识配置levelKey:节点层级key配置leafKey:叶子节点key配置
import { toTree } from 'kk-utils-library/tree';
const data = [
{
id: '1',
name: '1'
},
{
id: '2',
name: '2',
parentId: '1'
},
{
id: '3',
name: '3',
parentId: '1'
},
{
id: '4',
name: '4',
parentId: '2'
},
{
id: '5',
name: '5'
}
];
const result = toTree(data);
console.log('result', result);
// [
// {
// id: '1',
// name: '1',
// children: [
// {
// id: '2',
// name: '2',
// parentId: '1',
// children: [
// {
// id: '4',
// name: '4',
// parentId: '2',
// children: null,
// level: 3,
// isLeaf: true
// }
// ],
// level: 2,
// isLeaf: false
// },
// {
// id: '3',
// name: '3',
// parentId: '1',
// children: null,
// level: 2,
// isLeaf: true
// }
// ],
// level: 1,
// isLeaf: false
// },
// {
// id: '5',
// name: '5',
// children: null,
// level: 1,
// isLeaf: true
// }
// ];getDepthAndLength
获取树结构的深度和最长子级长度
getDepthAndLength(tree, [options])tree:树形数组options:配置项,可选,对象类型,支持基础配置项
import { getDepthAndLength } from 'kk-utils-library/tree';
const data = [
{
key: 1,
children: [
{
key: 11,
children: [
{
key: 99
},
{
key: 112
}
]
},
{
key: 12,
children: [
{
key: 122,
children: [
{
key: 1221
},
{
key: 1222
}
]
}
]
}
]
}
];
const result = getDepthAndLength(data);
console.log('result', result);
// { "depth": 3, "length": 2 } // 深度和最长子级数量fixParentId
给树形数组每一项补上parentId
fixParentId(array, [options])array:数组options:配置项,可选,对象类型,不支持基础配置项itemKey:指定节点key名,默认值为idchildrenKey:自定义子节点key名,默认值为childrenparentKey:自定义父节点key名,默认值为parentId
import { fixParentId } from 'kk-utils-library/tree';
const data = [
{
id: 1,
children: [
{
id: 11,
children: [
{
id: 99
},
{
id: 112
}
]
},
{
id: 12,
children: [
{
id: 122,
children: [
{
id: 1221
},
{
id: 1222
}
]
}
]
}
]
}
];
const result = fixParentId(data);
console.log('result', result);
// [
// {
// id: 1,
// children: [
// {
// id: 11,
// children: [
// {
// id: 99,
// parentId: 11
// },
// {
// id: 112,
// parentId: 11
// }
// ],
// parentId: 1
// },
// {
// id: 12,
// children: [
// {
// id: 122,
// children: [
// {
// id: 1221,
// parentId: 122
// },
// {
// id: 1222,
// parentId: 122
// }
// ],
// parentId: 12
// }
// ],
// parentId: 1
// }
// ]
// }
// ];findAncestor
从树形数组里根据传入的节点ID查找出它的所有祖先元素,返回一个有层级关系的tree数据
findAncestor(array, [options])array:数组options:配置项,可选,对象类型,不支持基础配置项root顶层标识配置itemKey:指定节点key名,默认值为idchildrenKey:自定义子节点key名,默认值为childrenparentKey:自定义父节点key名,默认值为parentIdwithChildren:是否携带子级数据,默认为false
import { findAncestor } from 'kk-utils-library/tree';
const data = [
{
id: 1,
children: [
{
id: 11,
children: [
{
id: 99,
parentId: 11
},
{
id: 112,
parentId: 11
}
],
parentId: 1
},
{
id: 12,
children: [
{
id: 122,
children: [
{
id: 1221,
parentId: 122
},
{
id: 1222,
parentId: 122
}
],
parentId: 12
}
],
parentId: 1
}
]
}
];
const result = findAncestor(data, 1221);
console.log('result', result);
// {
// id: 1,
// children: [
// {
// id: 12,
// children: [
// {
// id: 122,
// children: [
// {
// id: 1221,
// parentId: 122
// }
// ],
// parentId: 12
// }
// ],
// parentId: 1
// }
// ]
// }excel-js
excel-js是kk-utils里的工具之一(1.2.0版本开始支持),其作用是有多个针对导出导出的方法函数,是我在写项目时积累下来的,几乎可以覆盖日常所需
这个工具是基于GitHub上开源的exceljs的代码,基于此工具库的基础上进行二次封装适合我业务的功能
可用方法
importExcel
导入Excel
importExcel(File, [options])- File:要导入的Excel文件
- options:配置项,可选,对象类型
- allWorksheets:
boolean,是否导入所有工作表,无论true还是false,返回的结果都是二维数组,默认为false - getValue:
(cell) => string,获取单元格的文本值,默认为(cell) => cell.text - headerStartLine:
number,表头开始行数,默认1开始 - headerTotalLine:
number,表头总行数,默认1 - toJsonArray:
boolean,是否转换成JSON格式,默认true- false:则返回的数据是
[[key, key, key], [value, value, value], [value,value,value]]这种格式 - true:则返回的数据是
[{key, value}, {key, value}, {key, value}]这种格式
- false:则返回的数据是
- allWorksheets:
<input type="file" id="file" accept=".xlsx" />
<button id="import">导入所选文件</button>这是我要导入的Excel文件,第一行就是表头,总共一行表头,所以使用默认的headerStartLine和headerTotalLine就可以了,如果是多行表头或者开始不是第一行则自行调整或者传入对应参数
import { importExcel } from 'kk-utils-library/excel-js';
const fileInput = document.getElementById('file');
const importButton = document.getElementById('import');
importButton.addEventListener('click', () => {
const file = fileInput.files[0];
if (!file) {
alert('请选择文件');
return;
}
importExcel(file, {
headerStartLine: 1,
headerTotalLine: 1
}).then((data) => {
console.log('data', data);
// [
// [
// {
// 操作类型: '新增',
// 客户名称: '测试1',
// 客户编码: 'TEST001',
// 客户类型: '供应商',
// 省: '辽宁省',
// 市: '沈阳市',
// 区: '辽中县'
// },
// {
// 操作类型: '修改',
// 客户名称: '测试2',
// 客户编码: 'TEST002',
// 客户类型: '客户',
// 省: '山西省',
// 市: '太原市',
// 区: '晋源区'
// },
// {
// 操作类型: '删除',
// 客户名称: '测试3',
// 客户编码: 'TEST003',
// 客户类型: '客户与供应商',
// 省: '吉林省',
// 市: '长春市',
// 区: '宽城区'
// },
// {
// 操作类型: '不变',
// 客户名称: '测试4',
// 客户编码: 'TEST004',
// 客户类型: '供应商',
// 省: '湖南省',
// 市: '长沙市',
// 区: '雨花区'
// }
// ]
// ];
});
});exportExcel
导出Excel
exportExcel([options])- filename:导出的文件名,默认为
excel - sheets:
object[],要导出的工作表- sheetName:
string,表名,默认为SheetJS[index + 1] - withDefaultStyle:
boolean,携带默认样式,默认true,全局默认样式可通过setGlobalDefaultStyle()配置 - adaptiveWidth:
boolean,自适应列宽,默认true - adaptiveWidthOptions:
object,自适应列宽配置项- minWidth:
number,最小列宽,默认5 - maxWidth:
number,最大列宽,默认50 - interstice:
number,列宽额外空隙,默认5 - ignoreLines:
number[],计算列宽忽略的行,因为有些行会有合并单元格的操作,这样会导致合并行的列度最大并使用合并行的列宽作为整列的宽,所以可以传入合并行的行数来进行列宽计算忽略
- minWidth:
- processing:
(worksheet) => void,对工作表对象做操作处理,这个是在自动列宽和默认样式之前执行的 - extraProcessing:
(worksheet) => void,对工作表对象做操作额外处理,这个是在自动列宽和默认样式之后执行的
- sheetName:
- processing:
(workbook) => void,对Excel对象做操作处理
<button id="export">导出测试文件</button>import { exportExcel } from 'kk-utils-library/excel-js';
const exportButton = document.getElementById('export');
exportButton.addEventListener('click', () => {
const data = [
['姓名', '年龄', '性别'],
['张三', 18, '男'],
['李四', 19, '女'],
['王五', 20, '男']
];
exportExcel({
filename: 'test',
sheets: [
{
processing: (worksheet) => {
worksheet.addRows(data);
},
extraProcessing: (worksheet) => {
_merge(worksheet.getRow(1), {
fill: {
type: 'pattern',
pattern: 'solid',
fgColor: {
argb: 'FF99CCFF'
}
}
});
_merge(worksheet.getRow(2).getCell(2), {
fill: {
type: 'pattern',
pattern: 'solid',
fgColor: {
argb: 'FFFF4949'
}
}
});
}
}
]
});
});然后就可以看到下载了一份名为test.xlsx的文件,打开就是我们要的数据和效果了
coordinatesFromRange
从一个区间范围获取所有的坐标矩阵
coordinatesFromRange(range)- range:
[number, number, number, number]坐标点,四个参数分别代表开始行开始列结束行结束列
import { coordinatesFromRange } from 'kk-utils-library/excel-js';
const coordinatesResult = coordinatesFromRange([2, 3, 3, 4]);
console.log('coordinatesResult', coordinatesResult);
// [
// [2, 3],
// [2, 4],
// [3, 3],
// [3, 4]
// ];isCoordinateInCoordinates
判断一个坐标点是否在坐标矩阵内
isCoordinateInCoordinates(coordinate, coordinates)- coordinate:
[number, number]坐标点 - coordinates:坐标矩阵
import { isCoordinateInCoordinates } from 'kk-utils-library/excel-js';
const isCoordinateInCoordinatesResult = isCoordinateInCoordinates(
[2, 3],
coordinatesResult
);
const isCoordinateInCoordinatesResult2 = isCoordinateInCoordinates(
[12, 13],
coordinatesResult
);
console.log('isCoordinateInCoordinatesResult', isCoordinateInCoordinatesResult);
// true
console.log('isCoordinateInCoordinatesResult2', isCoordinateInCoordinatesResult2);
// falseisCoordinateInRange
判断一个坐标点是否在坐标范围内
isCoordinateInRange(coordinate, range)- coordinate:
[number, number]坐标点 - range:
[number, number, number, number]坐标点,四个参数分别代表开始行开始列结束行结束列
import { isCoordinateInRange } from 'kk-utils-library/excel-js';
const isCoordinateInRangeResult = isCoordinateInRange(
[2, 3],
[2, 3, 5, 8]
);
const isCoordinateInRangeResult2 = isCoordinateInRange(
[12, 13],
[2, 3, 5, 8]
);
console.log('isCoordinateInRangeResult', isCoordinateInRangeResult);
// true
console.log('isCoordinateInRangeResult2', isCoordinateInRangeResult2);
// falsegetHorizontalMerges
获取横向合并数据,此数据是专门给exceljs用的
getHorizontalMerges(excelData)- excelData:二维数组
import {
getHorizontalMerges,
freeMerge as fm, // 代表自由合并 上下都合并,必须是正方形/长方形 起点为fm左上角单元格
horizontalMerge as hm, // 代表横向合并 起点为hm前一个单元格
verticalMerge as vm // 代表纵向合并 起点为vm上一个单元格
} from 'kk-utils-library/excel-js';
const horizontalMergeAndVerticalMergeTestData = [
[11, 12, hm, hm, 15, 16, 17, 18, 19],
[21, 22, 23, 24, 25, fm, fm, 28, 29],
[31, 32, vm, 34, 35, fm, fm, 38, 39],
[41, 42, vm, 44, vm, 46, hm, hm, hm],
[51, 52, 53, 54, vm, 56, 57, 58, 59],
[61, 62, vm, 64, vm, 66, 67, 68, 69],
[71, 72, vm, 74, 75, 76, 77, 78, 79],
[81, 82, vm, 84, 85, 86, 87, 88, 89],
[91, 92, 93, 94, 95, 96, 97, 98, 99]
];
const horizontalMergesResult = getHorizontalMerges(
horizontalMergeAndVerticalMergeTestData
);
console.log('horizontalMergesResult', horizontalMergesResult);
// [
// [1, 2, 1, 4],
// [4, 6, 4, 9]
// ];getVerticalMerges
获取纵向合并数据,此数据是专门给exceljs用的
getVerticalMerges(excelData)- excelData:二维数组
import {
getVerticalMerges,
freeMerge as fm, // 代表自由合并 上下都合并,必须是正方形/长方形 起点为fm左上角单元格
horizontalMerge as hm, // 代表横向合并 起点为hm前一个单元格
verticalMerge as vm // 代表纵向合并 起点为vm上一个单元格
} from 'kk-utils-library/excel-js';
const horizontalMergeAndVerticalMergeTestData = [
[11, 12, hm, hm, 15, 16, 17, 18, 19],
[21, 22, 23, 24, 25, fm, fm, 28, 29],
[31, 32, vm, 34, 35, fm, fm, 38, 39],
[41, 42, vm, 44, vm, 46, hm, hm, hm],
[51, 52, 53, 54, vm, 56, 57, 58, 59],
[61, 62, vm, 64, vm, 66, 67, 68, 69],
[71, 72, vm, 74, 75, 76, 77, 78, 79],
[81, 82, vm, 84, 85, 86, 87, 88, 89],
[91, 92, 93, 94, 95, 96, 97, 98, 99]
];
const verticalMergesResult = getVerticalMerges(
horizontalMergeAndVerticalMergeTestData
);
console.log('verticalMergesResult', verticalMergesResult);
// [
// [2, 3, 4, 3],
// [3, 5, 6, 5],
// [5, 3, 8, 3]
// ];getMatrixMerges
获取纵向和横向的合并数据,此数据是专门给exceljs用的
getMatrixMerges(excelData)- excelData:二维数组
import {
getMatrixMerges,
freeMerge as fm, // 代表自由合并 上下都合并,必须是正方形/长方形 起点为fm左上角单元格
horizontalMerge as hm, // 代表横向合并 起点为hm前一个单元格
verticalMerge as vm // 代表纵向合并 起点为vm上一个单元格
} from 'kk-utils-library/excel-js';
const freeMergeTestData = [
[11, 21, fm, fm, fm, 61, fm, fm, 91],
[21, 22, fm, fm, fm, 26, 27, 28, 29],
[31, 32, fm, fm, fm, 36, fm, fm, 39],
[41, 42, 43, 44, 45, 46, fm, fm, 49],
[51, 52, fm, fm, 55, 56, fm, fm, 59],
[fm, 62, fm, fm, 65, 66, 67, 68, 69],
[fm, 72, fm, fm, 75, 76, 77, 78, 79],
[81, 82, fm, fm, 85, 86, 87, 88, 89],
[91, 92, 93, 94, 95, 96, 97, 98, 99]
];
const matrixMergesResult = getMatrixMerges(freeMergeTestData);
console.log('matrixMergesResult', matrixMergesResult);
// [
// [1, 2, 3, 5],
// [1, 6, 1, 8],
// [2, 6, 5, 8],
// [4, 2, 8, 4],
// [5, 1, 7, 1]
// ];getMerges
获取合并数据,此数据是专门给exceljs用的
此方法涵盖了前面三种getMerge方法,会自动识别数据里的hm, vm, fm
getMerges(excelData)- excelData:二维数组
import {
getMerges,
freeMerge as fm, // 代表自由合并 上下都合并,必须是正方形/长方形 起点为fm左上角单元格
horizontalMerge as hm, // 代表横向合并 起点为hm前一个单元格
verticalMerge as vm // 代表纵向合并 起点为vm上一个单元格
} from 'kk-utils-library/excel-js';
const horizontalMergeAndVerticalMergeTestData = [
[11, 12, hm, hm, 15, 16, 17, 18, 19],
[21, 22, 23, 24, 25, fm, fm, 28, 29],
[31, 32, vm, 34, 35, fm, fm, 38, 39],
[41, 42, vm, 44, vm, 46, hm, hm, hm],
[51, 52, 53, 54, vm, 56, 57, 58, 59],
[61, 62, vm, 64, vm, 66, 67, 68, 69],
[71, 72, vm, 74, 75, 76, 77, 78, 79],
[81, 82, vm, 84, 85, 86, 87, 88, 89],
[91, 92, 93, 94, 95, 96, 97, 98, 99]
];
const mergesResult = getMerges(horizontalMergeAndVerticalMergeTestData);
console.log('mergesResult', mergesResult);
// [
// [1, 2, 1, 4],
// [4, 6, 4, 9],
// [2, 3, 4, 3],
// [3, 5, 6, 5],
// [5, 3, 8, 3],
// [1, 5, 3, 7]
// ];getDefaultStyle
获取全局默认样式
getDefaultStyle()import { getDefaultStyle } from 'kk-utils-library/excel-js';
const beforeStyle = getDefaultStyle();
console.log('beforeStyle', beforeStyle);
// {
// font: {
// size: 14
// },
// alignment: {
// vertical: 'top',
// wrapText: true
// },
// border: {
// top: {
// style: 'thin'
// },
// left: {
// style: 'thin'
// },
// bottom: {
// style: 'thin'
// },
// right: {
// style: 'thin'
// }
// },
// fill: {
// type: 'pattern',
// pattern: 'solid',
// fgColor: {
// argb: 'FF99CCFF'
// }
// }
// }getDefaultStyle
获取全局默认样式
getDefaultStyle()import { setGlobalDefaultStyle } from 'kk-utils-library/excel-js';
const afterStyle = setGlobalDefaultStyle({
font: {
size: 14
},
fill: {
type: 'pattern',
pattern: 'solid',
fgColor: {
argb: 'FF99CCFF'
}
}
});
const afterStyle = getDefaultStyle();
console.log('afterStyle', afterStyle);
// {
// font: {
// size: 14
// },
// alignment: {
// vertical: 'top',
// wrapText: true
// },
// border: {
// top: {
// style: 'thin'
// },
// left: {
// style: 'thin'
// },
// bottom: {
// style: 'thin'
// },
// right: {
// style: 'thin'
// }
// },
// fill: {
// type: 'pattern',
// pattern: 'solid',
// fgColor: {
// argb: 'FF99CCFF'
// }
// }
// }setAdaptiveWidth
设置Excel的单元格自适应宽度,如果你自己使用exceljs则需要自己使用setAdaptiveWidth去处理,kk-utils里的导出默认是true了,可以自己传入调整参数,ExcelJs的参数需自己看文档
setAdaptiveWidth(Worksheet, [options])import { setAdaptiveWidth } from 'kk-utils-library/excel-js';
import ExcelJS from 'exceljs';
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet('SheetJS');
worksheet.addRows([
['姓名', '简称', '年龄', '性别'],
['小明', '无', 18, '男'],
['古力那扎尔·拜合提亚尔', '古力娜扎', 16, '女'],
[
'巴勃罗·迭戈·荷瑟·山迪亚哥·弗朗西斯科·德·保拉·居安·尼波莫切诺·克瑞斯皮尼亚诺·德·罗斯·瑞米迪欧斯·西波瑞亚诺·德·拉·山迪西玛·特立尼达·玛利亚·帕里西奥·克里托·瑞兹·布拉斯科·毕加索',
'毕加索',
92,
'男'
]
]);
console.log('before worksheet widths', _map(worksheet.columns, 'width'));
// [null, null, null, null];
setAdaptiveWidth(worksheet, {
minWidth: 15,
maxWidth: 50
});
console.log('after worksheet widths', _map(worksheet.columns, 'width'));
// [50, 17, 15, 15];getDataHeader
获取最后渲染数据用的表头,因为表头我们可能需要合并,所以塞数据的时候原始表头不适用,需要使用列一一对应的表头才能更方便加入表体数据
getDataHeader(excelData)- excelData:二维数组
import { getDataHeader } from 'kk-utils-library/excel-js';
const dataHeader = getDataHeader([
['编码', '时间', '已批准', '已核销', '未核销', hm, '已支付', '待支付'],
[vm, vm, vm, vm, '申请中', '未申请', vm, vm]
]);
console.log('dataHeader', dataHeader);
// [
// '编码',
// '时间',
// '已批准',
// '已核销',
// '申请中',
// '未申请',
// '已支付',
// '待支付'
// ];getColumnLetterByNumber
根据列下标1开始获取对应的Excel字母列
getColumnLetterByNumber(number)import { getColumnLetterByNumber } from 'kk-utils-library/excel-js';
const letter = getColumnLetterByNumber(5);
console.log('letter', letter);
// EgetDepthAndLength
获取树结构的深度和最长子级长度
getDepthAndLength(tree, [options])tree:树形数组options:配置项,可选,对象类型,支持基础配置项itemKey:指定节点key名,默认值为idchildrenKey:自定义子节点key名,默认值为children
import { getDepthAndLength } from 'kk-utils-library/excel-js';
const getDepthAndLengthTree = [
{
key: 1,
children: [
{
{
key: 12,
children: [
{
key: 122,
children: [
{
key: 1221
},
{
key: 1222,
children: [
{
key: 12221
},
{
key: 12222
},
{
key: 12223
},
{
key: 12224
},
{
key: 12225
},
{
key: 12226
}
]
}
]
}
]
}
]
}
];
const getDepthAndLengthResult = getDepthAndLength(getDepthAndLengthTree);
console.log('getDepthAndLengthResult', getDepthAndLengthResult);
// { depth: 5, length: 6 }getFillHorizontalMergeKeyMap
获取表头横向合并列所对应的合并长度
getFillHorizontalMergeKeyMap(Tree, [options])tree:树形数组options:配置项,可选,对象类型,支持基础配置项itemKey:指定节点key名,默认值为idchildrenKey:自定义子节点key名,默认值为children
import { getFillHorizontalMergeKeyMap } from 'kk-utils-library/excel-js';
const treeHeader = [
{
prop: 'index',
label: '序号'
},
{
prop: 'budgetCycleItemName',
label: '预算周期项名称'
},
{
prop: 'expectedShipmentAmount',
label: '预发货金额',
children: [
{
prop: 'originalExpectedShipmentAmount',
label: '调整前金额'
},
{
prop: 'adjustedExpectedShipmentAmount',
label: '调整的金额'
},
{
prop: 'finalExpectedShipmentAmount',
label: '调整后金额'
}
]
},
{
prop: 'budgetAmount',
label: '预算金额',
children: [
{
prop: 'originalBudgetAmount',
label: '调整前金额'
},
{
prop: 'adjustedBudgetAmount',
label: '调整的金额'
},
{
prop: 'finalBudgetAmount',
label: '调整后金额'
}
]
}
];
const getFillHorizontalMergeKeyMapResult =
getFillHorizontalMergeKeyMap(treeHeader);
console.log(
'getFillHorizontalMergeKeyMapResult',
getFillHorizontalMergeKeyMapResult
);
// {
// index: 0,
// budgetCycleItemName: 0,
// expectedShipmentAmount: 2,
// originalExpectedShipmentAmount: 0,
// adjustedExpectedShipmentAmount: 0,
// finalExpectedShipmentAmount: 0,
// budgetAmount: 2,
// originalBudgetAmount: 0,
// adjustedBudgetAmount: 0,
// finalBudgetAmount: 0
// }tableHeaderToMultidimensionalArray
把树结构表头处理成Excel的表头
tableHeaderToMultidimensionalArray(Tree, [options])tree:树形数组options:配置项,可选,对象类型,支持基础配置项itemKey:指定节点key名,默认值为idchildrenKey:自定义子节点key名,默认值为childrenlabelKey: 自定义节点文本key名,默认值为label
import { tableHeaderToMultidimensionalArray } from 'kk-utils-library/excel-js';
const treeHeader = [
{
prop: 'index',
label: '序号'
},
{
prop: 'budgetCycleItemName',
label: '预算周期项名称'
},
{
prop: 'expectedShipmentAmount',
label: '预发货金额',
children: [
{
prop: 'originalExpectedShipmentAmount',
label: '调整前金额'
},
{
prop: 'adjustedExpectedShipmentAmount',
label: '调整的金额'
},
{
prop: 'finalExpectedShipmentAmount',
label: '调整后金额'
}
]
},
{
prop: 'budgetAmount',
label: '预算金额',
children: [
{
prop: 'originalBudgetAmount',
label: '调整前金额'
},
{
prop: 'adjustedBudgetAmount',
label: '调整的金额'
},
{
prop: 'finalBudgetAmount',
label: '调整后金额'
}
]
}
];
const multidimensionalArray = tableHeaderToMultidimensionalArray(treeHeader);
console.log('multidimensionalArray', multidimensionalArray);
// [
// [
// '序号',
// '预算周期项名称',
// '预发货金额',
// '-hm',
// '-hm',
// '预算金额',
// '-hm',
// '-hm'
// ],
// [
// '-vm',
// '-vm',
// '调整前金额',
// '调整的金额',
// '调整后金额',
// '调整前金额',
// '调整的金额',
// '调整后金额'
// ]
// ];conversionToJsonArray
把Excel数据转成数组对象格式
conversionToJsonArray(ExcelData, [options])- excelData:二维数组
- options:配置项,可选,对象类型
- headerStartLine:
number,表头开始行数,默认1开始 - headerTotalLine:
number,表头总行数,默认1
- headerStartLine:
import { conversionToJsonArray } from 'kk-utils-library/excel-js';
const arrayData = [
['操作类型', '客户名称', '客户编码', '省', '市', '区'],
[
'不变',
'苏州秦曼商贸有限公司',
'11605028',
'苏北省(作废)',
'苏州市',
'吴中区'
],
[
'不变',
'测试-嘉士柏河南省郑州——麻三定/麻坤丽',
'JSB12001003',
'河南省',
'郑州市',
'中原区'
]
];
const conversionToJsonArrayResult = conversionToJsonArray(arrayData);
console.log('conversionToJsonArrayResult', conversionToJsonArrayResult);
// [
// {
// 操作类型: '不变',
// 客户名称: '苏州秦曼商贸有限公司',
// 客户编码: '11605028',
// 省: '苏北省(作废)',
// 市: '苏州市',
// 区: '吴中区'
// },
// {
// 操作类型: '不变',
// 客户名称: '测试-嘉士柏河南省郑州——麻三定/麻坤丽',
// 客户编码: 'JSB12001003',
// 省: '河南省',
// 市: '郑州市',
// 区: '中原区'
// }
// ];