我正在使用jQuery构建购物应用程序。在文本输入中输入文本并按下Enter键会添加一个新项目。将鼠标悬停在该项目上并单击“删除”将删除该项目。点击一个项目会将其交叉。
在文本输入中添加新列表项后,将应用正确的类,但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
答案 0 :(得分: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() {
...
})
这样效率更高。
答案 1 :(得分:0)
因为,例如,当您运行附加事件的此函数时,您添加的相关.delete
项的元素仍然不存在。因此,虽然$(".delete").hide();
在页面加载(或$(document).ready()
,实际上)中对DOM中的项目非常有用,但它无法告诉.delete
尚不存在的项目去做。想象一下$(document).ready()
和课堂上的初始说明一样。如果你上课迟到,你会错过说明。
你基本上有两种选择。
1)利用Event Bubbling。当事件发生在DOM中的某个项目时,它会将事件冒泡到DOM中的其他父项。因此,当您点击一个按钮时,点击&#39;事件在DOM中冒泡,包含<body>
在内的所有包含元素都知道它发生了。事实证明这很方便,因为您稍后添加到DOM的项目仍会将其事件冒泡。这意味着您可以将侦听器附加到外部元素(如<body>
),检查哪个元素是事件的来源,然后执行某些操作。 jQuery,它已成为一个深思熟虑的库,包括一个通过on
method执行此操作的简单方法。您可以像这样重写\\cross off list;
方法:
$('body').on('click', '.tile', function() {
$(this).toggleClass("deleteAction");
});
2)将$(document).ready()
内的所有内容包裹在function cartInit()
这样的单独命名函数中,并随时$("input[name='shopping_item']").change()
调用该函数。只是,不要这样做。使用事件冒泡。 :)
答案 2 :(得分:0)
问题是您是直接将事件附加到每个单独的元素,并且只有在文档准备就绪时才会执行此操作。这意味着稍后添加的所有后续元素都不会附加任何处理程序。
要解决此问题,您应该使用事件委派,这基本上意味着您将处理程序附加到父节点而不是每个单独的元素。来自孩子的事件将冒泡到父节点,在那里你可以拦截它们。 jQuery让你指定一个委托选择器,以便你可以指定感兴趣的子节点。
例如,以下内容会捕获.tile
容器中.shopping_item_list
元素的每次点击。
$('.shopping_item_list').on('click', '.tile', function () {
//do something
});
现在,关于在悬停时显示/隐藏元素,我不会使用JS。 CSS足以表达该行为。例如,如果您只想在.delete
元素悬停时显示.tile
元素,则可以执行此操作。
.tile .delete {
display: none;
}
.tile:hover .delete {
display: block;
}