如果再加上右鍵功能,嗯,「PM,請給我幾個人月吧」!
最大的問題應該出在瀏覽器相容性,以及少了一些很好用的 function 吧。
這些問題 jQuery 都解決了,所以今天種一顆樹簡單多了。
程式有三隻:easytree.js、easytree.html 與 easytree.css,當然還有幾張 icon。
easytree.js
var bi = {}; bi.Tree = function(domId) { this.domId = domId; this.dom = null; this.nodes = []; this.nodeSn = 1; this.isShow = false; this.maxLevel = 5; this.logging = true; // 建立根目錄 this.rootNode = new bi.Folder(this, 'EasyTree', true); this.rootNode.isRoot = true; this.nodes[this.rootNode.nodeId] = this.rootNode; // 好用的變數 var that = this; // create the tree dom if not found if ($('#' + this.domId).length == 0) { $('body').append('<div id="' + this.domId + '"></div>'); } this.dom = $('#' + this.domId); // add tree dom class this.dom.addClass('biTree'); // attachEvent - 開關目錄 $('.folderTitle').live('click', function() { var nodeId = $(this).attr('nodeId'); var node = that.get(nodeId); that.toggleFolder(node); }); // attachEvent - 右鍵選單 $('.node, #rcMenu').live("contextmenu", function(e){ return false; }); $('#rcMenu').live("mouseleave", function(e){ $(this).hide(); }); $('.node').live('mousedown', function(e) { if (e.which != 3) { return false; } var nodeId = $(this).attr('nodeId'); var node = that.get(nodeId); var rcMenu = that.getRcMenu(); rcMenu.css({'top': e.pageY + 'px', 'left': e.pageX + 'px'}); rcMenu.empty(); if (node.children) { // folder node rcMenu.append('<div class="item" onclick="tree.addFile(\'New File\', ' + nodeId + ');">Add A File</div>'); rcMenu.append('<div class="item" onclick="tree.addFolder(\'New Folder\', false, ' + nodeId + ');">Add A Folder</div>'); rcMenu.append('<div class="item" onclick="tree.renameNode(' + nodeId + ');">Rename...</div>'); rcMenu.append('<div class="item" onclick="tree.deleteFolder(' + nodeId + ');">Delete</div>'); } else { // file node rcMenu.append('<div class="item" onclick="tree.renameNode(' + nodeId + ');">Rename...</div>'); rcMenu.append('<div class="item" onclick="tree.deleteFile(' + nodeId + ');">Delete</div>'); } }); /** * 取得右鍵選單 */ this.getRcMenu = function() { if ($('#rcMenu').length == 0) { $('body').append('<div id="rcMenu"></div>'); } var rcMenu = $('#rcMenu'); rcMenu.show(); return rcMenu; }; /** * 計算每個 node 的位置 */ this.calculate = function() { $('.node').each(function(){ var p = $(this).offset(); var w = $(this).outerWidth(); var h = $(this).outerHeight(); var node = that.get($(this).attr('nodeId')); node.area['top'] = p.top; node.area['left'] = p.left; node.area['bottom'] = p.top + h; node.area['right'] = p.left + w; }); }; /** * 開啟或關閉目錄 */ this.toggleFolder = function(node) { // 取得目錄包 var fullNodeDom = node.getFullNodeDom(); // 移除舊css fullNodeDom.removeClass('folderopen').removeClass('folderclosed'); // 修改狀態 node.open = !node.open; // 更新css fullNodeDom.addClass(node.open ? 'folderopen' : 'folderclosed'); node.getInsideDom().slideToggle(function(){ // 計算每個 node 的位置 that.calculate(); }); this.log(); }; /** * 新增目錄 */ this.addFolder = function(title, open, parentId) { $('#rcMenu').hide(); var parentNode = null; if (parentId) { parentNode = this.get(parentId); // 只能加在目錄下 if (!parentNode.children) { alert("Can't add something under a file!"); return; } // 層數限制 var parents = parentNode.getNodeDom().parents('.folderInside'); if (parents.length >= this.maxLevel) { alert("Can't add any folders deeper than this!"); return; } } var f = new bi.Folder(this, title, open); if (this.isShow) { // tree 已經 render,必須修改html var html = f.html(); var parentNode = this.get(parentId); // 加到 tree 裡 parentNode.add(f); // 加到 html 裡 parentNode.getInsideDom().append(html); // 沒打開的目錄把它打開 if (!parentNode.open) { this.toggleFolder(parentNode); } // 計算每個 node 的位置 this.calculate(); } else { // tree 尚未 render,先加到 tree 裡 this.add(f); } this.log(); return f; }; /** * 新增檔案 */ this.addFile = function(title, parentId) { $('#rcMenu').hide(); var parentNode = null; if (parentId) { parentNode = this.get(parentId); // 只能加在目錄下 if (!parentNode.children) { alert("Can't add something under a file!"); return; } // 層數限制 var parents = parentNode.getNodeDom().parents('.folderInside'); if (parents.length >= this.maxLevel) { alert("Can't add any files deeper than this!"); return; } } var f = new bi.File(this, title); if (this.isShow) { // tree 已經 render,必須修改html var html = f.html(); // 加到 tree 裡 parentNode.add(f); // 加到 html 裡 parentNode.getInsideDom().append(html); // 沒打開的目錄把它打開 if (!parentNode.open) { this.toggleFolder(parentNode); } // 計算每個 node 的位置 this.calculate(); } else { // tree 尚未 render,先加到 tree 裡 this.add(f); } this.log(); return f; }; /** * 重新命名 */ this.renameNode = function(nodeId) { $('#rcMenu').hide(); var node = this.get(nodeId); var newTitle = prompt('Enter new Title', node.title); if (!newTitle) { return; } // 更新 tree 裡的 node node.title = newTitle; // 更新網頁 node.getNodeDom().html(node.title); this.log(); }; /** * 刪除目錄 */ this.deleteFolder = function(nodeId) { $('#rcMenu').hide(); var node = this.get(nodeId); if (node.isRoot) { alert("Can't delete root node!"); return; } if (!confirm('Are you sure?')) { return; } this.doDeleteFolder(node); }; /** * 執行目錄刪除 */ this.doDeleteFolder = function(node) { // 從 tree 裡移除 var parentNode = this.get(node.getParentNodeId()); parentNode.children = $.grep(parentNode.children, function(obj){ return obj.nodeId != node.nodeId; }); // 從網頁移除 node.getFullNodeDom().slideUp(function(){ node.getFullNodeDom().remove(); // 計算每個 node 的位置 that.calculate(); }); this.log(); }; /** * 刪除檔案 */ this.deleteFile = function(nodeId) { $('#rcMenu').hide(); var node = this.get(nodeId); if (!confirm('Are you sure?')) { return; } this.doDeleteFile(node); }; /** * 執行檔案刪除 */ this.doDeleteFile = function(node) { // 從 tree 裡移除 var parentNode = this.get(node.getParentNodeId()); parentNode.children = $.grep(parentNode.children, function(obj){ return obj.nodeId != node.nodeId; }); // 從網頁移除 node.getNodeDom().slideUp(function(){ node.getNodeDom().remove(); // 計算每個 node 的位置 that.calculate(); }); this.log(); }; /** * 新增 node 到 tree 裡 */ this.add = function(node) { // 放到根目錄下 this.rootNode.children.push(node); // 快速查詢用 this.nodes[node.nodeId] = node; this.log(); }; /** * 快速查詢所有 node */ this.get = function(nodeId) { return this.nodes[nodeId]; }; /** * 將 tree 顯示到網頁裡 */ this.show = function() { this.dom.html(this.rootNode.html()); this.isShow = true; // 計算每個 node 的位置 this.calculate(); this.log(); }; this.log = function(msg, replace) { if (this.logging) { if (msg) { if (replace) { $('#msg').html('<br/>' + msg); } else { $('#msg').append('<br/>' + msg); } } else { $('#msg').html(this.toString()); } } }; this.toString = function() { var s = ' - BiTree Array In Memory - '; $.each(this.rootNode.children, function(idx, obj){ s += "<br/>" + obj; }); return s; }; }; bi.Folder = function(tree, title, open){ this.nodeId = tree.nodeSn++;; this.tree = tree; this.title = title; this.open = open; // 子包 this.children = []; // 是否為根目錄 this.isRoot = false; // 目錄名稱 DOM 物件 this.nodeDom = null; // 目錄包 DOM 物件 this.fullNodeDom = null; // DOM 物件的四邊 this.area = []; this.area['top'] = null; this.area['left'] = null; this.area['bottom'] = null; this.area['right'] = null; /** * 加入檔案或目錄 */ this.add = function(node) { // 放入子包 this.children.push(node); // 放入 tree 包,方便快速尋找 this.tree.nodes[node.nodeId] = node; }; /** * 取得 node 的 DOM 物件 */ this.getNodeDom = function() { if (!this.nodeDom) { this.nodeDom = $('.node' + this.nodeId); } return this.nodeDom; }; /** * 取得目錄包 */ this.getFullNodeDom = function() { // 因為目錄結構不同於檔案,用來取得整個目錄包 if (!this.fullNodeDom) { // 目錄名稱往上一層 this.fullNodeDom = this.getNodeDom().parent(); } return this.fullNodeDom; }; /** * 取得目錄包裡的子包 */ this.getInsideDom = function() { return $('.folderInside' + this.nodeId); }; /** * 取得父層 nodeId */ this.getParentNodeId = function() { return this.getNodeDom().parent().parent().attr('nodeId'); }; this.html = function() { // 目錄包結構為 // 目錄包 folder // - 目錄名稱 folderTitle // - 子包 folderInside // - 其他檔案或目錄 var html = ''; html += '<div class="folder ' + (this.open ? 'folderopen' : 'folderclosed') + '">'; html += '<div class="node folderTitle node' + this.nodeId + '" nodeId="' + this.nodeId + '">' + this.title + '</div>'; html += '<div class="folderInside folderInside' + this.nodeId + '" nodeId="' + this.nodeId + '" style="display: ' + (this.open ? 'block' : 'none') + '">'; $.each(this.children, function(idx, obj){ html += obj.html(); }); html += '</div>'; html += '</div>'; return html; }; this.toString = function() { var s = '[Folder ' + this.nodeId + '] ' + this.title; $.each(this.children, function(idx, obj){ s += "<br/>" + obj; }); return s; }; }; bi.File = function(tree, title) { this.nodeId = tree.nodeSn++;; this.tree = tree; this.title = title; // DOM 物件 this.nodeDom = null; // DOM 物件的四邊 this.area = []; this.area['top'] = null; this.area['left'] = null; this.area['bottom'] = null; this.area['right'] = null; /** * 取得 node 的 DOM 物件 */ this.getNodeDom = function() { if (!this.nodeDom) { this.nodeDom = $('.node' + this.nodeId); } return this.nodeDom; }; /** * 取得父層 nodeId */ this.getParentNodeId = function() { // 往上一層取 nodeId return this.getNodeDom().parent().attr('nodeId'); }; this.html = function() { var html = ''; html += '<div class="node file node' + this.nodeId + '" nodeId="' + this.nodeId + '">'; html += this.title; html += '</div>'; return html; }; this.toString = function() { return '[File ' + this.nodeId + '] ' + this.title; }; };
easytree.css
body { font-size: 14px; } .tree { width: 200px; } #msg { position: absolute; left: 500px; top: 0; margin: 10px; } /***** node *****/ .tree .folderclosed { } .tree .folderopen { } .tree .node { background-repeat: no-repeat; padding: 0 0 0 34px; cursor: pointer; } .tree .node:hover { color: #f30; } .tree .folder { } .tree .folderclosed > .folderTitle { background-image: url(../images/folderClosed.png); } .tree .folderopen > .folderTitle { background-image: url(../images/folderOpen.png); } .tree .folderInside { padding: 0 0 0 17px; } .tree .file { background-image: url(../images/file.png); } /***** rcMenu *****/ #rcMenu { background-color: #eee; border: 1px solid #ddd; position: absolute; padding: 5px; } #rcMenu .item { cursor: pointer; padding: 2px; } #rcMenu .item:hover { color: #fff; background-color: #f90; }easytree.html
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=BIG5"> <title>Easy Tree</title> <link type="text/css" rel="stylesheet" href="style/easytree.css"></link> <script type="text/javascript" src="http://code.jquery.com/jquery-1.7.2.min.js"></script> <script type="text/javascript" src="js/easytree.js"></script> <script type="text/javascript"> var tree; $(function(){ tree = new bi.Tree('easytree'); for (var i=1; i<=5; i++) { var f = new bi.Folder(tree, "Folder_" + i, false); f.add(new bi.Folder(tree, "Sub Folder_" + i, false)); f.add(new bi.File(tree, "File_" + i, "")); tree.add(f); } for (var i=1; i<=10; i++) { tree.addFile("File_" + (i + 5)); } tree.show(); $('#msg').show(); }); </script> </head> <body> <div id="easytree" class="tree"></div> <div id="msg"></div> </body> </html>當然,今天還是可以跟 PM 報個幾個月人力...
看到end那句 我笑了XD
回覆刪除看到end我笑了XD
回覆刪除