mSearch2组件mFilter联动筛选适配:品牌与车型独立匹配
MODX mSearch2/mFilter品牌与车型联动筛选适配方案
问题背景
基于MODX的mSearch2组件搭建了mFilter联动筛选器,现有脚本仅支持车型名称包含品牌关键词的场景(比如车型名是「Ford Galaxy」对应品牌Ford),选品牌后车型选择框才能正常显示生效。但产品数据库体量庞大,无法批量修改车型名称为「品牌+车型」格式,需要实现基于产品实际关联关系的条件判断,验证指定品牌是否对应特定车型。
现有实现脚本
var modelFilter = { // 选择器配置 options: { marka: '#mse2_tv\\|marka', model: '#mse2_tv\\|model', }, // 初始化函数 initialize: function() { $this = this; // 获取所需元素并保存为对象属性 this.marka = $(this.options['marka']); this.model = $(this.options['model']); // 从地址栏参数中查找已选品牌 var params = mSearch2.Hash.get(); // 无选中品牌时禁用车型选择 if (params['marka'] == undefined) { $this.disableModel(); } // 有选中品牌时启用车型选择 else { $this.enableModel(); } // 绑定品牌选择变更事件 this.marka.find('select').on('change', function() { // 选中品牌时,重置车型为默认选项并启用 if ($(this).val() != '') { $this.model.find('option:first').attr('selected', true); $this.enableModel(); } // 未选中品牌时禁用车型选择 else { $this.disableModel(); } }) }, // 禁用车型选择函数 disableModel: function() { // 清空并禁用所有非空值选项 $this.model.find('option[value!=""]').attr('selected', false).attr('disabled', true); // 隐藏车型选择框 $this.model.hide(); }, // 启用车型选择函数(原逻辑:基于文本匹配) enableModel: function() { // 获取品牌名称(去除括号和末尾空格) var marka = this.marka.find(':selected').text().replace(/\(.*?\)$/, '').replace(/\s+$/, ''); var re = new RegExp('^' + marka); // 遍历所有车型选项,根据文本匹配启用/禁用 $this.model.find('option').each(function() { var $this = $(this); // 不匹配且非空值则禁用隐藏 if (!$this.text().match(re) && $this.prop('value') != '') { $this.attr('disabled', true); $this.hide(); } // 匹配则启用显示 else { $this.attr('disabled', false); $this.show(); } }); // 显示车型选择框 $this.model.show(); }, } // 文档加载完成后初始化脚本 $(document).ready(function() { // 页面存在筛选器时执行 if ($('#mse2_mfilter').length > 0) { modelFilter.initialize(); } });
解决方案
核心思路:放弃文本正则匹配,改用品牌-车型关联映射表来判断对应关系,步骤如下:
1. 预构建品牌-车型映射表
先在页面中生成品牌与对应车型的映射关系,建议通过MODX后台snippet提前生成并渲染到页面,避免前端遍历大量数据影响性能。
后台生成映射表(MODX Snippet示例)
创建名为getBrandModelMap的snippet,代码如下:
<?php $map = []; // 替换为你的产品资源父ID或其他筛选条件 $products = $modx->getCollection('modResource', ['parent' => 123]); foreach ($products as $product) { $brand = $product->getTVValue('marka'); // 替换为你的品牌TV字段名 $model = $product->getTVValue('model'); // 替换为你的车型TV字段名 if (!empty($brand) && !empty($model)) { if (!isset($map[$brand])) { $map[$brand] = []; } // 车型去重 if (!in_array($model, $map[$brand])) { $map[$brand][] = $model; } } } // 输出为前端可直接使用的JSON变量 echo '<script>const brandModelMap = ' . json_encode($map) . ';</script>'; ?>
在页面头部或筛选器区域之前调用该snippet:[[getBrandModelMap]]
2. 修改enableModel函数逻辑
替换原有的文本匹配逻辑,改用映射表判断车型归属:
// 修改后的启用车型选择函数 enableModel: function() { // 获取当前选中品牌的value(确保与映射表的key一致) var selectedBrand = this.marka.find(':selected').val(); // 从映射表中获取该品牌对应的车型列表,无匹配则为空数组 var validModels = brandModelMap[selectedBrand] || []; // 遍历所有车型选项 $this.model.find('option').each(function() { var $option = $(this); var modelText = $option.text(); var modelValue = $option.val(); // 默认选项(空值)或车型在当前品牌列表中,则启用显示 if (modelValue === '' || validModels.includes(modelText) || validModels.includes(modelValue)) { $option.attr('disabled', false); $option.show(); } else { // 不属于当前品牌的车型,禁用隐藏 $option.attr('disabled', true); $option.hide(); } }); // 显示车型选择框 $this.model.show(); },
3. 优化初始化时的地址栏参数处理
确保地址栏中的品牌参数能正确关联映射表,修改初始化逻辑:
// 修改initialize中的地址栏参数判断部分 var params = mSearch2.Hash.get(); if (params['marka'] == undefined) { $this.disableModel(); } else { // 先设置品牌选择框的选中值,再启用车型筛选 $this.marka.find('select').val(params['marka']); $this.enableModel(); }
注意事项
- 确保品牌选择框的
value与映射表的key完全一致,避免匹配失败 - 如果车型的
value和text不一致,可根据实际情况调整validModels.includes的判断对象 - 产品数据量大时,建议后台缓存映射表,避免每次页面加载都遍历所有产品
内容的提问来源于stack exchange,提问作者Дмитрий Авакьян
相关产品推荐
相关产品推荐

