我正在用jQuery创建一个简单的待办事项清单。这是我使用JavaScript和jQuery的第一步。如何改善我的代码?用户在输入字段中输入任务,然后按“ Enter”提交。双击,他可以编辑他的记录。他可以标记复选框,并且记录将完成。通过单击底部的复选框,所有记录将被标记为已完成。按钮“清除竞争”会删除所有标记为已完成的记录。




 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> 




评论

请不要鼓励用户删除他们的小提琴。我知道有些人喜欢StackSnippets,但是对于我想提出的建议,他们非常不便。

您可以使用客户端MVC(模型-视图-控制器)框架。有一个站点可以比较各种框架的功能:TodoMVC我练习AngularJS(由Google)已经有几个月了,即使它并不总是那么容易,它也非常强大。使用Angular,您可以在控制器内通过数据绑定来创建“待办事项”列表。这是一个使用AngularJS的简单“待办事项列表”的小提琴。

由于至今还没有人提及,因此添加注释以帮助自己从现在起两年后浏览此代码总是很不错的。

#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();
  }
});


希望有帮助!