写着玩的 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();
