JavaScript 常用操作,列表转树、树转列表、数字格式化、日期格式化
列表转树
/**
* @function 列表结构转树结构,可以有一至多个根节点,见使用案列
* @param list {Array} 列表结构数据
* @param id {String} 列表数据项中的id字段
* @param pid {String} 列表数据项中的父id字段
* @param children {String} 返回结果中用来标识父子关系的children字段
* @param rootValue {Object} 筛选 pid 等于指定值的结果
* @param sortId {String} 对结果树每一层进行排序的字段
* @return {Array} 返回树结构结果
* @author Wuwj 2022-11-25
* @example
* listToTree([
{ "name": "安徽省", "treeID": "1-1", "parent": "1", "treeName": "安徽省_1-1" },
{ "name": "江苏省", "treeID": "1-2", "parent": "1", "treeName": "江苏省_1-2" },
{ "name": "浙江省", "treeID": "1-3", "parent": "1", "treeName": "浙江省_1-3" },
{ "name": "合肥市", "treeID": "1-1-1", "parent": "1-1", "treeName": "合肥市_1-1-1" },
{ "name": "黄山市", "treeID": "1-1-2", "parent": "1-1", "treeName": "黄山市_1-1-2" },
{ "name": "南京市", "treeID": "1-2-1", "parent": "1-2", "treeName": "南京市_1-2-1" },
{ "name": "扬州市", "treeID": "1-2-2", "parent": "1-2", "treeName": "扬州市_1-2-2" },
{ "name": "杭州市", "treeID": "1-3-1", "parent": "1-3", "treeName": "杭州市_1-3-1" },
{ "name": "舟山市", "treeID": "1-3-2", "parent": "1-3", "treeName": "舟山市_1-3-2" },
{ "name": "蜀山区", "treeID": "1-1-1-1", "parent": "1-1-1", "treeName": "蜀山区_1-1-1-1" },
{ "name": "巢湖市", "treeID": "1-1-1-2", "parent": "1-1-1", "treeName": "巢湖市_1-1-1-2" },
{ "name": "徽州区", "treeID": "1-1-2-1", "parent": "1-1-2", "treeName": "徽州区_1-1-2-1" },
{ "name": "溧水区", "treeID": "1-2-1-1", "parent": "1-2-1", "treeName": "溧水区_1-2-1-1" },
{ "name": "广陵区", "treeID": "1-2-2-1", "parent": "1-2-2", "treeName": "广陵区_1-2-2-1" },
{ "name": "余杭区", "treeID": "1-3-1-1", "parent": "1-3-1", "treeName": "余杭区_1-3-1-1" },
{ "name": "淳安县", "treeID": "1-3-1-2", "parent": "1-3-1", "treeName": "淳安县_1-3-1-2" },
{ "name": "定海区", "treeID": "1-3-2-1", "parent": "1-3-2", "treeName": "定海区_1-3-2-1" },
{ "name": "岱山县", "treeID": "1-3-2-2", "parent": "1-3-2", "treeName": "岱山县_1-3-2-2" }
], 'treeID', 'parent')
*/
const listToTree = (list, id = "id", pid = "pid", children = "children", rootValue = undefined, sortId = undefined) => {
let sou = JSON.parse(JSON.stringify(list)), temp = {}
sou.forEach((e) => { temp[e[id]] = e })
Object.keys(temp).forEach((e) => { temp[temp[e][pid]] && (temp[temp[e][pid]][children] ? temp[temp[e][pid]][children].push(temp[e]) : temp[temp[e][pid]][children] = [temp[e]]) })
let result = JSON.parse(JSON.stringify(Object.keys(temp).filter((e) => { return Object.keys(temp).filter(o => { return temp[o][id] === temp[e][pid] }).length === 0 }).map(t => { return temp[t] })))
if (rootValue !== undefined) {
result = result.filter(o => { return o[pid] === rootValue })
}
function sort (list, sortId) {
if (sortId !== undefined) {
list.sort((a, b) => {
if (a[sortId] > b[sortId]) { return 1 }
else { return -1 }
})
list.forEach((e) => {
if (e[children]) {
sort(e.children, sortId)
}
})
}
}
sort(result, sortId)
return result
}
树转列表
/**
* @function 树结构转列表结构,可以有一至多个根节点,见使用案列
* @param tree {Array} 树结构数据
* @param children {String} 树数据中用来标识父子关系的children字段
* @return {Array} 返回列表结构结果
* @author Wuwj 2022-11-25
* @example
* treeToList([{
"name": "安徽省", "treeID": "1-1", "parent": "1", "treeName": "安徽省_1-1", "children": [{
"name": "合肥市", "treeID": "1-1-1", "parent": "1-1", "treeName": "合肥市_1-1-1", "children": [
{ "name": "蜀山区", "treeID": "1-1-1-1", "parent": "1-1-1", "treeName": "蜀山区_1-1-1-1" },
{ "name": "巢湖市", "treeID": "1-1-1-2", "parent": "1-1-1", "treeName": "巢湖市_1-1-1-2" }
]
}, {
"name": "黄山市", "treeID": "1-1-2", "parent": "1-1", "treeName": "黄山市_1-1-2", "children": [
{ "name": "徽州区", "treeID": "1-1-2-1", "parent": "1-1-2", "treeName": "徽州区_1-1-2-1" }
]
}]
},
{
"name": "江苏省", "treeID": "1-2", "parent": "1", "treeName": "江苏省_1-2", "children": [{
"name": "南京市", "treeID": "1-2-1", "parent": "1-2", "treeName": "南京市_1-2-1", "children": [
{ "name": "溧水区", "treeID": "1-2-1-1", "parent": "1-2-1", "treeName": "溧水区_1-2-1-1" }
]
}, {
"name": "扬州市", "treeID": "1-2-2", "parent": "1-2", "treeName": "扬州市_1-2-2", "children": [
{ "name": "广陵区", "treeID": "1-2-2-1", "parent": "1-2-2", "treeName": "广陵区_1-2-2-1" }
]
}]
},
{
"name": "浙江省", "treeID": "1-3", "parent": "1", "treeName": "浙江省_1-3", "children": [{
"name": "杭州市", "treeID": "1-3-1", "parent": "1-3", "treeName": "杭州市_1-3-1", "children": [
{ "name": "余杭区", "treeID": "1-3-1-1", "parent": "1-3-1", "treeName": "余杭区_1-3-1-1" },
{ "name": "淳安县", "treeID": "1-3-1-2", "parent": "1-3-1", "treeName": "淳安县_1-3-1-2" }
]
}, {
"name": "舟山市", "treeID": "1-3-2", "parent": "1-3", "treeName": "舟山市_1-3-2", "children": [
{ "name": "定海区", "treeID": "1-3-2-1", "parent": "1-3-2", "treeName": "定海区_1-3-2-1" },
{ "name": "岱山县", "treeID": "1-3-2-2", "parent": "1-3-2", "treeName": "岱山县_1-3-2-2" }
]
}]
}])
*/
const treeToList = (tree, children = "children") => {
let sou = JSON.parse(JSON.stringify(tree))
function iteration (tree, children, level) {
let temp = []
tree.forEach((e) => {
e.level = level
temp.push(e)
if (e[children]) {
temp = temp.concat(iteration(e[children], children, level + 1))
delete e[children]
}
})
return temp
}
return iteration(sou, children, 1)
}
数字格式化
/**
* @function 对 Number 的扩展,将 Number 转化为指定格式的 String
* @param c {Number} 保留小数位数
* @param d {String} 小数点指示符号
* @param t {String} 千位符指示符号
* @return {String} 返回格式化后结果
* @author Wuwj 2022-12-19
* @example
* 243877.26448.customFormat(3,',','^') ==> '243^877,264'
*/
Number.prototype.customFormat = function (c, d, t) {
let n = this
c = isNaN(c = Math.abs(c)) ? 2 : c
d = d === undefined ? "." : d
t = t === undefined ? "," : t
const s = n < 0 ? "-" : ""
const i = String(parseInt(n = Math.abs(Number(n) || 0).toFixed(c)))
let j = i.length
j = j > 3 ? j % 3 : 0
return s + (j ? i.substring(0, j) + t : "") + i.substring(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "")
}
日期格式化
/**
* @function 对 Date 的扩展,将 Date 转化为指定格式的 String
* @param fmt {String} 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符,年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符
* @return {String} 返回格式化后结果
* @author Wuwj 2022-12-19
* @example
* (new Date()).customFormat('yyyy年MM月dd日 第qq季度 hh时mm分ss秒S毫秒')
*/
Date.prototype.customFormat = function (fmt) {
const o = {
"q+": Math.floor((this.getMonth() + 3) / 3), // 季度
"M+": this.getMonth() + 1, // 月,JavaScript 中月份是 0-11
"d+": this.getDate(), // 日
"h+": this.getHours(), // 小时
"m+": this.getMinutes(), // 分
"s+": this.getSeconds(), // 秒
"S": this.getMilliseconds() // 毫秒
}
let rst = /(y+)/.exec(fmt)
if (rst) {
fmt = fmt.replace(rst[0], (this.getFullYear() + "").substring(4 - rst[0].length))
}
for (const k in o) {
rst = new RegExp("(" + k + ")").exec(fmt)
if (rst) {
fmt = fmt.replace(rst[0], (rst[0].length === 1) ? (o[k]) : (("00" + o[k]).substring(("" + o[k]).length)))
}
}
return fmt
}