function addListItem()
{
var text = $('#new-text').val();
$("#todo-list").append('<li ><input type="checkbox" class="toggle"/ ><span class="text">'
+ text + ' </span><button class="destroy"></button></li>');
$("#new-text").val('');
}
function clearCompleted()
{
$("#todo-list .toggle:checked").parent().remove();
}
function deleteItem()
{
$(this).parent().remove();
}
function completed() {
if
(
$(this).parent().css('textDecoration') == 'line-through' )
{
$(this).parent().css('textDecoration', 'none');
$(this).parent().css('opacity', '1');
}
else
{
$(this).parent().css('textDecoration', 'line-through');
$(this).parent().css('opacity', '0.50');
}
}
$(document).ready(function(){
$('#new-text').keyup(function(e)
{
if (e.keyCode === 13)
{
addListItem();
}
});
$(document).on('click', '.destroy', deleteItem);
$("#toggle-all").click(function ()
{
$('input:checkbox').not(this).prop('checked', this.checked);
if ( $('li').css('textDecoration') == 'line-through' )
{
$('li').css('textDecoration', 'none');
$('li').parent().css('opacity', '1');
}
else
{
$('li').css('textDecoration', 'line-through');
$('li').parent().css('opacity', '0.5');
}
});
$(document).on('click', '.toggle', completed);
$("#clearcompleted").click(clearCompleted);
$('#todo-list').on('dblclick', 'span', function ()
{
var thisData = this.innerHTML,
$el = $('<input type="text" class="in-edit-text"/>');
$(this).replaceWith($el);
$el.val(thisData).focus();
$(this).find(".text").hide();
$(this).find(".destroy").hide();
}
);
$('#todo-list').on('keyup', '.in-edit-text', (function(e)
{
if (e.keyCode === 13)
{
$(this).replaceWith($('<span class="text">' + $(this).val() + '</span>'));
}
if (e.keyCode == 27) {
$('.in-edit-text').remove();
}
}));
});
html,
body {
margin: 0;
padding: 0;
}
body {
font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
line-height: 1.4em;
background: #f5f5f5;
color: #4d4d4d;
margin: 0 auto;
}
button {
outline: none;
}
input[type="checkbox"] {
width: auto;
}
#new-text {
background: white;
font-size: 24px;
margin: 130px 0 40px 0;
position: relative;
}
#toggle-all {
position: relative;
top: 0px;
left: 0px;
width: 40px;
height: 20px;
}
#todo-list {
margin: 0;
padding: 0;
list-style: none;
}
#todo-list li {
position: relative;
font-size: 24px;
border-bottom: 1px solid lightgrey;
}
#todo-list li .toggle {
text-align: center;
width: 40px;
height: auto;
position: absolute;
top: 0;
bottom: 0;
margin: auto 0;
appearance: none;
}
#todo-list li span {
white-space: pre;
padding: 15px 60px 15px 15px;
color: black;
margin-left: 45px;
display: block;
line-height: 1.2;
}
#todo-list li .destroy {
display: none;
position: absolute;
top: 0;
right: 10px;
bottom: 0;
width: 40px;
height: 40px;
margin: auto 0;
font-size: 30px;
color: #cc9a9a;
margin-bottom: 11px;
}
#todo-list li .destroy:after {
content: '×';
}
#todo-list li:hover .destroy {
display: block;
}
.in-edit-text{
padding: 15px 60px 15px 15px;
margin-left: 45px;
font-size: 24px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1><input type="text" id="new-text" placeholder="Input text here..."/></h1>
<ul id="todo-list">
</ul>
<br>
<input type="checkbox" id="toggle-all"/>
<br>
<br>
<button type="checkbox" id="clearcompleted">Clear completed</button>
#1 楼
使用CSS类而不是内联样式。不用修改每个TODO项的
style
,而使用CSS类。这会将样式转移到它所属的样式表中,并且仍然允许您测试项目以查看其是否已经完成:function completed() {
if ( !$(this).parent().hasClass('completed') ) {
$(this).parent().addClass('completed');
} else {
$(this).parent().removeClass('completed');
}
}
这使您的代码显得更流利,更像语言。
删除多个
$(this)
呼叫。无需多次调用$(this)
。 $
函数在每次调用时都会返回一个新的jQuery
对象。将此调用的返回值保存在变量中。此外,complete
函数始终引用$(this).parent()
,因此将其存储为变量:function completed() {
var $item = $(this).parent();
if ( !$item.hasClass('completed') ) {
$item.addClass('completed');
} else {
$item.removeClass('completed');
}
}
评论
\ $ \ begingroup \ $
为什么不使用toggleClass?顺便说一句,您在第一个代码块中有一个错误:您将一个类添加到元素的父级,但是将其从元素本身中删除。
\ $ \ endgroup \ $
– Flaambino
15年6月15日在20:08
\ $ \ begingroup \ $
@Flambino:修复了代码错误。有趣的事情。我已经在编辑器中修复了该问题,但是忘记复制并粘贴到我的答案中
\ $ \ endgroup \ $
– Greg Burghardt
15年6月15日在20:10
\ $ \ begingroup \ $
很酷-是的,我也经常犯这样的错误:P
\ $ \ endgroup \ $
– Flaambino
2015年6月15日20:11在
#2 楼
冗余属性您有一些冗余属性。第2个body声明上的边距没有做任何事情,因为您没有设置宽度。
html,
body {
margin: 0; /* original */
padding: 0;
}
body {
font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
line-height: 1.4em;
background: #f5f5f5;
color: #4d4d4d;
margin: 0 auto; /* redundant */
}
此外,由于内联元素不接受,所以这不是必需的width属性:
input[type="checkbox"] {
width: auto;
}
冗余选择器
选择器中引用了很多冗余元素。如果您的元素是一个列表,那么如果您要针对其后代之一,则无需引用li元素,因为ul必须包含li元素。换句话说,可以从所有这些选择器中删除
li
:#todo-list li .toggle {
}
#todo-list li span {
}
#todo-list li .destroy {
}
#todo-list li .destroy:after {
}
li的选择器是
#todo-list li:hover .destroy
标记/可用性
您的复选框需要带有标签。点击区域非常小,行动不便的用户将很难在没有标签帮助的情况下点击它们。实际上,您在这里使用跨度是一种令人遗憾的遗憾。
直到您单击最后一个复选框,才表明它的用途。用户不必猜测网站的任何部分。另外,应该禁用它或将其隐藏,直到填充列表为止。
#3 楼
Lyle的杯子对如何改善JavaScript整体给出了很好的答案。我想看一下HTML:不要在标题内输入内容。 HTML元素具有含义,而
<h1>
元素的意思是“这是文档的标题或文档的一部分”。但是似乎您只是在使用它来增大输入。此外,输入不是标题。增大它的大小应该由CSS来处理,因为这是纯粹的可视化操作。无需使用多个
<br>
标签。再次,似乎您正在使用它们进行布局,但是,再次,布局和样式应该使用CSS进行。我看到Greg Burghardt击败了我,但我也建议使用用于样式化已完成项目的类。不要添加内联样式。
#4 楼
3件事评论
一致性
更少的新行
我们都知道这是Enter键,但您应该在此处注释为什么使用魔法数字
$('#new-text').keyup(function(e)
{
if (e.keyCode === 13)
{
addListItem();
}
});
您在代码中使用了不同的支撑样式,这会造成一些混乱。
function completed() {
if
(
$(this).parent().css('textDecoration') == 'line-through' )
{
$(this).parent().css('textDecoration', 'none');
$(this).parent().css('opacity', '1');
}
else
{
$(this).parent().css('textDecoration', 'line-through');
$(this).parent().css('opacity', '0.50');
}
}
这是对JavaScript使用“常规”支撑样式的唯一代码块,但是if语句未使用相同的样式。
if (condition) {
//code
}
这通常是JavaScript的支撑方式
不要在
if (condition) {
和代码块之间插入新行。只需使用较少的新行。看这段代码,我注意到您将条件放在了新行上,请不要这样做。
function completed() {
if
(
$(this).parent().css('textDecoration') == 'line-through' )
{
$(this).parent().css('textDecoration', 'none');
$(this).parent().css('opacity', '1');
}
else
{
$(this).parent().css('textDecoration', 'line-through');
$(this).parent().css('opacity', '0.50');
}
}
这看起来好吗?
function addListItem() {
var text = $('#new-text').val();
$("#todo-list").append('<li ><input type="checkbox" class="toggle"/ ><span class="text">' + text + ' </span><button class="destroy"></button></li>');
$("#new-text").val('');
}
function clearCompleted() {
$("#todo-list .toggle:checked").parent().remove();
}
function deleteItem() {
$(this).parent().remove();
}
function completed() {
if ( $(this).parent().css('textDecoration') == 'line-through' )
{
$(this).parent().css('textDecoration', 'none');
$(this).parent().css('opacity', '1');
}
else
{
$(this).parent().css('textDecoration', 'line-through');
$(this).parent().css('opacity', '0.50');
}
}
$(document).ready(function(){
$('#new-text').keyup(function(e)
{
if (e.keyCode === 13)
{
addListItem();
}
});
$(document).on('click', '.destroy', deleteItem);
$("#toggle-all").click(function () {
$('input:checkbox').not(this).prop('checked', this.checked);
if ( $('li').css('textDecoration') == 'line-through' ) {
$('li').css('textDecoration', 'none');
$('li').parent().css('opacity', '1');
} else {
$('li').css('textDecoration', 'line-through');
$('li').parent().css('opacity', '0.5');
}
});
$(document).on('click', '.toggle', completed);
$("#clearcompleted").click(clearCompleted);
$('#todo-list').on('dblclick', 'span', function () {
var thisData = this.innerHTML,
$el = $('<input type="text" class="in-edit-text"/>');
$(this).replaceWith($el);
$el.val(thisData).focus();
$(this).find(".text").hide();
$(this).find(".destroy").hide();
});
$('#todo-list').on('keyup', '.in-edit-text', (function(e) {
if (e.keyCode === 13) {
$(this).replaceWith($('<span class="text">' + $(this).val() + '</span>'));
}
if (e.keyCode == 27) {
$('.in-edit-text').remove();
}
})
});
评论
\ $ \ begingroup \ $
语法问题:“较少的换行符”->“较少的换行符”
\ $ \ endgroup \ $
– Flaambino
15年6月15日在20:14
#5 楼
这将是我的第一篇评论,这简直让我失望。我要遍历每个函数:首先,我将从保存对todoList的引用开始。这样,您只需调用一次就可以在脚本中使用它:var $todoList = $('#todo-list'); // I use the $ to indicate a jQuery Object
var $newText = $('#newText'); // Dito for newText
addListItem()
var AddListItem_prependString = '<li><input type="checkbox" class="toggle" /><span class="text">';
var AddListItem_appendString = '</span><button class="destroy"></button></li>'
function addListItem(){
$todoList.append(AddListItem_prependString + $('#new-text').val() + AddListItem_appendString);
$newText.val('');
}
我更喜欢函数行上的方括号,但这只是一个见解,但是IMO这样会创建一个更易于阅读的文件
我将
append()
中的字符串取下来并翻了过来。进入vars。函数中的var现在可以解释它们的值,而无需创建长行这样就省去了一些硬编码,您不需要确切的值来了解它的作用
通过将它们放在前面函数,它们存在于全局范围中。
这使函数更轻巧,调用时占用的内存更少
将我的预定义选择器用于
$todoList
和$newText
,节省了两个DOM -lookups clearCompleted()
function clearCompleted(){
$todoList.find(".toggle:checked").closest('li').remove();
}
支架一字排好,IMO更好
使用我的预定义变量
$todoList
,保存DOM查找我也使用find。首先选择一个ID,然后找到子元素,这(几乎?)总是更快。 ID总是超快的,允许jquery使用
document.getElementById()
我将
.parent()
更改为.closest('li')
。 .parent()
可能更快,但是如果您更改HTML,则所有代码都会中断。现在不会了。deleteItem()
function deleteItem(){
if( confirm("Are you sure?") ){
$(this).closest('li').remove();
}
}
支架一字排开,IMO更好
我将
.parent()
更改为.closest('li')
。 .parent()
可能更快,但是如果您更改HTML,则所有代码都会中断。现在不会了。我添加了一个确认。这是可选的,但用户可能会意外单击它。
toggleItemCompleted()
function toggleItemCompleted() {
$(this).closest('li').toggleClass('completedItem') )
}
将函数名称更改为'toggleItemCompleted',它更具描述性,是您的代码正在执行的操作。
样式不应使用Javascript,而应使用CSS
检查类比检查样式要快得多。另外,检查样式是愚蠢的,但是如果您决定不想要换行了吗?您必须因为样式而更改所有JavaScript吗?!
使用了
.toggleClass
,因为这正是您现在要执行的操作我将
.parent()
更改为.closest('li')
。 .parent()
可能更快,但是如果您更改HTML,则所有代码都会中断。现在不会。各种document.ready代码
$(document).ready(function(){
$(document).on('click', '.destroy', deleteItem);
$(document).on('click', '.toggle', toggleItemCompleted);
$("#clearcompleted").click(clearCompleted);
$('#new-text').keyup(function(e){
// Check if enter is pressed:
if (e.keyCode === 13){ addListItem(); }
});
$("#toggle-all").click(function (){
// Set all LI's as compelted/uncompleted based in the toggle-all checkbox
$todoList.find('li').addClass('completedItem', this.checked);
});
$('#todo-list').on('dblclick', 'span', function (){
$el = $('<input type="text" class="in-edit-text"/>');
$(this).replaceWith($el);
$el.val( this.innerHTML ).focus();
$(this).find(".text, .destroy").hide();
});
$('#todo-list').on('keyup', '.in-edit-text', function(e){
// Check if enter is pressed:
if (e.keyCode === 13){
$(this).replaceWith($('<span class="text">' + $(this).val() + '</span>'));
}
// Check if XXX is pressed:
if (e.keyCode == 27) {
$('.in-edit-text').remove();
}
});
});
删除所有换行符,这是意见,但是我认为这样可以更容易理解文件
将所有带有函数的事件处理程序放在一起,更易于扩展。
它们有点丢失了中间代码
#toggle-all
现在使用一个类,保存csslines。切换器具有第二个参数,true将添加该类,false将删除。我们使用此
添加了关于我们正在寻找哪个键的注释
todo-list doubleclick不需要;不需要在变数中使用
this.innerHTML
,已经准备好了它已经存在于
this
中,您只需要使用一次,而无需存储它#6 楼
似乎没有人提到的一个快速项目是使用IIFE。我总是推荐这个。它基本上为您的代码创建了一个私有作用域,并防止您的代码污染全局作用域(这是很不好的事情)。您在全球范围内拥有的代码越多,您的代码与其他人的代码发生冲突的机会就越大。这里是操作方法:
(function( $ ) {
//your code here
})( jQuery );
在IIFE的底部,您可以将一个对象添加到全局范围,并使其包含所有代码:
window.toDo = {
add : addListItem,
clear : clearCompleted,
//etc
};
然后您可以参考像这样的功能:
$('#new-text').on ('keyup', function(e) {
if (e.keyCode === 13) { //enter key
toDo.add();
}
});
希望有帮助!
评论
请不要鼓励用户删除他们的小提琴。我知道有些人喜欢StackSnippets,但是对于我想提出的建议,他们非常不便。您可以使用客户端MVC(模型-视图-控制器)框架。有一个站点可以比较各种框架的功能:TodoMVC我练习AngularJS(由Google)已经有几个月了,即使它并不总是那么容易,它也非常强大。使用Angular,您可以在控制器内通过数据绑定来创建“待办事项”列表。这是一个使用AngularJS的简单“待办事项列表”的小提琴。
由于至今还没有人提及,因此添加注释以帮助自己从现在起两年后浏览此代码总是很不错的。