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

ASP.NET 6中使用Fetch API实现车辆列表无刷新筛选

实现ASP.NET 6 MVC多条件无刷新车辆筛选

1. 改造控制器方法,支持多参数筛选与AJAX请求

修改你的CarsController的Index方法,接收所有筛选参数并构建动态LINQ查询,同时区分AJAX请求返回局部视图:

using Microsoft.EntityFrameworkCore;
using YourProjectNamespace.Models;

public class CarsController : Controller
{
    private readonly AppDbContext _context;

    public CarsController(AppDbContext context)
    {
        _context = context;
    }

    public async Task<IActionResult> Index(
        List<string>? brands,
        string? model,
        int? minYear,
        int? maxYear,
        decimal? minPrice,
        decimal? maxPrice)
    {
        var query = _context.Cars.AsQueryable();

        // 品牌复选框筛选
        if (brands != null && brands.Any())
        {
            query = query.Where(c => brands.Contains(c.Brand));
        }

        // 型号模糊筛选
        if (!string.IsNullOrWhiteSpace(model))
        {
            query = query.Where(c => c.Model.Contains(model));
        }

        // 年份范围筛选
        if (minYear.HasValue)
        {
            query = query.Where(c => c.Year >= minYear.Value);
        }
        if (maxYear.HasValue)
        {
            query = query.Where(c => c.Year <= maxYear.Value);
        }

        // 价格范围筛选
        if (minPrice.HasValue)
        {
            query = query.Where(c => c.Price >= minPrice.Value);
        }
        if (maxPrice.HasValue)
        {
            query = query.Where(c => c.Price <= maxPrice.Value);
        }

        var cars = await query.ToListAsync();

        // 判断是否为AJAX请求,返回局部视图
        if (Request.Headers["X-Requested-With"] == "XMLHttpRequest")
        {
            return PartialView("_CarPartial", cars);
        }

        // 首次加载返回完整视图
        return View(cars);
    }
}

2. 前端筛选表单与Fetch API实现

在Index.cshtml中构建筛选表单,并编写JS监听筛选变化,通过Fetch请求更新车辆列表:

<!-- 筛选区域 -->
<div class="filter-panel">
    <!-- 品牌复选组 -->
    <div class="filter-group">
        <h5>品牌</h5>
        <label><input type="checkbox" name="brands" value="宝马"> 宝马</label>
        <label><input type="checkbox" name="brands" value="奔驰"> 奔驰</label>
        <label><input type="checkbox" name="brands" value="奥迪"> 奥迪</label>
    </div>

    <!-- 型号输入框 -->
    <div class="filter-group">
        <h5>型号</h5>
        <input type="text" id="model-input" placeholder="输入型号关键词">
    </div>

    <!-- 年份范围 -->
    <div class="filter-group">
        <h5>年份范围</h5>
        <input type="number" id="min-year" placeholder="最小年份" min="1990" max="@DateTime.Now.Year">
        <input type="number" id="max-year" placeholder="最大年份" min="1990" max="@DateTime.Now.Year">
    </div>

    <!-- 价格范围 -->
    <div class="filter-group">
        <h5>价格范围</h5>
        <input type="number" id="min-price" placeholder="最低价格" min="0">
        <input type="number" id="max-price" placeholder="最高价格" min="0">
    </div>

    <button id="apply-filters">应用筛选</button>
    <button id="reset-filters">重置筛选</button>
</div>

<!-- 车辆列表容器(用于替换局部视图) -->
<div id="car-list-container">
    @await Html.PartialAsync("_CarPartial", Model)
</div>

<script>
// 绑定筛选触发事件
document.getElementById('apply-filters').addEventListener('click', applyFilters);
document.getElementById('reset-filters').addEventListener('click', resetFilters);
// 实时监听输入变化(可选)
document.querySelectorAll('.filter-panel input').forEach(input => {
    input.addEventListener('change', applyFilters);
});

async function applyFilters() {
    const formData = new FormData();

    // 收集选中的品牌
    document.querySelectorAll('input[name="brands"]:checked').forEach(cb => {
        formData.append('brands', cb.value);
    });

    // 收集其他筛选值
    formData.append('model', document.getElementById('model-input').value.trim());
    formData.append('minYear', document.getElementById('min-year').value || '');
    formData.append('maxYear', document.getElementById('max-year').value || '');
    formData.append('minPrice', document.getElementById('min-price').value || '');
    formData.append('maxPrice', document.getElementById('max-price').value || '');

    try {
        // 构建查询字符串(GET请求参数拼接)
        const searchParams = new URLSearchParams(formData);
        const response = await fetch(`/Cars/Index?${searchParams}`, {
            method: 'GET',
            headers: {
                'X-Requested-With': 'XMLHttpRequest', // 标记AJAX请求
                'Accept': 'text/html'
            }
        });

        if (!response.ok) throw new Error('筛选请求失败');

        const html = await response.text();
        document.getElementById('car-list-container').innerHTML = html;
    } catch (err) {
        console.error('筛选出错:', err);
    }
}

function resetFilters() {
    // 清空所有筛选输入
    document.querySelectorAll('.filter-panel input').forEach(input => {
        if (input.type === 'checkbox') input.checked = false;
        else input.value = '';
    });
    // 重新加载默认列表
    applyFilters();
}
</script>

3. 局部视图_CarPartial.cshtml适配

确保局部视图仅渲染车辆列表,无多余布局:

@model List<YourProjectNamespace.Models.Car>

<div class="car-grid">
    @foreach (var car in Model)
    {
        <div class="car-card">
            <h3>@car.Brand @car.Model</h3>
            <p>年份: @car.Year</p>
            <p>价格: @car.Price.ToString("C")</p>
            <!-- 其他车辆信息字段 -->
        </div>
    }

    @if (!Model.Any())
    {
        <p class="no-results">未找到符合条件的车辆</p>
    }
</div>

关键注意事项

  • 参数绑定:ASP.NET MVC会自动将URL中的brands=宝马&brands=奔驰这类参数绑定到List<string> brands参数
  • 空值处理:控制器中对所有参数做空值判断,避免LINQ查询抛出异常
  • 性能优化:数据量大时需添加分页逻辑,在控制器中接收page和pageSize参数并修改LINQ查询
  • 兼容性:X-Requested-With头是识别AJAX请求的标准方式,确保控制器能正确区分请求类型

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 19:52:57