我是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 ....
});
}
答案 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/ *