You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# .NET MVC项目中无需JavaScript实现动态增删列表项

没问题,我帮你梳理下怎么在.NET MVC里实现这个动态增删复杂对象列表的功能,咱们从后端到前端一步步来:

1. 定义后端模型

首先咱们把Person和它的嵌套Address对象定义好,毕竟要先有模型才能做绑定:

public class Address
{
    public string Street { get; set; }
    public string City { get; set; }
}

public class Person
{
    public string FirstName { get; set; }
    public Address Address { get; set; }
}

然后在控制器里写一个GET方法,用来加载系统中已有的Person数据并返回视图:

public ActionResult Index()
{
    // 这里模拟从数据库/系统获取现有Person列表,你可以替换成真实的数据源
    var existingPersons = new List<Person>
    {
        new Person { FirstName = "Alice", Address = new Address { Street = "123 Main St", City = "New York" } },
        new Person { FirstName = "Bob", Address = new Address { Street = "456 Oak Ave", City = "Los Angeles" } }
    };
    return View(existingPersons);
}
2. 前端视图实现(Razor + JS)

视图要基于List<Person>模型,先渲染已有数据,再实现动态增删的逻辑。我这里用了Bootstrap的样式类来美化界面,你可以根据自己的项目调整:

@model List<Person>

@using (Html.BeginForm("SavePersons", "Home", FormMethod.Post))
{
    <div id="persons-container" class="mb-3">
        <!-- 渲染已有的Person数据 -->
        @for (int i = 0; i < Model.Count; i++)
        {
            <div class="person-item border p-3 mb-3">
                <h5>Person @(i + 1)</h5>
                <div class="mb-2">
                    @Html.LabelFor(m => m[i].FirstName, "First Name")
                    @Html.TextBoxFor(m => m[i].FirstName, new { @class = "form-control", placeholder = "Enter first name" })
                </div>
                
                <div class="address-group mb-2">
                    <h6>Address</h6>
                    <div class="mb-2">
                        @Html.LabelFor(m => m[i].Address.Street, "Street")
                        @Html.TextBoxFor(m => m[i].Address.Street, new { @class = "form-control", placeholder = "Enter street" })
                    </div>
                    <div class="mb-2">
                        @Html.LabelFor(m => m[i].Address.City, "City")
                        @Html.TextBoxFor(m => m[i].Address.City, new { @class = "form-control", placeholder = "Enter city" })
                    </div>
                </div>
                
                <button type="button" class="btn btn-danger remove-person">Remove</button>
            </div>
        }
    </div>

    <button type="button" id="add-person" class="btn btn-primary me-2">Add Person</button>
    <button type="submit" class="btn btn-success">Submit All</button>
}

@section Scripts {
    <script>
        $(document).ready(function() {
            // 点击添加按钮,生成新的Person表单
            $('#add-person').click(function() {
                const container = $('#persons-container');
                const currentIndex = container.children('.person-item').length;
                
                // 构建新的表单元素,注意name属性要符合MVC模型绑定的格式
                const newPersonHtml = `
                    <div class="person-item border p-3 mb-3">
                        <h5>Person ${currentIndex + 1}</h5>
                        <div class="mb-2">
                            <label>First Name</label>
                            <input type="text" name="[${currentIndex}].FirstName" class="form-control" placeholder="Enter first name" />
                        </div>
                        
                        <div class="address-group mb-2">
                            <h6>Address</h6>
                            <div class="mb-2">
                                <label>Street</label>
                                <input type="text" name="[${currentIndex}].Address.Street" class="form-control" placeholder="Enter street" />
                            </div>
                            <div class="mb-2">
                                <label>City</label>
                                <input type="text" name="[${currentIndex}].Address.City" class="form-control" placeholder="Enter city" />
                            </div>
                        </div>
                        
                        <button type="button" class="btn btn-danger remove-person">Remove</button>
                    </div>
                `;
                
                container.append(newPersonHtml);
            });
            
            // 点击删除按钮,移除对应的Person表单,并重新索引确保绑定正常
            $(document).on('click', '.remove-person', function() {
                $(this).closest('.person-item').remove();
                
                // 重新更新所有表单的索引,MVC要求数组索引连续才能正确绑定
                $('#persons-container .person-item').each(function(newIndex) {
                    // 更新标题
                    $(this).find('h5').text(`Person ${newIndex + 1}`);
                    // 更新所有输入框的name属性索引
                    $(this).find('input[name^="["]').each(function() {
                        const oldName = $(this).attr('name');
                        const newName = oldName.replace(/^\[(\d+)\]/, `[${newIndex}]`);
                        $(this).attr('name', newName);
                    });
                });
            });
        });
    </script>
}
3. 后端处理POST请求

最后在控制器里写一个POST方法,接收提交的List<Person>数据:

[HttpPost]
public ActionResult SavePersons(List<Person> persons)
{
    // 先验证模型是否合法
    if (ModelState.IsValid)
    {
        // 这里写你的业务逻辑,比如把数据保存到数据库、更新系统数据等
        // 示例:_personRepository.SaveAll(persons);
        
        // 处理完后重定向回列表页
        return RedirectToAction("Index");
    }
    
    // 如果验证失败,返回视图并保留用户输入的内容
    return View("Index", persons);
}
几个关键提示
  • 模型绑定规则:MVC能正确绑定列表的核心是表单元素的name属性格式必须是[索引].属性名,嵌套对象就是[索引].嵌套对象.属性名,比如[0].Address.Street。
  • 连续索引:删除项之后一定要重新更新后续项的索引,不然MVC会跳过索引不连续的项,导致后端接收的数据不完整。
  • 样式调整:我用了Bootstrap的类,如果你项目里没引入Bootstrap,直接去掉这些类也不影响功能,只是界面会朴素一点。

内容的提问来源于stack exchange,提问作者user2769810

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:18:05