const createDragTree = function (setting) { class DragTree { /** * 构造函数 */ constructor(setting) { // 无索引 this.datas = []; // 以key为索引indexedDB this.items = {}; // 以排序为索引 this.nodes = []; // 根节点 this.children = []; // 树设置 this.setting = setting; } /** * 树结构根据显示排序 */ sortTreeNode(isResort) { const self = this; const addSortNodes = function (nodes) { if (!nodes) { return } for (let i = 0; i < nodes.length; i++) { self.nodes.push(nodes[i]); nodes[i].index = self.nodes.length - 1; if (!isResort) { nodes[i].children = self.getChildren(nodes[i]); } else { nodes[i].children.sort((a, b) => { return a[self.setting.order] - b[self.setting.order]; }) } addSortNodes(nodes[i].children); } }; this.nodes = []; if (!isResort) { this.children = this.getChildren(); } else { this.children.sort((a, b) => { return a[self.setting.order] - b[self.setting.order]; }); } addSortNodes(this.children); } /** * 加载数据(初始化), 并给数据添加部分树结构必须数据 * @param datas */ loadDatas(datas) { const self = this; // 清空旧数据 this.items = {}; this.nodes = []; this.datas = []; this.children = []; // 加载全部数据 datas.sort(function (a, b) { return a[self.setting.level] - b[self.setting.level]; }); for (const data of datas) { const keyName = itemsPre + data[this.setting.id]; if (this.items[keyName]) continue; const item = JSON.parse(JSON.stringify(data)); item.children = []; item.expanded = true; item.visible = true; if (item[setting.pid] === setting.rootId) { this.children.push(item); } else { const parent = this.getParent(item); if (!parent) continue; parent.children.push(item); } this.items[keyName] = item; this.datas.push(item); } this.children.sort((a, b) => { return a[self.setting.order] - b[self.setting.order]; }); this.sortTreeNode(true); } getItemsByIndex(index) { return this.nodes[index]; } /** * 根据id获取树结构节点数据 * @param {Number} id * @returns {Object} */ getItems(id) { return this.items[itemsPre + id]; }; getNodeIndex(node) { return this.nodes.indexOf(node); } /** * 查找node的parent * @param {Object} node * @returns {Object} */ getParent(node) { return this.getItems(node[this.setting.pid]); }; getTopParent(node) { const parents = this.getAllParents(node); parents.sort((a, b) => { return a.level - b.level; }); return parents[0]; }; getAllParents(node) { const parents = []; if (!node) return parents; let vP = this.getParent(node); while (vP) { parents.push(vP); vP = this.getParent(vP); } return parents; } /** * 查找node的前兄弟节点 * @param node * @returns {*} */ getPreSiblingNode(node) { if (!node) return null; const parent = this.getParent(node); const siblings = parent ? parent.children : this.children; const index = siblings.indexOf(node); return (index > 0) ? siblings[index - 1] : null; } /** * 查找node的后兄弟节点 * @param node * @returns {*} */ getNextSiblingNode(node) { const parent = this.getParent(node); const siblings = parent ? parent.children : this.children; const index = siblings.indexOf(node); if (index >= 0 && index < siblings.length - 1) { return siblings[index + 1]; } else { return null; } } /** * 查询node的已下载子节点 * @param {Object} node * @returns {Array} */ getChildren(node) { const setting = this.setting; const pid = node ? node[setting.id] : setting.rootId; const children = this.datas.filter(function (x) { return x[setting.pid] === pid; }); children.sort((a, b) => { return a[setting.order] - b[setting.order]; }); return children; }; /** * 递归方式 查询node的已下载的全部后代 (兼容full_path不存在的情况) * @param node * @returns {*} * @private */ _recursiveGetPosterity(node) { let posterity = node.children; for (const c of node.children) { posterity = posterity.concat(this._recursiveGetPosterity(c)); } return posterity; }; /** * 查询node的已下载的全部后代 * @param {Object} node * @returns {Array} */ getPosterity(node) { const self = this; const posterity = this._recursiveGetPosterity(node); posterity.sort(function (x, y) { return self.getNodeIndex(x) - self.getNodeIndex(y); }); return posterity; }; /** * 查询node是否是父节点的最后一个子节点 * @param {Object} node * @returns {boolean} */ isLastSibling(node) { const siblings = this.getChildren(this.getParent(node)); return (siblings && siblings.length > 0) ? node[this.setting.order] === siblings[siblings.length - 1][this.setting.order] : false; }; /** * 查询node是否是父节点的最后一个可见子节点 * @param {Object} node * @returns {boolean} */ isLastViewSibling(node) { const siblings = (this.getChildren(this.getParent(node))).filter(x => { return !x.filter }); return (siblings && siblings.length > 0) ? node.order === siblings[siblings.length - 1].order : false; }; /** * 得到树结构构成id * @param node * @returns {*} */ getNodeKey(node) { return node[this.setting.id]; }; /** * 刷新子节点是否可见 * @param {Object} node * @private */ _refreshChildrenVisible(node) { if (!node.children) { node.children = this.getChildren(node); } if (node.children && node.children.length > 0) { for (const child of node.children) { child.visible = node.expanded && node.visible && !child.filter; this._refreshChildrenVisible(child); } } }; /** * 设置节点是否展开, 并控制子节点可见 * @param {Object} node * @param {Boolean} expanded */ setExpanded(node, expanded) { node.expanded = expanded; this._refreshChildrenVisible(node); }; /** * 递归 设置节点展开状态 * @param {Array} nodes - 需要设置状态的节点 * @param {Object} parent - nodes的父节点 * @param {Function} checkFun - 判断节点展开状态的方法 * @private */ _recursiveExpand(nodes, parent, checkFun) { for (const node of nodes) { const expanded = checkFun(node); if (node.expanded !== expanded) { node.expanded = expanded; } node.visible = parent ? (parent.expanded && parent.visible && !node.filter) : !node.filter; this._recursiveExpand(node.children, node, checkFun); } } /** * 自定义展开规则 * @param checkFun */ expandByCustom(checkFun) { this._recursiveExpand(this.children, null, checkFun); // this._saveMarkExpandFold(); } /** * 展开到第几层 * @param {Number} level - 展开层数 */ expandByLevel(level) { const levelField = this.setting.level; this.expandByCustom(function (n) { return n[levelField] < level; }); } /** * 自动展开节点node * @param node * @returns {*} */ autoExpandNode(node) { const parents = this.getAllParents(node); const reload = []; for (const p of parents) { if (!p.expanded) { reload.push(p); this.setExpanded(p, true); } } return reload; } /** * 加载数据(动态),只加载不同部分 * @param {Array} datas * @return {Array} 加载到树的数据 * @privateA */ _updateData(datas) { datas = datas instanceof Array ? datas : [datas]; let loadedData = []; for (const data of datas) { let node = this.getItems(data[this.setting.id]); if (node) { for (const prop in data) { if (data[prop] !== undefined && data[prop] !== node[prop]) { if (prop === this.setting.pid) { loadedData.push(this.getItems(node[this.setting.pid])); loadedData.push(this.getItems(data[this.setting.pid])); } if (prop === this.setting.order) { loadedData = loadedData.concat(this.getPosterity(node)); } node[prop] = data[prop]; } } loadedData.push(node); } } loadedData = _.uniq(loadedData); for (const node of loadedData) { if (node) { node.children = this.getChildren(node); node.expanded = node.children.length === 0 ? true : node.children[0].visible; } else { this.children = this.getChildren(null); } } this.sortTreeNode(true); return loadedData; }; /** * 加载数据(动态),只加载不同部分 * @param {Array} datas * @return {Array} 加载到树的数据 * @privateA */ _loadData(datas) { datas = datas instanceof Array ? datas : [datas]; const loadedData = [], resortData = []; for (const data of datas) { let node = this.getItems(data[this.setting.id]); if (node) { const parent = this.getItems(node[this.setting.pid]); for (const prop in data) { if (data[prop] !== undefined && data[prop] !== node[prop]) { node[prop] = data[prop]; if (parent && resortData.indexOf(parent) === -1) { resortData.push(parent); } } } loadedData.push(node); } else { const keyName = itemsPre + data[this.setting.id]; const node = JSON.parse(JSON.stringify(data)); this.items[keyName] = node; this.datas.push(node); node.expanded = true; node.visible = true; loadedData.push(node); if (resortData.indexOf(node) === -1) { resortData.push(node); } const parent = this.getItems(node[this.setting.pid]); if (parent && resortData.indexOf(parent) === -1) { resortData.push(parent); } else { resortData.push(this.setting.rootId); } } } for (const node of resortData) { if (node && node !== this.setting.rootId) { node.children = this.getChildren(node); } else { this.children = this.getChildren(null); } } this.sortTreeNode(true); for (const node of loadedData) { if (!node.expanded) { this.setExpanded(node, true); } } return loadedData; }; /** * 清理数据(动态) * @param datas * @private */ _freeData(datas) { datas = datas instanceof Array ? datas : [datas]; const freeDatas = []; const removeArrayData = function (array, data) { const index = array.indexOf(data); array.splice(index, 1); }; for (const data of datas) { const node = this.getItems(data); if (node) { freeDatas.push(node); node.deleteIndex = this.nodes.indexOf(node); delete this.items[itemsPre + node[this.setting.id]]; if (node[this.setting.pid] !== this.setting.rootId) { const parent = this.getItems(node[this.setting.pid]); if (parent) { removeArrayData(parent.children, node); } } else { removeArrayData(this.children, node); } removeArrayData(this.datas, node); } } for (const node of freeDatas) { removeArrayData(this.nodes, node); } return freeDatas; }; /** * 因为提交其他数据,引起的树结构数据更新,调用该方法 * * @param data - 更新的数据 {update, create, delete} * @returns {{}} */ loadPostData(data) { const result = {}; if (data.delete) { result.delete = this._freeData(data.delete); } if (data.create) { result.create = this._loadData(data.create); } if (data.update) { result.update = this._updateData(data.update); } return result; } recursiveFun(children, fun) { if (!fun) return; if (!children || children.length === 0) return; for (const c of children) { this.recursiveFun(c.children, fun); fun(c); } } } return new DragTree(setting); };