【问题标题】:How to reexecute java script when new elements added to document model将新元素添加到文档模型时如何执行javascript
【发布时间】:2026-01-17 15:10:01
【问题描述】:

我为带有产品列表的页面实现了分页和过滤。

@model ProductFiltersViewModel

...

<div class="row">
    <aside class="col-3">
        <nav class="sidebar card py-2 mb-4">
            <ul class="nav flex-column" id="nav_accordion">
                <form asp-action="LoadGames" id="filters-form">
                
                    <input type="hidden" asp-for="PaginationInfo.PageNumber" />
                    <li class="nav-item">
                        <div class="container-fluid">
                            <span>Page Size</span>
                            <select asp-for="PaginationInfo.PageSize" class="form-select">
                                <option value="2" selected>2</option>
                                <option value="10">10</option>
                                <option value="20">20</option>
                                <option value="50">50</option>
                                <option value="100">100</option>
                            </select>
                        </div>
                    </li>
//Filters here not important for the question//
                </form>

            </ul>
        </nav>
    </aside>
    <div class="col-9" id="loaded-games">
        <div class="table-responsive">
            <table class="table table-striped">
                <thead>
                <tr>
                    <th>Name</th>
                    <th>Placed</th>
                    <th>Views</th>
                    <th>Price</th>
                    <th></th>
                </tr>
                </thead>
                <tbody id="loaded-games-rows">
                </tbody>
            </table>
        </div>

        <div id="paging-control" style="display: none;">
            <button class="btn btn-success btn-load-games">Load more</button>
        </div>
    </div>
</div>

@section Scripts
{
    <script type="text/javascript" src="js/LoadGames.js"></script>
    ...
}

所以当我点击“加载更多”按钮 jquery 做 ajax 请求时,获取一定数量的产品(部分视图)并将它们放在页面的末尾。

$(document).ready(function () {
    loadGames($("form#filters-form"), true);

    $(".btn-load-games").click(function () {
        var form = $("form#filters-form");
        loadGames(form);
    });

    function loadGames(form, isInitial = false) {
        $.ajax({
            type: "POST",
            url: "/games",
            data: form.serialize(),
            success: function (response) {
                $("tbody#loaded-games-rows").append(response);
                incrementPageNumber();

                if (isInitial && !checkAndDisplayMessageIfNoGamesFound(response)) {
                    $("div#paging-control").show();
                }

                checkIfAllSuitedGamesAlreadyLoaded(response);
            },
            error: function (response) {
                alert(response.responseText);
            }
        });
    }
});

此部分视图包含产品的原始数据,每个原始数据都有一个“购买”按钮。

@model List<ProductDetailsViewModel>
@foreach (var item in Model)
{
    <tr>
        ...
        <td class="align-middle"> 
            <div class="d-flex justify-content-end">
                @if (item.Discontinued || item.UnitsInStock < 1)
                {
                    <button class="btn-add-to-basket btn btn-success" disabled>Buy</button>
                }
                else
                {
                    <button class="btn-add-to-basket btn btn-success" gamekey="@item.Key">Buy</button>
                }
                ...
            </div>
        </td>
    </tr>
}

<script type="text/javascript" src="js/AddGameToBasket.js"></script>

带有 jquery 的脚本附加到这个部分视图,它发送一个 ajax 请求,并在单击购买按钮时将产品添加到购物篮。 (顺便说一句,我无法将此脚本附加到主视图,因为尚未加载产品,并且 DOM 模型上没有“购买”按钮,所以当我单击按钮时没有任何反应)。

$(document).ready(function () {
    $(".btn-add-to-basket").click(function () {
        var gamekey = $(this).attr("gamekey");

        $.ajax({
            type: "POST",
            url: "/game/" + gamekey + "/buy",
            data: gamekey,
            success: function (response) {
                alert("Added to basket");
            },
            error: function (response) {
                alert(response.responseText);
            }
        });
    });
});

问题是,当加载另一批产品时,先前的按钮也开始监听事件,当我在调用两次的初始加载游戏事件上单击“购买”时,我最终向服务器发出了多个请求。那我该怎么办?

【问题讨论】:

  • 能否请您添加一些可重现的代码...这真的会帮助我们更好地理解!
  • @Sanmeet 已编辑

标签: javascript jquery ajax dom dom-events


【解决方案1】:

当你添加动态元素到 DOM 时,你需要附加事件监听器,可以在创建时完成以避免双重事件附加,这里是一个例子

$('#noevent').click(function(){
  let btn=document.createElement('button');
  btn.textContent ='No';
  $('.container').append(btn)
})

$('#event').click(function(){
  let btn=document.createElement('button');
  btn.textContent ='Yes';
  
  //The new event listener
  $(btn).click(function(){
      console.log('YES!!')
  })
  
  $('.container').append(btn)
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<button id='noevent'>No event</button><button id='event'>With event</button>
<div class='container'></div>

【讨论】:

    【解决方案2】:

    我只记得我之前被警告过这个问题,解决方案是在“主”页面中使用它

    $(document).on("click", ".btn-add-to-basket", function () {
            ... your code here
        });
    

    在局部视图中而不是$(.btn-add-to-basket).click( function () {...} );

    附:对于将来遇到此问题的人,您对更清晰的问题标题有何建议?

    【讨论】:

      【解决方案3】:

      我认为最好的方法是事件委托。

      jQuery Docs - .on() 方法

      例子:

      $( "#dataTable tbody" ).on( "click", "tr", function() {console.log( $( this).text() );});
      

      最好不要“听”文档对象,而是“听”包装动态元素的容器。

      您也可以从这里了解它在 JS 中的工作原理: Event Delegation in JavaScript

      【讨论】: