纯JavaScript实现Google Maps多条件地图标记筛选方案
Google Maps 标记多条件组合筛选重构方案
原有实现通过多层嵌套if判断处理筛选逻辑,仅支持2类筛选维度时就已经出现逻辑分支复杂、扩展性差的问题,新增筛选维度需要修改大量分支代码,极易出现判断漏洞。本次重构采用配置化规则+统一校验的思路,彻底消除嵌套if判断,支持最多4类筛选维度的任意组合匹配,未设置有效值的条件自动跳过不参与校验,仅满足所有已设置条件的标记才会显示。
核心设计思路
- 统一管理所有筛选状态,替代原有分散的独立筛选变量
- 将每个筛选维度的「有效值判断规则」「标记匹配规则」抽离为独立配置,新增维度仅需新增配置项,无需修改核心筛选逻辑
- 核心筛选流程固定:遍历标记→逐个校验生效规则→全部规则通过则显示标记,否则隐藏,全程无嵌套分支判断
- 4类默认支持的筛选维度:
- Project Type:数组存储选中的项目类型,匹配标记对应类型在选中列表内
- Region:数组存储选中的所属区域,匹配标记对应区域在选中列表内
- Name:字符串存储用户输入的名称关键词,匹配标记标题包含关键词(不区分大小写)
- Value:整数存储用户输入的项目价值阈值,匹配标记项目价值大于等于阈值
重构后完整代码
// 全局标记、地图实例存储 let map; const markers = []; // 筛选规则配置:新增筛选维度仅需在此处添加配置,无需修改核心筛选逻辑 const filterConfig = { project_type: { value: [], // 判断当前筛选是否有有效值,无有效值则不参与匹配 isActive: (val) => Array.isArray(val) && val.length > 0, // 单标记匹配规则 match: (marker, selectedVals) => selectedVals.includes(marker.project_type) }, region: { value: [], isActive: (val) => Array.isArray(val) && val.length > 0, match: (marker, selectedVals) => selectedVals.includes(marker.region) }, name: { value: "", isActive: (val) => typeof val === "string" && val.trim().length > 0, match: (marker, keyword) => marker.project_title.toLowerCase().includes(keyword.trim().toLowerCase()) }, value: { value: null, isActive: (val) => typeof val === "number" && !isNaN(val) && val > 0, match: (marker, threshold) => Number(marker.value) >= threshold } }; function initMap() { map = new google.maps.Map(document.getElementById("map"), { zoom: 5, center: { lat: -25.77649954803059, lng: 122.03240276153382 }, styles: darkMapStyle, }); const infoWindow = new google.maps.InfoWindow({ content: "", disableAutoPan: true, }); // 初始化所有标记 projectData.forEach(item => { const newMarker = new google.maps.Marker({ position: { lat: item.lat, lng: item.lng }, title: item.project_title, }); // 挂载筛选需要的所有属性到标记实例,统一转小写避免大小写匹配问题 newMarker.project_type = item.project_type.toLowerCase(); newMarker.region = item.region.toLocaleLowerCase(); newMarker.project_title = item.project_title; newMarker.value = item.value; markers.push(newMarker); }); // 核心筛选函数:无嵌套if判断 function filterData() { markers.forEach(marker => { let isVisible = true; // 遍历所有筛选规则 for (const [, rule] of Object.entries(filterConfig)) { const currentFilterValue = rule.value; // 无有效值的规则直接跳过 if (!rule.isActive(currentFilterValue)) continue; // 不满足任意一条生效规则则隐藏 if (!rule.match(marker, currentFilterValue)) { isVisible = false; break; } } marker.setMap(isVisible ? map : null); }); } // 重置所有筛选条件 function resetFilters() { // 重置复选框状态 document.querySelectorAll(".filter").forEach(item => { item.checked = false; }); // 重置文本、数字输入框 document.getElementById("name-filter").value = ""; document.getElementById("value-filter").value = ""; // 重置所有筛选规则的存储值为初始状态 filterConfig.project_type.value = []; filterConfig.region.value = []; filterConfig.name.value = ""; filterConfig.value.value = null; // 显示所有标记 filterData(); } // 重置按钮绑定事件 document.getElementById("reset").addEventListener("click", resetFilters); // 复选框类筛选(项目类型、区域)事件绑定 document.querySelectorAll(".filter").forEach(item => { item.addEventListener("change", () => { const filterType = item.getAttribute("data-type"); const filterValue = item.getAttribute("id").toLowerCase(); const targetValueList = filterConfig[filterType].value; const valueIndex = targetValueList.indexOf(filterValue); if (item.checked && valueIndex === -1) { targetValueList.push(filterValue); } if (!item.checked && valueIndex !== -1) { targetValueList.splice(valueIndex, 1); } filterData(); }); }); // 名称关键词输入框事件绑定 document.getElementById("name-filter").addEventListener("input", (e) => { filterConfig.name.value = e.target.value; filterData(); }); // 价值阈值输入框事件绑定 document.getElementById("value-filter").addEventListener("input", (e) => { const inputVal = parseInt(e.target.value.trim(), 10); filterConfig.value.value = isNaN(inputVal) ? null : inputVal; filterData(); }); // 初始化时重置筛选,显示所有标记 resetFilters(); } window.initMap = initMap;
配套HTML参考
需要新增名称、价值两个筛选维度的输入控件,示例结构如下,原有复选框筛选结构保持不变即可,data-type属性对应配置中的key值:
<div class="filter-group"> <h3>项目名称</h3> <input type="text" id="name-filter" placeholder="输入项目名称关键词"> </div> <div class="filter-group"> <h3>项目价值阈值</h3> <input type="number" id="value-filter" placeholder="输入最低项目价值" min="0"> </div>
扩展说明
- 新增筛选维度时,仅需在
filterConfig中新增对应配置项,明确值存储变量、有效值判断逻辑、标记匹配规则三个部分即可,核心筛选、重置逻辑不需要做任何修改 - 所有筛选条件默认采用AND匹配逻辑,即必须满足所有已设置的生效条件才会显示对应标记,支持任意筛选条件组合
- 彻底消除多层嵌套if判断,每个筛选维度的逻辑独立维护,排查问题、修改规则时不需要梳理复杂的分支关系
内容的提问来源于stack exchange,提问作者Paul Wilson
相关产品推荐
相关产品推荐

