ASP.NET Core 7 MVC中复用自定义多选下拉框的方案求助
解决方案:ASP.NET Core 7 MVC 中Bootstrap 5搜索多选下拉的复用与模型绑定
一、用Editor Template实现组件复用+模型自动绑定
Editor Template完全适配你的场景,它能直接绑定主视图模型属性,自动同步选中值,复用性强,操作并不繁琐。
1. 创建Editor Template模板
在Views/Shared/EditorTemplates目录下新建DropDownOption.cshtml,代码如下:
@model YourNamespace.DropDownOption <div class="dropdown bootstrap-multi-select" id="@ViewData.TemplateInfo.GetFullHtmlFieldName(string.Empty)"> <button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false"> @Model.Title </button> <div class="dropdown-menu p-2"> <input type="text" class="form-control mb-2" placeholder="搜索选项" oninput="filterDropdownOptions(this)"> @foreach (var option in Model.Options) { <div class="form-check"> <input class="form-check-input" type="checkbox" name="@ViewData.TemplateInfo.GetFullHtmlFieldName("SelectedValues")" value="@option.Value" @(Model.SelectedValues.Contains(option.Value) ? "checked" : "")> <label class="form-check-label">@option.Text</label> </div> } </div> </div> <script> function filterDropdownOptions(input) { const filterText = input.value.toLowerCase(); const optionItems = input.parentElement.querySelectorAll('.form-check'); optionItems.forEach(item => { const labelText = item.querySelector('.form-check-label').textContent.toLowerCase(); item.style.display = labelText.includes(filterText) ? 'block' : 'none'; }); } </script>
替换YourNamespace为实际命名空间,DropDownOption需包含Title(下拉标题)、Options(键值对集合)、SelectedValues(选中值集合)三个核心属性
2. 主视图中复用组件
在ExportView.cshtml里,直接用EditorFor调用模板:
@model YourNamespace.ExportViewModel <div class="row g-3"> <div class="col-md-6"> @Html.EditorFor(m => m.Property1, "DropDownOption") </div> <div class="col-md-6"> @Html.EditorFor(m => m.Property2, "DropDownOption") </div> </div>
提交表单时,每个下拉框的选中值会自动同步到对应模型属性的SelectedValues集合,无需额外处理。
二、实现Ajax联动过滤
基于上述模板,添加联动逻辑即可实现Property1选值后过滤Property2的选项:
1. 后端写联动接口
在控制器中新增Action,接收Property1的选中值,返回过滤后的Property2选项:
[HttpPost] [ValidateAntiForgeryToken] public IActionResult GetFilteredProperty2Options(List<string> selectedProperty1Values) { // 这里替换成你的业务逻辑:根据Property1选中值过滤Property2选项 var filteredOptions = _yourDataService.GetProperty2Options(selectedProperty1Values); return Json(filteredOptions); }
2. 修改模板添加联动监听
在DropDownOption.cshtml的脚本末尾添加选中监听逻辑:
<script> // 监听当前下拉框的选中变化 document.querySelectorAll('#@ViewData.TemplateInfo.GetFullHtmlFieldName(string.Empty) input[type="checkbox"]').forEach(cb => { cb.addEventListener('change', function() { const selectedValues = Array.from(document.querySelectorAll('#@ViewData.TemplateInfo.GetFullHtmlFieldName(string.Empty) input[type="checkbox"]:checked')) .map(item => item.value); // 通过ViewData判断当前是否是Property1(主视图调用时传入标识) if ('@ViewData["IsTriggerDropdown"]' === "true") { fetch('/YourControllerName/GetFilteredProperty2Options', { method: 'POST', headers: { 'Content-Type': 'application/json', 'RequestVerificationToken': '@Html.AntiForgeryToken()' }, body: JSON.stringify(selectedValues) }) .then(res => res.json()) .then(data => { // 更新Property2的下拉选项 const targetDropdown = document.querySelector('#Property2 .dropdown-menu'); // 清空原有选项(保留搜索框) targetDropdown.innerHTML = '<input type="text" class="form-control mb-2" placeholder="搜索选项" oninput="filterDropdownOptions(this)">'; // 新增过滤后的选项 data.forEach(opt => { const optionDiv = document.createElement('div'); optionDiv.className = 'form-check'; optionDiv.innerHTML = ` <input class="form-check-input" type="checkbox" name="Property2.SelectedValues" value="${opt.Value}"> <label class="form-check-label">${opt.Text}</label> `; targetDropdown.appendChild(optionDiv); }); }); } }); }); // 保留之前的filterDropdownOptions函数 function filterDropdownOptions(input) { const filterText = input.value.toLowerCase(); const optionItems = input.parentElement.querySelectorAll('.form-check'); optionItems.forEach(item => { const labelText = item.querySelector('.form-check-label').textContent.toLowerCase(); item.style.display = labelText.includes(filterText) ? 'block' : 'none'; }); } </script>
3. 主视图传递联动标识
调用Property1的模板时,通过ViewData传入标识:
@Html.EditorFor(m => m.Property1, "DropDownOption", new { IsTriggerDropdown = true })
三、为什么放弃View Components?
View Components是独立UI组件,拥有自身的模型上下文,无法直接绑定主视图的模型属性,所以不能自动同步主模型的选中值,这也是你之前遇到问题的核心原因。而Editor Template是专门为模型绑定设计的,完美匹配你的需求。
内容的提问来源于stack exchange,提问作者Rob K.
相关产品推荐
相关产品推荐

