通过传入含有父子级关系的数组(含有父级key),生成树型结构,树型结构用途很广泛,但是构造的时候很麻烦,核心思路一般用方法的递归实现,下面提供了一个公共的工具方法(实现了基础树结构的生成及过滤数据的功能)。
// 输入示例 id、pId、label是生成树的关键字段,同字段的值将会被覆盖,其他原有的字段将会被保留
[{ name: 'node1', id: '0', pId: ''}, { name: 'node2', id: '1', pId: '0'}]
// 结果示例
[
{
"name":"node1",
"id":"0",
"pId":"",
"label":"node1",
"children":[ // 子节点点
{
"name":"node2",
"id":"1",
"pId":"0",
"label":"node2"
}
]
}
]
// 调用示例例
produceTree([{ name: 'node1', id: '0', pId: ''}, { name: 'node2', id: '1', pId: '0'}])
produceTree([{ name: 'node1', id: '0', pId: ''}, { name: 'node2', id: '1', pId: '0'}],
{initNodeKey: '0'} // initNodeKey 是树的根节点值,一般需要传,不传默认为'0' )
produceTree(
[ // 含有父子级关系的数组 示例,id会被作为树的节点key,pId用来确认父子级关系
{ name: 'node1', id: '0', pId: ''},
{ name: 'node2', id: '1', pId: '0'}
],
// config 传参,具体描述见下方,congig传参采用了解构方式,忽略任意一个参数都将取用默认值
{ labelField: 'name', keyField: 'id', pKeyField: 'pId', initNodeKey: '0', maxHierarchy: 1}
)
/**
* @function
* @name produceTree
* @description 方法描述:数组生成树形数据
* @param {Array} data 数组
* @param {Map} config 配置参数,有默认值
* @example produceTree([{ name: 'node1', id: '0', pId: ''}, { name: 'node2', id: '1', pId: '0'}],{ labelField: 'name', keyField: 'id', pKeyField: 'pId', initNodeKey: '0'})
* @returns {Array} - 数组生成树形数据
*/
function produceTree (data, config = {}) {
// 默认配置解析
var configOri = {
labelField: 'name', // 名称字段名
keyField: 'id', // key字段名
pKeyField: 'pId', // 父级key字段名
initNodeKey: '0', // 树顶级key值
maxHierarchy: -1, // 限制最大层级深度, 为-1时无限制
hideConfig: { // 是否隐藏配置
openHide: true, // 是否启用隐藏
field: 'isHide', // 字段
hideValue: ['1'] // 为什么值时要隐藏
}
}
// 配置解析
config.hideConfig = { ...configOri.hideConfig, ...config.hideConfig }
var { labelField, keyField, pKeyField, initNodeKey, hideConfig } = { ...configOri, ...config }
// 将要忽略的值转成map
hideConfig.hideValueMap = {}
hideConfig.hideValue.forEach(hF => {
hideConfig.hideValueMap[hF] = hF
})
// 内置工具方法
function isNull (obj) {
if (obj === null || obj === undefined || obj === '') {
return true
}
return false
}
// 深度复制
function deepClone (source) {
if (!source && typeof source !== 'object') {
throw new Error('error arguments', 'shallowClone')
}
const targetObj = source.constructor === Array ? [] : {}
for (const keys in source) {
if (source.hasOwnProperty(keys)) {
if (source[keys] && typeof source[keys] === 'object') {
targetObj[keys] = source[keys].constructor === Array ? [] : {}
targetObj[keys] = deepClone(source[keys])
} else {
targetObj[keys] = source[keys]
}
}
}
return targetObj
}
data = deepClone(data)
var initNode
var treeList = []
// 预处理数据,并找到根节点
data.forEach(row => {
row.label = row[labelField]
row.id = row[keyField]
row.pId = row[pKeyField]
if (!(hideConfig.openHide && !isNull(hideConfig.hideValueMap[row[hideConfig.field]]))) {
if (row.id === initNodeKey) {
initNode = row
initNode.children = []
} else {
treeList.push(row)
}
}
})
if (isNull(initNode)) {
console.log('根节点不存在!')
return []
}
// 树的递归方法
var treeRecursion = function (treeList, key, maxHierarchy) {
var treeChildren = []
treeList.forEach(row => {
if (row.pId === key) {
if (maxHierarchy === 0) {
return treeChildren
}
treeChildren.push(row)
var children = treeRecursion(treeList, row.id, maxHierarchy - 1)
if (children.length > 0) {
row.children = children
}
}
})
return treeChildren
}
initNode.children = treeRecursion(treeList, initNodeKey, config.maxHierarchy)
return [initNode]
}
/**
* @function
* @name treeProduceList
* @description 方法描述:树结构数据生成列表
* @param {Array} treeData 数组
* @param {*} childrenField 子节点字段名, 默认为 children
* @param {String} filterField 过滤字段名,如果需要筛选的话传入,否则可不传
* @param {Array} filterValues 过滤字段值,多值用','隔开,如 '1,2,3' 这样子
* @example treeProduceList([{"id":"1","label":"node1","children":[{"id":"2","pId":"1","label":"node2"}]}], 'children')
* @returns {Array} - 数组生成树形数据
*/
export function treeProduceList (treeData, childrenField = 'children', filterField, filterValues) {
function deepClone (source) {
if (!source && typeof source !== 'object') {
throw new Error('error arguments', 'shallowClone')
}
const targetObj = source.constructor === Array ? [] : {}
for (const keys in source) {
if (source.hasOwnProperty(keys)) {
if (source[keys] && typeof source[keys] === 'object') {
targetObj[keys] = source[keys].constructor === Array ? [] : {}
targetObj[keys] = deepClone(source[keys])
} else {
targetObj[keys] = source[keys]
}
}
}
return targetObj
}
treeData = deepClone(treeData)
var array = []
treeData.forEach(item => {
var children = item[childrenField]
delete item[childrenField]
if (filterValues) {
var values = filterValues.split(',')
for (var i = 0; i < values.length; i++) {
if (item[filterField] === values[i]) {
array.push(item)
break
}
}
} else {
array.push(item)
}
if (children instanceof Array) {
array = array.concat(treeProduceList(children, childrenField, filterField, filterValues))
}
})
return array
}