Vaadin24 Hilla中Grid能否同时启用排序与筛选功能?
在Vaadin 24 Hilla Grid中同时实现排序与筛选功能
你的问题出在使用了GridSortColumn和GridFilterColumn这两种独立的列类型——前者仅提供排序能力,后者仅提供筛选能力,自然无法在同一列同时生效。要让同一列兼具排序和筛选功能,需要使用普通的GridColumn,并分别启用排序、添加筛选组件,同时确保后端能协同处理排序和筛选参数。
解决方案步骤与代码示例
1. 前端组件改造(React/TypeScript)
用GridColumn替代原有列类型,开启sortable属性,并在列头添加筛选输入组件,同时监听排序、筛选变化事件来更新数据源:
import { Grid, GridColumn, TextField } from '@vaadin/react-components'; import { useState, useEffect } from 'react'; import { Supplier, SupplierService } from 'Frontend/generated/endpoints'; import type { GridSortEvent } from '@vaadin/react-components/Grid'; export default function SupplierGrid() { const [items, setItems] = useState<Supplier[]>([]); const [nameFilter, setNameFilter] = useState(''); const [sortConfig, setSortConfig] = useState({ field: 'supplierId', direction: 'asc' }); // 调用后端接口获取数据 const fetchSuppliers = async () => { const response = await SupplierService.getSuppliers( nameFilter, sortConfig.field, sortConfig.direction, 0, // 当前页码 20 // 每页条数 ); setItems(response.content); }; // 监听排序变化 const handleSortChange = (event: GridSortEvent<Supplier>) => { const newSort = event.detail.sort; setSortConfig({ field: newSort.path, direction: newSort.direction }); fetchSuppliers(); }; // 监听筛选输入变化(回车或清除时触发) const handleFilterChange = () => { fetchSuppliers(); }; // 初始化加载数据 useEffect(() => { fetchSuppliers(); }, []); return ( <Grid column-reordering-allowed theme="column-borders row-stripes compact wrap-cell-content" items={items} onSortChanged={handleSortChange} > {/* 供应商ID列:仅排序 */} <GridColumn path="supplierId" sortable className='s_gridsort_modify' header="供应商ID" /> {/* 供应商名称列:排序 + 筛选 */} <GridColumn path="supplierName" sortable className='s_gridsort_modify' header={ <TextField placeholder="筛选名称" value={nameFilter} onChange={(e) => setNameFilter(e.target.value)} onKeyUp={(e) => e.key === 'Enter' && handleFilterChange()} clearButtonVisible onClear={() => handleFilterChange()} /> } /> </Grid> ); }
2. 后端接口适配(Java)
在Hilla后端编写支持筛选、排序、分页的接口,使用Spring Data的Specification和Sort来处理参数:
import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.data.jpa.domain.Specification; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import com.example.application.data.entity.Supplier; import com.example.application.data.repository.SupplierRepository; @RestController public class SupplierController { private final SupplierRepository supplierRepository; public SupplierController(SupplierRepository supplierRepository) { this.supplierRepository = supplierRepository; } @GetMapping("/suppliers") public Page<Supplier> getSuppliers( @RequestParam(required = false) String nameFilter, @RequestParam(defaultValue = "supplierId") String sortField, @RequestParam(defaultValue = "asc") String sortDirection, @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "20") int size ) { // 构建筛选条件 Specification<Supplier> spec = Specification.where(null); if (nameFilter != null && !nameFilter.isEmpty()) { spec = spec.and((root, query, cb) -> cb.like(cb.lower(root.get("supplierName")), "%" + nameFilter.toLowerCase() + "%") ); } // 构建排序规则 Sort sort = Sort.by(Sort.Direction.fromString(sortDirection), sortField); // 查询并返回分页结果 return supplierRepository.findAll(spec, PageRequest.of(page, size, sort)); } }
补充说明
- 如果数据量较小,也可以直接在前端做筛选(无需后端接口改造),通过Grid的
filter属性实现:
但大数据量场景下,后端处理筛选和排序能有效减少前端数据传输量,提升性能。<Grid ... filter={({ item }) => { if (!nameFilter) return true; return item.supplierName.toLowerCase().includes(nameFilter.toLowerCase()); }} > ... </Grid>
内容的提问来源于stack exchange,提问作者shas shalu
相关产品推荐
相关产品推荐

