如何通过两个按钮重排Div并持久化排序结果?
问题描述
通过foreach循环渲染多个列表项,希望通过上下按钮实现列表项重排,并且保存排序结果,刷新页面后仍保持新顺序。
已完成工作
- 用JavaScript实现了列表项的上下移动
- 在Lesson类中添加了
public int OrderNum字段,列表项按OrderNum升序排列 - 问题:点击按钮时无法修改对应Lesson的OrderNum值并完成保存
现有代码
C# Lesson类
public class Lesson : IModel { public override String partitionKey { get => CourseId; } [Required] public string CourseId { get; set; } [Required] [StringLength(256, ErrorMessage = "Maximum {1} characters")] public string Title { get; set; } [Required] public string Content { get; set; } public string ImageID { get; set; } public string ImageURL { get => (ImageID != null) ? Storage.Image.Path(ImageID) : null; } public int OrderNum { get; set; } }
HTML 渲染代码
@foreach (var Lesson in Model.Lessons.OrderBy(x => x.OrderNum)) { <li class="list-group-item" data-lesson-id="@Lesson.id"> <a href="@Url.Action("Index","Lesson", new { CourseCategory = Model.Course.Category, CourseID = Model.Course.id, Lesson.id })">@Lesson.OrderNum</a> @if (AppUser.CurrentUser.Areas.Admin) { <a class='up' href='#'><i class="fa-solid fa-arrow-up fa-lg"></i></a> <a class='down' href='#'><i class="fa-solid fa-arrow-down fa-lg"></i></a> <div class="Edit-Buttons-L"> <div> <a href="@Url.Action("EditLesson", "Lesson", new { CourseCategory = Model.Course.Category, CourseID = Model.Course.id, Lesson.id })"> <i class="fa-regular fa-pen-to-square fa-lg"></i> </a> </div> <div> <form action="@Url.Action("DeleteLesson","Lesson", new{CourseCategory = Model.Course.Category, CourseID = Model.Course.id, Lesson.id})" method="post"> <button type="submit" class="fa-regular fa-trash-can fa-lg" value="Delete"></button> </form> </div> </div> } </li> }
现有JavaScript代码
window.onload = function () { var upLink = document.querySelectorAll(".up"); for (var i = 0; i < upLink.length; i++) { upLink[i].addEventListener('click', function () { var wrapper = this.parentElement; if (wrapper.previousElementSibling) wrapper.parentNode.insertBefore(wrapper, wrapper.previousElementSibling); }); } var downLink = document.querySelectorAll(".down"); for (var i = 0; i < downLink.length; i++) { downLink[i].addEventListener('click', function () { var wrapper = this.parentElement; if (wrapper.nextElementSibling) wrapper.parentNode.insertBefore(wrapper.nextElementSibling, wrapper); }); } }
解决方案
要实现排序保存,需要在前端移动元素后收集排序信息,发送到后端更新数据库,步骤如下:
1. 修改HTML,添加Lesson ID标识
给每个列表项添加data-lesson-id属性,用于后续获取对应Lesson的ID(已在上面的HTML代码中修改)
2. 更新JavaScript,添加保存逻辑
修改JS代码,在移动元素后调用保存函数,将新的排序发送到后端:
window.onload = function () { // 阻止默认跳转行为 function preventDefault(e) { e.preventDefault(); } // 向上移动逻辑 document.querySelectorAll(".up").forEach(link => { link.addEventListener('click', function (e) { preventDefault(e); const wrapper = this.closest('.list-group-item'); if (wrapper.previousElementSibling) { wrapper.parentNode.insertBefore(wrapper, wrapper.previousElementSibling); saveLessonOrder(); } }); }); // 向下移动逻辑 document.querySelectorAll(".down").forEach(link => { link.addEventListener('click', function (e) { preventDefault(e); const wrapper = this.closest('.list-group-item'); if (wrapper.nextElementSibling) { wrapper.parentNode.insertBefore(wrapper.nextElementSibling, wrapper); saveLessonOrder(); } }); }); // 保存排序到后端 function saveLessonOrder() { // 收集当前排序的Lesson ID和对应的OrderNum const lessonOrder = Array.from(document.querySelectorAll('.list-group-item')).map((item, index) => ({ LessonId: item.dataset.lessonId, OrderNum: index + 1 // 排序从1开始,可根据需求调整 })); // 获取防伪造令牌(ASP.NET必填) const token = document.querySelector('input[name="__RequestVerificationToken"]')?.value; if (!token) { alert('缺少验证令牌,请刷新页面重试'); return; } // 发送POST请求 fetch('@Url.Action("UpdateLessonOrder", "Lesson")', { method: 'POST', headers: { 'Content-Type': 'application/json', 'RequestVerificationToken': token }, body: JSON.stringify(lessonOrder) }) .then(response => { if (!response.ok) throw new Error('保存失败'); return response.json(); }) .then(() => { // 更新页面显示的OrderNum document.querySelectorAll('.list-group-item').forEach((item, index) => { const orderEl = item.querySelector('a:first-child'); if (orderEl) orderEl.textContent = index + 1; }); }) .catch(err => { console.error('保存出错:', err); alert('排序保存失败,请重试'); }); } };
3. 添加后端接口
在LessonController中添加接收排序更新的接口,同时创建对应的DTO类:
// DTO类,用于接收前端发送的排序数据 public class LessonOrderUpdateDto { public string LessonId { get; set; } public int OrderNum { get; set; } } // LessonController中的方法 [HttpPost] public IActionResult UpdateLessonOrder([FromBody] List<LessonOrderUpdateDto> lessonOrders) { if (lessonOrders == null || !lessonOrders.Any()) { return BadRequest("无有效排序数据"); } // 遍历更新每个Lesson的OrderNum foreach (var update in lessonOrders) { var lesson = _lessonRepository.GetById(update.LessonId); // 替换为你的数据获取逻辑 if (lesson != null) { lesson.OrderNum = update.OrderNum; _lessonRepository.Update(lesson); // 替换为你的数据更新逻辑 } } _lessonRepository.SaveChanges(); // 保存到数据库 return Ok(new { Success = true }); }
4. 页面添加防伪造令牌
在页面的<form>外或合适位置添加ASP.NET防伪造令牌,确保POST请求能通过验证:
@Html.AntiForgeryToken()
内容的提问来源于stack exchange,提问作者user20654632
相关产品推荐
相关产品推荐

