简体   繁体   English

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

[英]Refactoring JavaScript code in regard to a lot of DOM methods

I'm a beginner in JavaScript, and i'm writing a simple To-do list application. 我是JavaScript的初学者,我正在编写一个简单的待办事项列表应用程序。 That accepts user input and adds it as a task in a form of a checkbox . 它接受用户输入并以checkbox的形式将其添加为任务。

The problem is that, the code has become more and more repetitive, I tried to make functions for the most repeating parts. 问题是,代码变得越来越重复,我试图为最重复的部分创建函数。 But i feel that there's a better way to do that using some kind of DOM native functions. 但我觉得使用某种DOM本机功能有更好的方法。

Here's my code (i'm writing a comment where i feel that there're better choice to make): 这是我的代码(我正在写评论,我觉得有更好的选择):

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 ....



    }); 


}

This is the reason most people use jQuery and template systems like Handlebars or Mustache. 这就是大多数人使用像Handlebars或Mustache这样的jQuery和模板系统的原因。 It's actually a lot faster, not to mention cleaner to implement and thus easier to maintain, to simply insert your complete view block into the DOM instead of manually creating the individual DOM elements and appending them one by one. 它实际上要快得多,更不用说实现更清晰,因此更容易维护,只需将完整的视图块插入DOM,而不是手动创建单个DOM元素并逐个附加它们。

The recommended way to manipulate the DOM using jQuery is to do something like: 使用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');

Creating large DOM constructs in a single go through innerHTML is a lot faster than manually creating and appending the individual elements. 通过innerHTML创建大型DOM构造比手动创建和附加单个元素快得多。

However, this still requires mixing HTML and JS, which is pretty ugly. 但是,这仍然需要混合使用HTML和JS,这非常难看。 So that's why these days developers opt for templates, which allow you to do something like: 所以这就是为什么现在开发人员选择模板,这允许你做类似的事情:

<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>

Then in your click handler: 然后在你的点击处理程序:

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

And from there, you can take it one step further and add two-way data binding, such as through Angular.js, Kockout.js or jsViews (+ jsRender). 从那里,您可以更进一步,添加双向数据绑定,例如通过Angular.js,Kockout.js或jsViews(+ jsRender)。 Then you just have something like this: 然后你就是这样的:

<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>

And in your controller: 在你的控制器中:

$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) { ... };

If you want to minimize your code wherever you can then using a library like jquery would be one of your best options. 如果你想尽可能地减少你的代码,那么使用像jquery这样的库将是你最好的选择之一。

However, if in this case you'd prefer to stick to 'pure' javascript, you could avoid all the appends up there, by adding a method to the Node object of the DOM similar to this one: 但是,如果在这种情况下你更喜欢坚持'纯'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;
        };
    })();
}

This would allow you to do something like 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)​​​;​​​​​

Take a look at the demo here: http://jsfiddle.net/8mjBR/2/ * 看看这里的演示: http//jsfiddle.net/8mjBR/2/ *

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM