【问题标题】:How to apply classes to input item using jQuery如何使用 jQuery 将类应用于输入项
【发布时间】:2014-06-02 10:39:57
【问题描述】:

我正在使用 jQuery 构建一个购物应用程序。在文本输入中输入文本并按回车键会添加一个新项目。将鼠标悬停在项目上并单击删除将删除该项目。点击一个项目会将其划掉。

在文本输入中添加新列表项后,应用了正确的类,但用于删除和划掉项目的 jquery 函数不起作用。例如,“删除”跨度应在页面加载时隐藏,并在您将鼠标悬停在列表项上时出现,但对于新列表项,删除跨度始终显示。为什么我的函数不适用于我通过输入添加的新项目?

HTML:

<div class="wrapper">
    <form  onsubmit="return false"> <!--return false prevents enter from refreshing page -->
        <input type="text" placeholder="I need to buy..." name="shopping_item">
    </form>
    <ul class="instructions">
        <li>Click on tile to mark complete</li>
        <li class="divider">|</li>
        <li>Hover and click “Delete” to delete</li>
    </ul>  
    <section>
        <h1 class="outline">Shopping List Items</h1>
        <ul class="shopping_item_list">
            <li class="tile">Flowers<span class="delete">Delete</span></li>
            <li class="tile middle">A gift card for mom's birthday<span class="delete">Delete</span></li>
            <li class="tile">A birthday card<span class="delete">Delete</span></li>
            <!-- Do I need to have divs to clear? It looks like it works without them. -->
            <li class="tile">Yogurt<span class="delete">Delete</span></li>
            <li class="tile middle">Applesauce<span class="delete">Delete</span></li>
            <li class="tile">Iced tea<span class="delete">Delete</span></li>

            <li class="tile">Ice cream<span class="delete">Delete</span></li>
            <li class="tile middle">Laundry detergent<span class="delete">Delete</span></li>
            <li class="tile">Sandwich bags<span class="delete">Delete</span></li>

        </ul>
    </section>
</div><!--end wrapper-->

CSS:

.shopping_item_list .delete {
display: block;
position: absolute;
bottom: 0;
left: 0;
right:0;
background-color: #000;
padding-top:10px;
padding-bottom: 10px;
font-family: Verdana, sans-serif;
font-size:18px;
text-align: center;
    }

.deleteAction {
background-color:#b7b7b7 !important; 
text-decoration:line-through;
color:#e1e1e1;
    }

JQuery:

$(document).ready(function() {

//add list item
$("input[name='shopping_item']").change(function() {
    var item = $(this).val();   
    $("<li class='tile'>" + item + "<span class='delete'>Delete</span>" + "</li>").prependTo(".shopping_item_list");
    $(".tile").removeClass("middle");   
    $(".shopping_item_list li:nth-child(3n+2)").addClass("middle");
}); 


// hide delete button
$(".delete").hide();


// delete square
$(".tile").hover(function() {
    $(this).find(".delete").toggle();
});

$(".tile").on("click", ".delete", function() {
    $(this).closest("li.tile").remove(); 
    $(".tile").removeClass("middle");   
    $(".shopping_item_list li:nth-child(3n+2)").addClass("middle");
});


// cross off list 
$(".tile").click(function() {
    $(this).toggleClass("deleteAction");
});


}); // end of ready function

【问题讨论】:

    标签: jquery html css


    【解决方案1】:

    当你运行这样的代码时:

    $(".tile").hover(function() {
       $(this).find(".delete").toggle();
    });
    

    它会在页面上找到所有具有 tile 类的项目,并在它们上安装悬停行为。

    如果您随后将 new 元素添加到具有 tile 类的页面中,则为时已晚。安装悬停行为的代码已经运行。

    解决这个问题的简单方法是改用这个结构:

    $(document).on("mouseenter mouseleave", ".tile", function() {
       $(this).find(".delete").toggle();
    });
    

    这表示通常要注意悬停在文档中具有 tile 类的项目上。因此它将适用于现有项目将来添加的项目。

    请注意,您可以在层次结构的任何级别执行此操作,因此如果您的所有 tile 元素始终位于 .shopping_item_list 内,那么您可以改为执行此操作:

    $(".shopping_item_list").on("mouseenter mouseleave", ".tile", function() {
       ...
    })
    

    这样更有效率。

    【讨论】:

    • 谢谢。我根据您的示例更新了代码,现在可以使用了!
    【解决方案2】:

    问题是您将事件直接附加到每个单独的元素,并且仅在文档准备好时才执行此操作。这意味着以后添加的所有后续元素都不会附加任何处理程序。

    要解决这个问题,您应该使用事件委托,这基本上意味着您将处理程序附加到父节点而不是每个单独的元素。来自孩子的事件将冒泡到您可以拦截它们的父节点。 jQuery 让您指定一个委托选择器,以便您可以指定感兴趣的子代。

    例如,以下代码将捕获对 .tile 容器内 .tile 元素的每次点击。

    $('.shopping_item_list').on('click', '.tile', function () {
        //do something
    });
    

    现在,关于在悬停时显示/隐藏元素,我不会为此使用 JS。 CSS 足够强大来表达这种行为。例如,如果您只想在悬停.tile 元素时显示.delete 元素,您可以这样做。

    .tile .delete {
        display: none;
    }
    
    .tile:hover .delete {
        display: block;
    }
    

    【讨论】:

    • 谢谢。这非常有用,特别是对于显示和隐藏删除范围。
    • 我想两个都选,不知道能不能。我可以吗? :) 两者都很有帮助。我首先看到了第一个答案,所以我用它来修复课堂作业。你的帮助我显示了删除跨度。尽管我同时使用了两者,但您确实更完整地解决了这个问题。我会换成你的。
    【解决方案3】:

    因为,例如,当您运行此附加事件的函数时,您添加的相关.delete 项的元素还不存在。因此,虽然$(".delete").hide(); 在页面加载时对 DOM 中的项目(或实际上是 $(document).ready())非​​常有效,但它无法告诉 .delete 尚不存在的项目该怎么做。想象$(document).ready() 就像在教室里的初始指令集。如果你来晚了,你会错过指示。

    你基本上有两个选择。

    1)使用Event Bubbling。当 DOM 中的某个项目发生事件时,它会将事件冒泡到 DOM 中的其他父项。因此,当您单击一个按钮时,“单击”事件会在 DOM 中冒泡,并且所有包含元素,包括 &lt;body&gt; 都知道它发生了。事实证明这很方便,因为您稍后添加到 DOM 的项目仍然会冒泡它们的事件。这意味着您可以将侦听器附加到外部元素(如&lt;body&gt;)检查哪个元素是事件的来源,然后采取一些行动。 jQuery,它已经成为一个深思熟虑的库,包括一个通过on method 执行此操作的简单方法。您可以像这样重写您的 \\cross off list; 方法:

    $('body').on('click', '.tile', function() {
        $(this).toggleClass("deleteAction");
    });
    

    2) 将您当前在$(document).ready() 中拥有的所有内容包装在一个单独的命名函数中,例如function cartInit(),并在$("input[name='shopping_item']").change() 发生时调用该函数。只是,不要那样做。使用事件冒泡。 :)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-06-03
      • 2010-09-19
      • 1970-01-01
      • 2013-04-16
      • 1970-01-01
      • 1970-01-01
      • 2011-03-11
      • 1970-01-01
      相关资源
      最近更新 更多