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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 18:46:06