Skip to content

列筛选

为列配置 filtersfilterMethod,在表头进行单选或多选筛选。

这是列筛选的第一种入口(表头快捷筛选)。需要「A 且(B 或 C)」这类复合条件时, 用第二种入口 高级筛选(筛选管理器),两者可同时使用,结果取交集。

使用的 API

ts
type Column = {
  key: string;  // 列标识(必填)
  title: string;  // 列标题(必填)
  width: number;  // 列宽(必填)
  filters: Array<{label, value, checked?}>;  // 筛选选项
  filterMultiple: boolean;  // 是否多选筛选
  filterMethod: (value, row) => boolean;  // 自定义筛选方法
}

type Options = {
  list: T[];  // 数据列表
  itemKey: string;  // 行唯一标识字段名
  estimatedSize: number;  // 行预估高度(px)
  buffer: number;  // 缓冲区行数
  border: boolean;  // 是否显示边框
}

示例

微应用尚未挂载。

源码

点击查看源码
ts
import { faker } from '@faker-js/faker';
import {
  VirtTable,
} from '@virt-table/vanilla';
import {
  vtColumnFilter,
} from '@virt-table/vanilla/plugins';

export function bootstrapTableFilter(root: HTMLElement): () => void {
  const departments = ['工程部', '设计部', '市场部', '财务部', '人事部'];
  const levels = ['P5', 'P6', 'P7', 'P8'];
  const cities = ['北京', '上海', '杭州', '深圳'];

  const list = Array.from({ length: 500 }, (_, i) => ({
    id: i,
    name: faker.person.fullName(),
    department: departments[i % departments.length],
    level: levels[i % levels.length],
    city: cities[i % cities.length],
    score: Math.floor(Math.random() * 100),
  }));

  const columns = [
    { key: 'name', title: '姓名', width: 180 },
    {
      key: 'department',
      title: '部门',
      width: 140,
      filters: departments.map((d) => ({ label: d, value: d })),
      filterMultiple: true,
    },
    {
      key: 'level',
      title: '级别',
      width: 100,
      filters: levels.map((l) => ({ label: l, value: l })),
      filterMultiple: false,
    },
    {
      key: 'city',
      title: '城市',
      width: 120,
      filters: cities.map((c) => ({ label: c, value: c })),
    },
    {
      key: 'score',
      title: '分数',
      width: 120,
      filters: [
        { label: '≥ 80 优秀', value: 80 },
        { label: '≥ 60 及格', value: 60 },
        { label: '< 60 不及格', value: -1 },
      ],
      filterMultiple: false,
      filterMethod: (filterValue: number, row: { score: number }) => {
        if (filterValue === -1) return row.score < 60;
        return row.score >= filterValue;
      },
    },
  ];

  root.innerHTML = `
    <div class="virt-table-controls">
      <button class="virt-table-btn" id="btnClearFilter">清除全部筛选</button>
    </div>
    <div id="status" class="status-text"></div>
    <div style="width:800px;height:600px;" class="demo-container" id="tableContainer"></div>
  `;

  const container = root.querySelector('#tableContainer') as HTMLElement;
  const status = root.querySelector('#status') as HTMLElement;
  const listeners: (() => void)[] = [];

  const setStatus = (text: string) => {
    status.textContent = text;
  };

  const table = new VirtTable(container, {
    plugins: [vtColumnFilter()],
    list,
    columns,
    itemKey: 'id',
    estimatedSize: 40,
    buffer: 4,
    border: true,
    onFilterChange: (filters) => {
      const keys = Object.keys(filters);
      if (keys.length === 0) {
        setStatus(`列筛选:${list.length} 行(无筛选)`);
      } else {
        const desc = keys.map((k) => `${k}: ${filters[k].join(',')}`).join(';');
        const renderTotal = (table.core.state as any).renderTotal ?? list.length;
        setStatus(`筛选条件 ${desc},结果 ${renderTotal} 行`);
      }
    },
  });

  setStatus(`列筛选:${list.length} 行(点击表头筛选图标)`);

  const btnClearFilter = root.querySelector('#btnClearFilter')!;
  const onClearFilter = () => {
    table.clearAllFilters();
    setStatus(`列筛选:${list.length} 行(已清除全部筛选)`);
  };
  btnClearFilter.addEventListener('click', onClearFilter);
  listeners.push(() => btnClearFilter.removeEventListener('click', onClearFilter));

  return () => {
    table.destroy();
    listeners.forEach((off) => off());
    root.innerHTML = '';
  };
}