简单的任务管理系统(三)

概况

这个任务也做了好久了,最近把重构版本的代码基本写好了,这次重构的目的主要是想减少重复的代码。在这方面个人感觉还算良好,Js代码减少了100行左右。但是重复代码减少的同时,又暴露出了新的弊端。就是出现了很多交叉的代码,大大说代码的结构理想状态下是树状的只有很少的一部分是交叉的,而我的代码现在是网状的。大大说我没有利用好回调函数,以后要加大这方面的练习。

主要的代码
//判断对象是否为空对象
function isNotEmpty(obj) {
    for (var prop in obj) {
        if (obj.hasOwnProperty(prop))
            return true;
    }
    return false;
}

var FLAG_FOLDER = 0;
var FLAG_TASK = 1;
//flag用于标记是是哪种调用 不过当flag实参不传递时 flag的值是undefined
function xhrFunc(url, flag) {
    var xhr = new XMLHttpRequest();
    xhr.open('get', url);
    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4 && xhr.status === 200) {
            //如果后台返回的是空对象 json解析后也是空对象 因此需要判断返回的json解析后是否为空,不能简单判断它是否为null
            var response = JSON.parse(xhr.responseText);

            //先猜flag为undefined
            if ((typeof response === 'string' || isNotEmpty(response)) && flag != undefined) {
                switch (flag) {
                    //根据flag值不同 调用不同的函数 包括窗口刷新时的创建文件夹 
                    case FLAG_FOLDER:
                        for (var i = 0; i < response.length; i++) {
                            create(FLAG_FOLDER, response[i]);
                        }
                        break;
                    case FLAG_TASK:
                        for (var i = 0; i < response.length; i++) {
                            create(FLAG_TASK, response[i]);
                        }
                        break;
                    case 2:
                        var editBox = document.getElementById('editBox');
                        editBox.value = response || '';
                };
            }
        }
    };
    xhr.send();
}
window.addEventListener('load', init);
function init() {
    //load事件发生时从后台读取文件夹列表并创建
    xhrFunc('/api/load-folderLists-when-refresh', FLAG_FOLDER);
    //创建文件夹 文件
    var addFolder = document.getElementsByClassName('feet')[0];
    addFolder.addEventListener('click', function () {
        var folderName = prompt('输入文件夹名:', '');
        if (folderName != null && folderName != '') {
            xhrFunc('/api/create-folder?folderName=' + encodeURIComponent(folderName));
            create(FLAG_FOLDER, folderName);
        }
    });
    var addTask = document.getElementsByClassName('feet')[1];
    addTask.addEventListener('click', function () {
        var openMark0 = document.getElementById('openMark0');
        var folderName = openMark0.getAttribute('folderName');
        if (openMark0 != 'undefined' && openMark0 != null) {
            var taskName = prompt('输入文件名:', '');
            if (taskName != null && taskName != '') {
                xhrFunc('/api/create-task?folderName=' + encodeURIComponent(folderName) +'&taskName=' + encodeURIComponent(taskName));
                create(FLAG_TASK, taskName);
            }
        } else {
            alert('文件必须保存在文件夹中!');
        }
    });

    //保存editBox数据
    var save = document.getElementById('save');
    save.addEventListener('click', saveData);
}
//flag用于表示要添加的是文件夹还是文件 为了和addClassify数组中的元素对应 分别取0和1
//name是用户输入的名字 需要给每个小的item都加上一个name属性 以便再次利用
function create(flag, name) {
    var mainBody = document.getElementsByClassName('mainBody');
    var mainBodyItem = document.createElement('div');
    mainBodyItem.className = 'mainBodyItem' + flag;
    mainBodyItem.addEventListener('click', function () {
        openedMark(this, flag);
    });
    mainBody[flag].appendChild(mainBodyItem);
    if (flag == FLAG_FOLDER) {
        mainBodyItem.setAttribute('folderName', name);
        var folderIcon = document.createElement('span');
        folderIcon.className = 'folderIcon';
        mainBodyItem.appendChild(folderIcon);
    }
    if (flag == FLAG_TASK) {
        mainBodyItem.setAttribute('taskName', name);
        var completeIcon = document.createElement('span');
        completeIcon.className = 'completeIcon';
        mainBodyItem.appendChild(completeIcon);
    }
    var displayName = document.createElement('span');
    displayName.className = 'displayName';
    displayName.innerHTML = name;
    mainBodyItem.appendChild(displayName);
    var removeIcon = document.createElement('span');
    removeIcon.className = 'removeIcon';
    removeIcon.addEventListener('click', function (event) {
        remove(this);
        //阻止冒泡
        event.stopPropagation();
    });
    mainBodyItem.appendChild(removeIcon);
}
//删除操作
function remove(ele) {
    var messageFromUser = confirm('确定要做删除操作吗?数据将被清空!');
    if (messageFromUser != null && messageFromUser != '') {
        var parentEle = ele.parentNode;
        if (parentEle.id == 'openMark0') {
            var name = parentEle.getAttribute('folderName');
            xhrFunc('/api/remove-folder?folderName=' + encodeURIComponent(name));
            cleanUpList(FLAG_FOLDER);
            cleanUpList(FLAG_TASK);
        } else if (parentEle.id == 'openMark1') {
            var name = parentEle.getAttribute('taskName');
            var openFolder = document.getElementById('openMark0');
            var folderName = openFolder.getAttribute('folderName');
            xhrFunc('/api/remove-task?folderName=' + encodeURIComponent(folderName) + '&taskName=' + encodeURIComponent(name));
            var mainBody = document.getElementsByClassName('mainBody')[1];
            mainBody.removeChild(parentEle);
        }
    }
}

