+4
-1
@@ -0,2 +1,5 @@ | ||
| 2020/08/25 | ||
| - v1.1.0 添加函数insertBefore、insertAfter、findPathAll,并修改了旧的函数名以使其简短。 | ||
| 2020/08/23 | ||
| - v1.0.0第一版发布 | ||
| - v1.0.0 第一版发布 |
+78
-25
@@ -12,5 +12,7 @@ (function (factory) { | ||
| const treeHanlder = { | ||
| listToTree (list, config = {}) { | ||
| config = Object.assign({}, DEFAULT_CONFIG, config); | ||
| const getConfig = config => Object.assign({}, DEFAULT_CONFIG, config); | ||
| const tools = { | ||
| fromList (list, config = {}) { | ||
| config = getConfig(config); | ||
| const nodeMap = new Map(), result = [], { id, children, pid } = config; | ||
@@ -28,4 +30,4 @@ for (const node of list) { | ||
| treeToList (tree, config = {}) { | ||
| config = Object.assign({}, DEFAULT_CONFIG, config); | ||
| toList (tree, config = {}) { | ||
| config = getConfig(config); | ||
| const { children } = config, result = [...tree]; | ||
@@ -39,4 +41,4 @@ for (let i = 0; i < result.length; i++) { | ||
| treeFindNode (tree, func, config = {}) { | ||
| config = Object.assign({}, DEFAULT_CONFIG, config); | ||
| findNode (tree, func, config = {}) { | ||
| config = getConfig(config); | ||
| const { children } = config, list = [...tree]; | ||
@@ -50,4 +52,4 @@ for (let node of list) { | ||
| treeFindNodeAll (tree, func, config = {}) { | ||
| config = Object.assign({}, DEFAULT_CONFIG, config); | ||
| findNodeAll (tree, func, config = {}) { | ||
| config = getConfig(config); | ||
| const { children } = config, list = [...tree], result = []; | ||
@@ -61,4 +63,4 @@ for (let node of list) { | ||
| treeFindPath (tree, func, config = {}) { | ||
| config = Object.assign({}, DEFAULT_CONFIG, config); | ||
| findPath (tree, func, config = {}) { | ||
| config = getConfig(config); | ||
| const path = [], list = [...tree], visitedSet = new Set(), { children } = config; | ||
@@ -80,28 +82,79 @@ while (list.length) { | ||
| treeFilter (tree, func, config = {}) { | ||
| config = Object.assign({}, DEFAULT_CONFIG, config); | ||
| findPathAll (tree, func, config = {}) { | ||
| config = getConfig(config); | ||
| const path = [], list = [...tree], result = []; | ||
| const visitedSet = new Set(), { children } = config; | ||
| while (list.length) { | ||
| const node = list[0]; | ||
| if (visitedSet.has(node)) { | ||
| path.pop(); | ||
| list.shift(); | ||
| } else { | ||
| visitedSet.add(node); | ||
| node[children] && list.unshift(...node[children]); | ||
| path.push(node); | ||
| func(node) && result.push([...path]); | ||
| } | ||
| } | ||
| return result | ||
| }, | ||
| filter (tree, func, config = {}) { | ||
| config = getConfig(config); | ||
| const { children } = config; | ||
| function filter (list) { | ||
| function listFilter (list) { | ||
| return list.map(node => ({ ...node })).filter(node => { | ||
| node[children] = node[children] && filter(node[children]); | ||
| node[children] = node[children] && listFilter(node[children]); | ||
| return func(node) || (node[children] && node[children].length) | ||
| }) | ||
| } | ||
| return filter(tree) | ||
| return listFilter(tree) | ||
| }, | ||
| treeForEach (tree, func, config = {}) { | ||
| config = Object.assign({}, DEFAULT_CONFIG, config); | ||
| forEach (tree, func, config = {}) { | ||
| config = getConfig(config); | ||
| const list = [...tree], { children } = config; | ||
| for (const node of list) { | ||
| func(node); | ||
| node[children] && list.push(...node[children]); | ||
| for (let i = 0; i < list.length; i++) { | ||
| func(list[i]); | ||
| list[i][children] && list.splice(i + 1, 0, ...list[i][children]); | ||
| } | ||
| }, | ||
| _insert (tree, node, targetNode, config, after) { | ||
| config = getConfig(config); | ||
| const { children } = config; | ||
| function insert (list) { | ||
| let idx = list.indexOf(node); | ||
| idx < 0 ? list.forEach(n => insert(n[children] || [])) : list.splice(idx + after, 0, targetNode); | ||
| } | ||
| insert(tree); | ||
| }, | ||
| insertBefore (tree, newNode, oldNode, config = {}) { | ||
| tools._insert(tree, oldNode, newNode, config, 0); | ||
| }, | ||
| insertAfter (tree, oldNode, newNode, config = {}) { | ||
| tools._insert(tree, oldNode, newNode, config, 1); | ||
| }, | ||
| }; | ||
| const makeHandlers = () => { | ||
| const obj = {}; | ||
| for (let key in tools) { | ||
| if (key.startsWith('_')) continue | ||
| obj[key] = tools[key]; | ||
| } | ||
| return obj | ||
| }; | ||
| const handlers = makeHandlers(); | ||
| const treeHandler = { | ||
| ...handlers, | ||
| createInstance (config) { | ||
| const obj = {}; | ||
| for (let key in treeHanlder) { | ||
| const func = treeHanlder[key]; | ||
| if (func == treeHanlder.createInstance) continue | ||
| for (const key in handlers) { | ||
| const func = handlers[key]; | ||
| obj[key] = (...args) => func(...args, config); | ||
@@ -113,4 +166,4 @@ } | ||
| module.exports = treeHanlder; | ||
| module.exports = treeHandler; | ||
| }))); |
+1
-1
| { | ||
| "name": "tree-tool", | ||
| "version": "1.0.2", | ||
| "version": "1.1.0", | ||
| "description": "为Javascript操作树结构数据提供的一些便捷接口", | ||
@@ -5,0 +5,0 @@ "scripts": { |
+67
-25
@@ -31,9 +31,12 @@ ## JS树结构数据处理工具 | ||
| | ---- | :----: | :----: | | ||
| | 列表结构转树结构 | treeTool.listToTree(list[, config]) | | | ||
| | 树结构转列表结构 | treeTool.treeToList(tree[, config] ) | | | ||
| | 查找符合条件的单个节点 | treeTool.treeFindNode(tree, callback[, config]) | 返回广度优先遍历查找到的第一个符合条件(callback(node)为true)的节点,没有则返回null | | ||
| | 查找符合条件的所有节点 | treeTool.treeFindNodeAll(tree, callback[, config]) | | | ||
| | 查找节点路径 | treeTool.treeFilter(tree, callback[, config]) | 返回符合条件(callback(node)为true)的节点的所有祖先节点有序组成的数组,没有找到节点则返回null | | ||
| | 树结构筛选 | treeTool.treeFindNode(tree, callback[, config]) | 返回符合筛选条件(callback(node)为true)的树节点构成的树,一个节点符合条件,其祖先节点也会被保留返回 | | ||
| | 树结构遍历 | treeTool.treeForEach(tree, callback[, config]) | 对于所有节点node调用callback(node),广度优先 | | ||
| | 列表结构转树结构 | treeTool.fromList(list[, config]) | | | ||
| | 树结构转列表结构 | treeTool.toList(tree[, config] ) | | | ||
| | 查找符合条件的单个节点 | treeTool.findNode(tree, callback[, config]) | 返回广度优先遍历查找到的第一个符合条件(callback(node)为true)的节点,没有则返回null | | ||
| | 查找符合条件的所有节点 | treeTool.findNodeAll(tree, callback[, config]) | | | ||
| | 查找符合条件的单个节点的路径 | treeTool.findPath(tree, callback[, config]) | 返回符合条件(callback(node)为true)的节点的所有祖先节点有序组成的数组,没有找到节点则返回null | | ||
| | 查找符合条件的所有节点的路径 | treeTool.findPathAll(tree, callback[, config]) | 返回符合条件(callback(node)为true)的节点路径组成的数组 | | ||
| | 树结构筛选 | treeTool.filter(tree, callback[, config]) | 返回符合筛选条件(callback(node)为true)的树节点构成的树,一个节点符合条件,其祖先节点也会被保留返回 | | ||
| | 树结构遍历 | treeTool.forEach(tree, callback[, config]) | 对于所有节点node调用callback(node),深度优先 | | ||
| | 在指定node前插入newNode | treeTool.insertBefore (tree, newNode, oldNode[, config]) { | 如果树中没有oldNode,则不会改变原数组。注意node和newNode的参数顺序,和它们在树中的顺序一致 | | ||
| | 在指定node后插入newNode | treeTool.insertAfter (tree, oldNode, newNode[, config]) { | 如果树中没有oldNode,则不会改变原数组。注意node和newNode的参数顺序,和它们在树中的顺序一致 | | ||
| | 创建闭包了配置项config的实例 | treeTool.createInstance(config) | 为了避免每个函数都传入config参数,你可以使用该API创建一个实例,以上所有API可以当成实例方法使用 | | ||
@@ -99,2 +102,4 @@ | ||
| ```js | ||
| const tree = require('./index') | ||
| function getTree () { | ||
@@ -171,5 +176,5 @@ const tree = [ | ||
| // 列表结构转树 | ||
| function testListToTree () { | ||
| function testFromList () { | ||
| const list = getList() | ||
| const tree = instance.listToTree(list) | ||
| const tree = instance.fromList(list) | ||
| console.log(JSON.stringify(tree, null, 2)) | ||
@@ -179,13 +184,13 @@ } | ||
| // 树结构转列表结构 | ||
| function testTreeToList () { | ||
| function testToList () { | ||
| const tree = getTree() | ||
| const list = instance.treeToList(tree) | ||
| console.log(JSON.stringify(list, null, 2)) | ||
| const list = instance.toList(tree) | ||
| console.log(list.map(i => i.id)) | ||
| } | ||
| // 查找节点 | ||
| function testTreeFindNode () { | ||
| function testFindNode () { | ||
| const callback = node => node.id == '2-1' | ||
| const tree = getTree() | ||
| const result = instance.treeFindNode(tree, callback) | ||
| const result = instance.findNode(tree, callback) | ||
| console.log(JSON.stringify(result, null, 2)) | ||
@@ -195,8 +200,8 @@ } | ||
| // 查找符合条件的所有节点 | ||
| function testTreeFindNodeAll () { | ||
| function testFindNodeAll () { | ||
| const list = getList() | ||
| const tree = instance.listToTree(list) | ||
| const tree = instance.fromList(list) | ||
| const callback = node => node.parentId == '1' | ||
| const result = instance.treeFindNodeAll(tree, callback) | ||
| const result = instance.findNodeAll(tree, callback) | ||
| console.log(JSON.stringify(result, null, 2)) | ||
@@ -206,24 +211,61 @@ } | ||
| // 查找节点路径 | ||
| function testTreeFindPath () { | ||
| function testFindPath () { | ||
| const callback = node => node.id == '2-1' | ||
| const tree = getTree() | ||
| const result = instance.treeFindPath(tree, callback) | ||
| console.log(JSON.stringify(result, null, 2)) | ||
| const result = instance.findPath(tree, callback) | ||
| console.log(result.map(i => i.id)) | ||
| } | ||
| // 查找符合条件的所有节点的路径 | ||
| function testFindPathAll () { | ||
| const callback = node => node.id == '2-1' || node.id == '1-2-1' | ||
| const tree = getTree() | ||
| const result = instance.findPathAll(tree, callback) | ||
| console.log(result) | ||
| } | ||
| // 树节点过滤 | ||
| function testTreeFilter () { | ||
| function testFilter () { | ||
| const callback = node => node.id == '2-1' | ||
| const tree = getTree() | ||
| const result = instance.treeFilter(tree, callback) | ||
| const result = instance.filter(tree, callback) | ||
| console.log(JSON.stringify(result, null, 2)) | ||
| } | ||
| // 树节点遍历 | ||
| function testTreeForEach () { | ||
| // 树节点遍历 深度优先 | ||
| function testForEach () { | ||
| const tree = getTree() | ||
| const idList = [] | ||
| instance.treeForEach(tree, node => idList.push(node.id)) | ||
| instance.forEach(tree, node => idList.push(node.id)) | ||
| console.log(idList) | ||
| } | ||
| // 节点插入:在node前插入newNode | ||
| function testInsertBefore () { | ||
| const tree = getTree() | ||
| const node = instance.findNode(tree, n => n.id == '1-2-1') | ||
| const newNode = { | ||
| id: '1-2-0', | ||
| title: '节点1-2-0' | ||
| } | ||
| instance.insertBefore(tree, newNode, node) | ||
| const idList = [] | ||
| instance.forEach(tree, node => idList.push(node.id)) | ||
| console.log(idList) | ||
| } | ||
| // 节点插入:在node后插入newNode | ||
| function testInsertAfter () { | ||
| const tree = getTree() | ||
| const node = instance.findNode(tree, n => n.id == '1-2-1') | ||
| const newNode = { | ||
| id: '1-2-2', | ||
| title: '节点1-2-2' | ||
| } | ||
| instance.insertAfter(tree, node, newNode) | ||
| const idList = [] | ||
| instance.forEach(tree, node => idList.push(node.id)) | ||
| console.log(idList) | ||
| } | ||
| ``` | ||
@@ -230,0 +272,0 @@ |
13194
28.8%143
45.92%282
17.5%