写着玩的 1. [代码] [JavaScript]代码 // @author yanming// @email arist1213@163.com// @time 2016/06/18var data = [{'id': 0,'text': 'Root','children': [{'id': 1,'text': 'Child 1'},{'id': 2,'text': 'Child 2','children': [{'id': 6,'text'
1. [代码][JavaScript]代码
// @author yanming // @email arist1213@163.com // @time 2016/06/18 var data = [{ 'id': 0, 'text': 'Root', 'children': [{ 'id': 1, 'text': 'Child 1' }, { 'id': 2, 'text': 'Child 2', 'children': [ { 'id': 6, 'text': 'Child 6' }, { 'id': 7, 'text': 'Child 5', 'children': [ ] } ] }, { 'id': 3, 'text': 'Child 3', 'children': [ { 'id': 4, 'text': 'Child 4' }, { 'id': 5, 'text': 'Child 5' } ] } ] }]; var Tree = function(tree) { this.TYPE = {MOVE_NODE: "move_node",COPY_NODE: "copy_node",DELETE_NODE: "delete_node",CUT_NODE: "cut_node",PASTE_NODE: "paste_node",}; this.tree = tree || [{'id': 0, 'text': 'Root'}]; this.type = null; this.id = null; this.prefix = "node_"; this.delimiter = "_"; // 在数组指定位置插入元素 Array.prototype.insertNode = function (index, item) { this.splice(index, 0, item); }; } Tree.prototype = { // 打印树 output: function(tree, level) { var _this = this; tree = tree || this.tree; level = level || 0; if (tree) { tree.forEach(function(node){ console.log('-'.repeat(level)+''+node.text+' - id:'+node.id); if (node.children && node.children.length > 0) { _this.output(node.children, level+1); } }) } }, // 遍历树 traverse: function(tree, fn) { var _this = this; tree = tree || this.tree; if (tree && Array.isArray(tree)) { tree.forEach(function(node, index){ fn.call(_this, node, tree, index); if (node && node.children && Array.isArray(node.children) ) { _this.traverse(node.children, fn); } }) } else { fn.call(_this, tree); } }, // 深度克隆一个节点 // clone 'from' object with members from 'to'. If 'to' is null, a deep clone of 'from' is returned // @reference http://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-clone-an-object _clone: function(from, to) { var _this = this; if (from == null || typeof from != "object") return from; if (from.constructor != Object && from.constructor != Array) return from; if (from.constructor == Date || from.constructor == RegExp || from.constructor == Function || from.constructor == String || from.constructor == Number || from.constructor == Boolean) return new from.constructor(from); to = to || new from.constructor(); for (var name in from) { to[name] = typeof to[name] == "undefined" ? _this._clone(from[name], null) : to[name]; } return to; }, // 获取节点 _get: function(id, fn) { var _this = this; var found = false; this.traverse(this.tree, function(node, tree, index) { if (node.id === id) { found = true; fn.call(_this, node, tree, index); } }) if (!found) { throw new Error("can get node id "+id); } }, // 添加子节点指定位置节点 _move: function(id, _node, pos) { this.traverse(this.tree, function(node, tree, index) { if (node.id === id) { if (node.children && Array.isArray(node.children)) { if (pos !== undefined) { node.children.insertNode(pos, _node); } else { node.children.push(_node); } } else { node.children = []; node.children.push(_node); } } }) }, // 删除所有子节点及当前节点 _deleteNodeTree: function(tree) { var _this = this; this.traverse(tree, function(node, tree, index) { if (node.children && node.children.length > 0) { _this._deleteNode(node.children); } // 移除当前节点 tree.splice(index, 1); }) }, // 移动节点 moveNode: function(from, to, pos) { var move_node; this._get(from, function(node, tree, index){ tree.splice(index, 1); move_node = node; }); this._move(to, move_node, pos); }, // 移除当前节点 // @param deleteChildren true 移除所有子节点 // TODO 如果不移除子节点,需要把子节点添加到当前移除节点的父节点中 deleteNode: function(deleteId, deleteChildren) { deleteChildren = deleteChildren || true; var _this = this; this.traverse(this.tree, function(node, tree, index) { if (node.id == deleteId) { if (deleteChildren && node.children && node.children.length > 0) { _this._deleteNodeTree(node.children); } tree.splice(index, 1); } }) }, copyNode: function(id) { this.type = this.TYPE.COPY_NODE; this.id = id; return this; }, cutNode: function(id) { this.type = this.TYPE.CUT_NODE; this.id = id; return this; }, createNode: function(pid, node, pos) { this._move(pid, node, pos); }, // 更新节点 updateNode: function(id, fn) { var _this = this; this._get(id, function(node, tree, index){ fn.call(_this, node, tree, index); }) }, pasteTo: function(pid, pos) { if (this.id) { switch(this.type) { case this.TYPE.CUT_NODE: this.moveNode(this.id, pid, pos); this.reset(); break; case this.TYPE.COPY_NODE: var copy, parent; this._get(this.id, function(node, tree, index){ copy = node; }); this._get(pid, function(node, tree, index){ parent = node; }); // generate new id var suffix = parent.id; var counter = 1; // TODO _clone var copied = this._clone(copy); copied.id = this.prefix+suffix+this.delimiter+(counter); if (copied.children && Array.isArray(copied.children)) { this.traverse(copied.children, function(node, tree, index) { node.id = this.prefix+suffix+this.delimiter+(++counter); }) } else { copied.id = this.prefix+suffix+this.delimiter+counter; } this._move(pid, copied, pos); this.reset(); break; default: throw new Error("illeage action type!"); break; } } }, reset: function() { this.id = null; this.type = null; } } var tree = new Tree(); tree.output(); //tree.updateNode(5, "Node5"); //tree.moveNode(4, 2, 2); //tree.deleteNode(3); //tree.copyNode(3).pasteTo(2, 1); // tree.deleteNode("node_0_2"); // tree.deleteNode("7"); // tree.moveNode("node_0_3", 2); //tree.cutNode(5).pasteTo(2); //tree.createNode(0, {text: 'hello', id: 11}); console.log('-'.repeat(20)); tree.output();