如何用JavaScript和jQuery实现API数据更新时列表排序滑动动画
问题描述
我需要在从5个不同API获取数据时,实现按价格排序的滑动动画,动画效果类似联赛中低排名选手上升或游戏中的排序动画。以下是我在.cshtml中的代码:
<ul id="externalPharmacyList" @* data-aos="fade-up" *@></ul> <script src="https://code.jquery.com/jquery-3.6.4.min.js"></script> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script> <script> $(document).ready(function () { var data1 = @Html.Raw(Json.Serialize(Model)); var data2 = @Html.Raw(Json.Serialize(Model)); var jsonData = data1.concat(data2); function displaySortedData() { // Modify the sorting function to compare copay values as numbers var sortedJsonData = jsonData.sort(function (a, b) { return parseFloat(a.copay) - parseFloat(b.copay); }); for (var i = 0; i < sortedJsonData.length; i++) { var item = sortedJsonData[i]; var fullAddress = item.address1 + " " + item.address2 + " " + item.city + " " + item.state + " " + item.zipCode; var listItemHtml = ` <li style="display:none;"> <div class="b-m-pharmacy-det"> <div class="b-p-name"> ${item.pharmacyName} <small>${fullAddress}</small> </div> <div class="b-m-qty"> ${item.quantity} ${item.drugName} </div> <div class="b-m-price" style="text-align:right"> ${item.copay} </div> </div> </li>`; $('#externalPharmacyList').append(listItemHtml); } // Apply the slide animation to the list items $('#externalPharmacyList li').slideDown(); } // Call the displaySortedData function after both data sets are concatenated displaySortedData(); }); </script>
当前代码逻辑:将SOAP API返回的Model序列化为JSON,拼接多组数据后按copay字段排序,生成隐藏的<li>元素后统一调用slideDown动画。但我希望在排序过程中呈现动画,而非排序完成后统一显示,请问我哪里出错了,该如何调整?
解决方案
问题根源
当前代码是先一次性完成排序并插入所有元素到DOM,再统一触发显示动画,本质上只是静态展示最终排序结果,没有模拟排序过程中元素位置交换的动态效果,所以看不到“排序时的动画”。
调整步骤
先渲染所有未排序元素到DOM
跳过提前排序的步骤,先把所有数据对应的<li>元素插入列表(设置绝对定位方便后续移动动画),让用户先看到初始的未排序状态。模拟排序过程+逐帧动画
不要用原生sort直接生成最终结果,改用冒泡排序这类步骤直观的算法,每完成一次元素位置交换,就用jQuery的animate方法展示元素移动的动画效果,让排序过程可视化。修改后的完整代码
<ul id="externalPharmacyList" style="position: relative; list-style: none; padding: 0; margin: 0;"></ul> <script src="https://code.jquery.com/jquery-3.6.4.min.js"></script> <script> $(document).ready(function () { // 替换为你的真实多API数据拼接逻辑 var data1 = @Html.Raw(Json.Serialize(Model)); var data2 = @Html.Raw(Json.Serialize(Model)); var jsonData = data1.concat(data2); // 渲染未排序的初始列表项 function renderUnsortedItems() { var list = $('#externalPharmacyList'); list.empty(); var itemHeight = 60; // 每项固定高度,需和动画top值对应 jsonData.forEach(function(item, index) { var fullAddress = item.address1 + " " + item.address2 + " " + item.city + " " + item.state + " " + item.zipCode; var listItemHtml = ` <li style="display:block; position: absolute; top: ${index * itemHeight}px; left: 0; width: 100%; margin: 0; padding: 10px; box-sizing: border-box; background: #fff; border-bottom: 1px solid #eee;"> <div class="b-m-pharmacy-det"> <div class="b-p-name"> ${item.pharmacyName} <small>${fullAddress}</small> </div> <div class="b-m-qty"> ${item.quantity} ${item.drugName} </div> <div class="b-m-price" style="text-align:right"> ${item.copay} </div> </div> </li>`; list.append(listItemHtml); }); } // 冒泡排序+位置交换动画 function animateSorting() { var items = $('#externalPharmacyList li'); var itemsArray = Array.from(items); var swapped; var index = 0; var itemHeight = 60; function bubbleStep() { swapped = false; for (var i = 0; i < itemsArray.length - 1 - index; i++) { var currentCopay = parseFloat(itemsArray[i].querySelector('.b-m-price').textContent.trim()); var nextCopay = parseFloat(itemsArray[i+1].querySelector('.b-m-price').textContent.trim()); if (currentCopay > nextCopay) { // 交换数组中的元素引用 [itemsArray[i], itemsArray[i+1]] = [itemsArray[i+1], itemsArray[i]]; // 动画移动元素到目标位置 $(itemsArray[i]).animate({top: i * itemHeight}, 300); $(itemsArray[i+1]).animate({top: (i+1) * itemHeight}, 300); swapped = true; } } index++; // 等待当前轮动画完成后执行下一轮 if (swapped && index < itemsArray.length) { setTimeout(bubbleStep, 350); } else { // 排序完成后恢复相对定位,避免布局异常 items.css({position: 'relative', top: 'auto'}); } } bubbleStep(); } // 执行流程:先渲染初始列表,延迟启动排序动画 renderUnsortedItems(); setTimeout(animateSorting, 500); }); </script>
关键说明
- 定位逻辑:用绝对定位实现元素上下移动的平滑动画,排序完成后改回相对定位,保证后续页面布局正常。
- 排序算法选择:冒泡排序的交换步骤直观,适合做逐帧动画;如果数据量较大,可替换为插入排序,动画逻辑保持一致。
- 异步API处理:如果是从5个异步API获取数据,需用
Promise.all等待所有请求完成后,再调用renderUnsortedItems,避免数据不全导致的错误。
内容的提问来源于stack exchange,提问作者Sandeep Verma
相关产品推荐
相关产品推荐

