关于许多DOM方法重构JavaScript代码

时间:2012-07-29 19:58:46

标签: javascript refactoring

我是JavaScript的初学者,我正在编写一个简单的待办事项列表应用程序。它接受用户输入并以checkbox的形式将其添加为任务。

问题在于,代码变得越来越重复,我试图为最重复的部分创建函数。但我觉得使用某种DOM本机函数有更好的方法。

这是我的代码(我正在撰写评论,我觉得有更好的选择):

window.onload = function(){
    submitBtn.addEventListener("click", function(){ 

         //Some code ...                

        var task = document.createElement("input"); 
        task.id = "task" + i;
        task.type = "checkbox"; 

        var taskLabel = document.createElement("label"); 
        taskLabel.htmlFor = "task" + i;
        taskLabel.appendChild(document.createTextNode(textBox.value));

         //This is from a function i've created to create buttons
        var deleteBtn = createButton("delete");
        var undoBtn = createButton("undo", "none");
        var divideBtn = createButton("divide");

        var taskContainer = document.createElement("p"); 

        //A LOT of appendChild is happening .. How can i minimize that using 
        //native DOM methods
        taskContainer.appendChild(task); 
        taskContainer.appendChild(taskLabel);
        taskContainer.appendChild(deleteBtn);
        taskContainer.appendChild(divideBtn);
        taskContainer.appendChild(undoBtn);

        taskPool.appendChild(taskContainer);        

         //the rest of the code ....



    }); 


}

2 个答案:

答案 0 :(得分:2)

这就是大多数人使用像Handlebars或Mustache这样的jQuery和模板系统的原因。它实际上要快得多,更不用说实现更简洁,因此更容易维护,只需将完整的视图块插入DOM,而不是手动创建单个DOM元素并逐个附加它们。

使用jQuery操作DOM的推荐方法是执行以下操作:

var taskName = 'task'+i,
    taskLabel = textBox.value,
    taskHtml =
        '<div>
            <input type="checkbox" name="'+taskName+'">
            <label for="'+taskNAme+'">'+taskLabel+'</label>
            <fieldset>
                <button id="btnDel'+i+'">Delete</button>
                <button id="btnDiv'+i+'">Divide</button>
                <button id="btnUndo'+i+'">Undo</button>
            </fieldset>
        </div>';
$(taskHtml).appendTo('#TaskPool');

在单个浏览innerHTML中创建大型DOM构造比手动创建和附加单个元素要快得多。

然而,这仍然需要混合HTML和JS,这非常难看。所以这就是为什么现在开发人员选择模板,这可以让你做类似的事情:

<script id="task-template" type="text/x-handlebars-template">
    <div>
        <input type="checkbox" name="task{{i}}">
        <label for="task{{i}}">{{label}}</label>
        <fieldset>
            <button id="btnDel{{i}}">Delete</button>
            <button id="btnDiv{{i}}">Divide</button>
            <button id="btnUndo{{i}}">Undo</button>
        </fieldset>
    </div>
</script>

然后在你的点击处理程序中:

var source = $("#task-template").html(),
    template = Handlebars.compile(source),
    context = {
      i: i,
      label: textBox.value
    },
    html = template(context);
$('#TaskPool').append(html);

从那里,您可以更进一步,添加双向数据绑定,例如通过Angular.js,Kockout.js或jsViews(+ jsRender)。那么你就是这样的:

<ol id="TasksList">
    <li ng-repeat="task in tasks | orderBy:orderProp">
        <input type="checkbox" name="{{task.name}}" ng:model="task.checked">
        <label for="{{task.name}}">{{task.label}}</label>
        <fieldset>
            <button ng-click="deleteTask(task.id)">Delete</button>
            <button ng-click="divideTask(task.id)">Divide</button>
            <button ng-click="undoTask(task.id)">Undo</button>
        </fieldset>
    </li>            
</ol>

在你的控制器中:

$scope.orderProp = 'id';
$scope.nextId = 0;
$scope.addTask = function(label) {
    var id = $scope.nextId++,
        task = {
            id: id,
            label: label,
            name: 'task'+id,
            checked: false
        };
    $scope.tasks.push(task);
};
$scope.deleteTask = function(id) { ... };
$scope.divideTask = function(id) { ... };
$scope.undoTask = function(id) { ... };

答案 1 :(得分:1)

如果您想尽可能减少代码,那么使用像jquery这样的库将是您最好的选择之一。

但是,如果在这种情况下你更喜欢坚持纯粹的&#39; javascript,你可以通过向DOM的Node对象添加一个类似于这个的方法来避免那里的所有追加:

/* is Node.prototype.multiAppend already defined? */
if( typeof Node.prototype.multiAppend !== "function" ) {
    Node.prototype.multiAppend = (function() {
        /*get the Array.prototype.slice method to use on the returned function*/
        var slice = [].slice;

        /*the function multiAppend comes to be*/
        return function() {
            var i = 0,
                max = arguments.length;

            for (; i < max; i++) {
                this.appendChild(arguments[i]);
            }

            /*allow chainability*/
            return this;
        };
    })();
}

这可以让你做这样的事情:

var item = document.getElementsByClassName('item')[0],

    /*create elements*/
    h1 = document.createElement("h1"),
    div = document.createElement("div"),
    p = document.createElement("p");

    /*append them to item with just one line*/
    item.multiAppend(h1, div, p)​​​;​​​​​

在此处查看演示:http://jsfiddle.net/8mjBR/2/ *