下拉选「全部」选了等于没选——Vendor 组件 Falsy 检查吞掉空字符串
某后台管理系统的列表页有一个状态筛选下拉框:正常 / 已关闭 / 待审核。产品要求加一个「全部」选项,点了之后取消状态过滤、展示所有记录。我照着其他字段的做法,给「全部」加了 value: "",上线后用户反馈:选了「全部」,列表还是只显示「正常」的数据,跟没动一样。
现象
- 选「正常」→ 正确只显示 status=1 的记录
- 选「已关闭」→ 正确只显示 status=0 的记录
- 选「全部」→ 依然只显示 status=1,和默认状态一模一样
网络请求里看 payload,选「全部」时根本没有 status 字段——value: "" 选项被静默丢弃了。
根因
问题出在封装好的表格组件内部。该组件有一个 makeData() 方法,负责把当前的筛选变量打包成请求参数:
// 组件内部 src/xtcomponents/XtTablePage/index.vue ~line 713
makeData() {
var da = { pagesize: this.pagesize, currpage: this.currpage };
for (var s in this.vars) {
if (this.vars[s]) { // ❌ falsy 检查——'' / 0 / false / null 全部被过滤掉
da[s] = this.vars[s];
}
}
return da;
}if (this.vars[s]) 是一个 JS falsy 检查。"" 是 falsy,所以用户选了「全部」之后,status: "" 这一项直接被过滤掉,根本不会出现在 makeData() 返回的对象里。
组件随后 $emit('on-change', val) 把这个残缺的对象传给父组件。父组件的处理通常是这样:
getData(val) {
this.pageOpitons = { ...this.searchForm, ...val };
// searchForm 里有 status: '1' 作为默认值
// 因为 val 里没有 status,展开后默认值就复活了
}两段代码一叠加,结果就是:选「全部」= 用 searchForm 默认值覆盖,最终请求还是带着 status=1。
把「全部 / 重置」选项的 value 设为 "" 是最直觉的做法,但只要 vendor 组件内部用 if (value) 做参数过滤,"" 就会被静默丢弃——组件不报错、父组件不报错、网络请求也不报错,只有用户会发现「全部」没效果。更隐蔽的是,父组件的 spread 默认值会悄悄补位,让结果看起来像是「全部」等于「默认筛选条件」,完全没有错误提示可循。
正解
不要试图修改 vendor 组件源码(牵一发动全身,其他依赖 falsy 过滤的列可能因此崩掉),而是绕路:用一个 truthy 哨兵值代替空字符串,在父组件层面拦截并删除它。
第一步:selectlist 用 truthy 哨兵
selectlist: [
{ name: "全部", value: "all" }, // ✅ "all" 是 truthy,能通过 makeData 的检查
{ name: "已关闭", value: "0" },
{ name: "正常", value: "1" },
{ name: "待审核", value: "3" }
]注意 value: "0" 同样是 falsy——如果你的选项里有 0,也要确认它能顺利通过。这里 "0" 是字符串,是 truthy,没问题;但 0(数字)就不行了。
第二步:父组件拦截并删除哨兵
getData(val) {
const merged = { ...this.searchForm, ...val };
if (merged.status === 'all') {
delete merged.status; // 后端收到无 status 字段 = 不过滤
}
this.pageOpitons = merged;
}第三步:后端按「字段缺席」判断是否过滤
if (isset($data['status']) && $data['status'] !== '') {
$where .= " AND s.status = :status";
}
// 注意:不要加 else { status = '1' },那会是一次回归用一个有意义的 truthy 字符串(如 "all")作为「全部」的 value,让它能顺利通过 vendor 组件的 falsy 过滤;在父组件拿到数据后,检测到哨兵值就 delete 掉对应 key,后端按字段是否存在判断是否施加过滤条件。整个链路不碰 vendor 源码,改动范围最小,副作用可控。
一句话外卖
Vendor 组件只要有
if (value)的参数过滤,value:""的重置选项就是隐形的——不要用空字符串做哨兵,改用 truthy 占位符并在业务层 delete。