//在显示当前打开的文件夹中的文件前,清除掉上一次打开文件夹中显示出的文件列表
function cleanUpList(flag) {
    if (flag == FLAG_FOLDER) {
        var mainBody = document.getElementsByClassName('mainBody')[0];
        var openFolder = document.getElementById('openMark0');
        mainBody.removeChild(openFolder);
    } else if(flag == FLAG_TASK) {
        var mainBody = document.getElementsByClassName('mainBody')[1];
        var mainBodyItems = document.getElementsByClassName('mainBodyItem1');
        while (mainBodyItems.length) {
            mainBody.removeChild(mainBodyItems[0]);
        }      
    }
}


function openedMark(ele, flag) {
    var mainBody = document.getElementsByClassName('mainBody');
    var mainBodyItems = document.getElementsByClassName('mainBodyItem' + flag);
    for (var i = 0; i < mainBodyItems.length; i++) {
        mainBodyItems[i].id = '';
    }
    ele.id = 'openMark' + flag;
    if (flag == FLAG_FOLDER) {
        var folderName = ele.getAttribute('folderName');
        cleanUpList(FLAG_TASK);
        xhrFunc('/api/load-taskLists-when-folderOpened?folderName=' + encodeURIComponent(folderName), FLAG_TASK);
    } else if (flag == FLAG_TASK) {
        var folder = document.getElementById('openMark0');
        var folderName = folder.getAttribute('folderName');
        var taskName = ele.getAttribute('taskName');
        displayTaskName(taskName);
        xhrFunc('/api/read-data-when-taskOpened?folderName=' + encodeURIComponent(folderName) + '&taskName=' + encodeURIComponent(taskName), 2);
    }
}
function saveData() {
    var editBox = document.getElementById('editBox');
    var data = editBox.value;
    var folderName = returnOpenFile()[0];
    var taskName = returnOpenFile()[1];
    if (folderName == null || taskName == null) {
        alert('数据必须保存在文件中!');
    } else {
        xhrFunc('/api/writeData-when-saveButtonClicked?folderName=' + encodeURIComponent(folderName) + '&taskName=' + encodeURIComponent(taskName) + '&data=' + encodeURIComponent(data));
    }
}

function displayTaskName(taskName) {
    var displayTaskName = document.getElementById('displayTaskName');
    displayTaskName.innerHTML = taskName;
}

//返回打开的文件和文件夹
function returnOpenFile() {
    var openFolder = document.getElementById('openMark0');
    var openTask = document.getElementById('openMark1');
    if (openFolder != null || openTask !== null) {
        var folderName = openFolder.getAttribute('folderName');
        var taskName = openTask.getAttribute('taskName');
    }
    return [folderName, taskName];
}

function markCompletedOrNot() {

}
//全部代码已推到我的github https://github.com/shiqiwang/
代码的主要不足
  • 代码不是逻辑清楚的树状结构,各个函数的功能不够单一
  • 没有利用好回调函数拆分函数功能
  • 对于固定的标识符(标签)没有用语义化的常量
总结

代码真的要天天写才行,前面就是因为耽搁了一段时间没写,导致我再次打开的时候,我已经完全忘记了我前面写的函数是准备填充什么函数体的了。

Talk is cheap, show them the code!