将<li>元素添加到<ul>中并为每个元素添加点击事件?

6
我想要在一个
    元素中添加一系列的
  • 元素,并以编程方式为每个元素添加点击事件。
    我不确定如何以整洁、jQuery风格的方式完成这个任务。
    这是我的现有代码:
    <ul id="saved-list"></ul>
    <script type="text/javascript">
    $.each(all_objects, function() {{
        var list_route = "<li><a href='#saved-route'>" + this.text + "</a></li>";
        $('#saved-list').append(list_route);      
        // add unique id (this.id) to item and click event here?
        // pseudocode - onclick: alert(this.id);
    });
    $('#saved-list').refresh('listview'); // jquery mobile list refresh
    </script>
    

    请问如何以编程方式为每个列表项添加点击事件?

    更新:我需要为每个列表项执行稍微不同的操作(假设是一个警报)-抱歉没有表述清楚。


2
你的ul id属性缺少引号,而且你的脚本周围没有脚本块。是复制粘贴出了问题吗? - Jerod Venema
10个回答

15

使用.live().delegate()比担心在创建每个元素时都创建.click()处理程序更好。像这样:

$('#saved-list').delegate('li', 'click', function () {
    // do stuff on click
});

你只需要绑定一次点击事件监听器,它就会对所有ID为saved-list元素后代的 <li> 元素生效。


如果你真的想为每个 <li> 创建单独的点击处理程序(我不建议这样做),以下是一种不错的方法:

$.each(all_objects, function() {
    var $a = $('<a/>', {
        href: '#saved-route',
        text: this.text
    });

    var $li = $('<li/>', {
        click: function () {
            // do stuff on click
        }
    }).append($a);

    $('#saved-list').append($li);
});

抱歉,我没有说清楚,我需要对每个li元素执行不同的操作。(已更新问题) - phil123
听起来不错,谢谢。顺便问一下,为什么您不建议为每个列表元素创建单独的点击处理程序? - phil123
@phil 当使用.live().delegate()时,这并不一定是问题。单击处理程序函数的行为可以根据被单击的元素而异。 - Matt Ball
通常我更喜欢使用.live().delegate()而不是.bind()(或其等效物),以尽量减少事件监听器的数量。许多事件监听器可能会拖慢页面,特别是在旧版浏览器中。请参见http://stackoverflow.com/questions/2629803/和https://dev59.com/D1PTa4cB1Zd3GeqPlawV。 - Matt Ball
如果您在许多元素上对特定事件(或事件集)执行完全相同的逻辑,则在某个公共祖先上创建单个事件侦听器比在您感兴趣的每个单个元素上创建侦听器更轻便。此外,使用.live().delegate()在公共祖先上,您不必担心重新绑定添加的元素的侦听器。这是另一个重要的优势,并且肯定适用于您的情况。 - Matt Ball

6

不要这样做。

与其为每个元素绑定新的事件处理程序(这可能会变得非常昂贵),不如将单个事件处理程序绑定到共同祖先#saved-list上。 事件冒泡意味着祖先元素会收到其后代元素的事件通知,因此你可以在那里处理事件,而不是在原始元素上处理。

类似于这样的代码...

$.each(all_objects, function() {{
    var list_route = "<li><a href='#saved-route'>" + this.text + "</a></li>";
    $('#saved-list').append(list_route);      
});
$('#saved-list').delegate('li', 'click', function() {
    // do something here each time a descendant li is clicked
});

请查看delegate


4

@Matt Ball的回答已经很接近答案了,但我想更清楚地补充一下:您可以根据所点击的元素执行不同的委托操作:

<ul id="saved-list"></ul>
<script type="text/javascript">
var $savedList = $("#saved-list");
$.each(all_objects, function() {
    $savedList.append("<li><a href='#saved-route'>" + this.text + "</a></li>");
});
$savedList.delegate("li", "click", function (e) {
    alert($(this).text());
});

$('#saved-list').refresh('listview'); // jQuery Mobile 列表刷新

请注意,在委托中,this仍然指的是被点击的li元素。


1

你好Phil,在jQuery中,你可以创建DOM对象而不将它们作为文本添加到DOM中。这将使你有机会在它们被添加之前(以及之后)对它们进行操作。

$("<li />")
  .append(
    $("<a />")
     .attr("href" ,"#saved-route")
     .text(this.text))
  .click(function() {
    // your click event
  })
  .appendTo("#saved-list");

1
这不对,你正在将 href 属性添加到 <li> 上,而根本没有创建 <a> - Matt Ball

1
你可以使用live函数,但缺点是你可能需要一些机制来确定哪些已被点击的li项:
$("#saved-list li").live('click', function() {
    //act on click
});

1

在你当前的循环中添加这个代码(或者在循环之后),不就可以了吗?

$('#saved-list li').click(function(){ alert('hello'); });


0
这就是为什么bind存在的原因。
$.each(all_objects, function(index) {{
    $("#saved-list").append("<li id='item" + index + "'><a href='#saved-route'>" + this.text + "</a></li>");
    $("#saved-list li").bind("click", function() {
        alert("Clicked on " + this.id);
    });
});

此外,这种方式非常容易为每个项目创建不同的点击:

$("#saved-list li#item1").bind(...)
$("#saved-list li#item2").bind(...)
$("#saved-list li#item3").bind(...)

.bind('click', ...).click(...) 是相同的东西。 - Matt Ball
没问题;只是指出.click()更简洁。 - Matt Ball

0
$.each(all_objects, function() {{
    var list_route = "<li><a href='#saved-route'>" + this.text + "</a></li>";
    var newLi = $(list_route);
    newLi.click( function(){} ).attr("id","foo");
    //if you want the a
    newLi.find("a").click( function(){} ).attr("id","foo");

    $('#saved-list').append(newLi);              
});

0

.click 函数会将点击事件处理程序函数绑定到任何给定的元素。正如您代码中的注释所提到的,您可以使用ID或其他方式在DOM化之后选择项目,但另一种方法是简单地引用包含要绑定的元素的变量。

例如:

var li = $('<li />');
li.click(function() { ... });

这可能是有些风格的,但 jQuery 的一个特点是它是可链式的。这意味着 jQuery 函数调用始终返回对 jQuery 自身包装集的引用。利用可链接的特性,您可以像这样重新编写上面的代码:
var list = $('#saved-list'); $.each(all_objects, function(i, item) {{
    list.append(
        $('<li />')
            .append(
                $('<a />').text(item.text)
            )
            .click(function() { ... } );
    );
});

0

虽然我不知道这个$('#saved-list').refresh('listview')是什么意思,但以下可能是您要找的内容:

var listItemEls = all_objects.map(function () {
    return $('<li id="' + this.id + '"><a href="#saved-route">' + this.text + '</a></li>')
           .click(function (e) {
               // do whatever here
           })
           .get();
});

$('#saved-list').append(listItemEls);

请注意,我们避免在最后一刻之前将内容附加到DOM中,因为附加操作是昂贵的。
正如其他帖子所提到的,通常使用委托的点击处理程序是更好的方法。它看起来会像这样:
var listItemEls = all_objects.map(function () {
    return $('<li id="' + this.id + '"><a href="#saved-route">' + this.text + '</a></li>')
           .get();
});

$('#saved-list').append(listItemEls)
                .delegate("li", "click", function (e) {
                    // do stuff here.
                });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接