将新元素添加到文档模型时如何执行 java 脚本

How to reexecute java script when new elements added to document model

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

@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);
            }
        });
    });
});

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

当你向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>

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

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

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

P.S。对于将来遇到此问题的人,对于更清晰的问题标题有什么建议吗?

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

jQuery Docs - .on() 方法

示例:

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

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

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