本文介绍如何利用 javascript 将用户在文本框中输入的房屋编号,作为 id 动态查找并高亮 svg 中对应房屋图形,避免为每个房屋编写重复按钮和函数,提升应急场景下的响应效率。
本文介绍如何利用 javascript 将用户在文本框中输入的房屋编号,作为 id 动态查找并高亮 svg 中对应房屋图形,避免为每个房屋编写重复按钮和函数,提升应急场景下的响应效率。
在急救调度等时间敏感场景中,快速定位无序编号的房屋至关重要。原始方案中为每个房屋硬编码按钮与独立函数(如 select01()、select02()),不仅冗余难维护,也无法适应动态新增或编号变更。理想解法应支持单次输入、实时匹配、双向切换(选中/取消),且具备良好的可扩展性。
✅ 推荐方案:基于原生 Web Component 的声明式 SVG 房屋地图
我们封装一个自定义元素
? 核心实现要点:
-
动态解析与渲染:遍历所有
元素,提取编号、坐标,生成 和居中 标签; - 智能匹配逻辑:使用 nr.includes(inputValue) 支持模糊搜索(如输入 "1" 可同时匹配 "1a"、"11"、"21"),满足不规则编号需求;
- CSS 类控制状态:通过 element.classList.toggle("selected", match) 实现选中/取消的原子操作;
- 自动 viewBox 适配:根据所有房屋坐标自动计算 SVG 可视区域,确保完整显示。
? 完整可运行代码(复制即用):
<svg-house-map>
<input type="text" placeholder="请输入房屋编号(支持模糊匹配)"><br>
<svg viewBox="0 0 0 0" style="background:#f5f5f5; border:1px solid #ccc; width:100%; max-width:600px;">
<style>
.selected { fill: #e74c3c !important; stroke: #c0392b; stroke-width: 2; }
circle { transition: all 0.2s ease; }
text { font-family: Arial, sans-serif; }
</style>
<!-- 房屋数据:格式为 "编号,CX,CY,RADIUS"(RADIUS 可选,默认10) -->
<house>01,380,400,40</house>
<house>02,380,60,40</house>
<house>03,80,240,40</house>
<house>04,430,210,40</house>
<house>05,110,60,40</house>
<house>06,230,130,40</house>
<house>07,130,370,40</house>
<house>08,280,280,40</house>
</svg>
</svg-house-map>
<script>
customElements.define("svg-house-map", class extends HTMLElement {
connectedCallback() {
setTimeout(() => {
const svg = this.querySelector("svg");
const input = this.querySelector("input");
const houses = Array.from(svg.querySelectorAll("house"));
const vbx = [], vby = [];
houses.forEach(house => {
const [nr, cx, cy, r = 10] = house.textContent.split(",").map(s => s.trim());
const radius = Number(r);
vbx.push(Number(cx) + radius + 5);
vby.push(Number(cy) + radius + 5);
// 构建带编号的 SVG 图形
const id = `NR${nr.replace(/[^a-zA-Z0-9]/g, '_')}`;
const circleHTML = `
<circle id="${id}-circle" cx="${cx}" cy="${cy}" r="${radius}"
fill="#27ae60" stroke="#2c3e50" stroke-width="1.5"/>
<path id="${id}-path" d="M${Number(cx)-radius} ${cy} h${radius*2}" stroke="none"/>
<text>
<textPath href="#${id}-path" startoffset="50%" text-anchor="middle"
dominant-baseline="middle" fill="#2c3e50" font-size="${radius*0.8}px">
${nr}
</textPath>
</text>
`;
house.innerHTML = circleHTML;
// 绑定输入事件:实时匹配并切换高亮
input.addEventListener("input", () => {
const value = input.value.trim();
const circle = house.querySelector("circle");
const match = value && nr.toLowerCase().includes(value.toLowerCase());
circle.classList.toggle("selected", match);
});
// 替换 <house> 标签为实际 SVG 内容
house.replaceWith(...house.children);
});
// 自动设置 viewBox
if (vbx.length && vby.length) {
svg.setAttribute("viewBox", `0 0 ${Math.max(...vbx)} ${Math.max(...vby)}`);
}
});
}
});
</script>⚠️ 注意事项与优化建议:
- ID 合法性处理:房屋编号若含特殊字符(如 /, #, 空格),需转义为合法 CSS ID(示例中已用 replace(/[^a-zA-Z0-9]/g, '_') 处理);
- 性能考虑:百级房屋仍可流畅运行;若超千级,建议添加防抖(debounce)避免高频重绘;
-
无障碍增强:可为
添加 aria-label="House 01",提升屏幕阅读器支持; - 离线可用:整个方案不依赖外部库,纯原生 JS,适合部署在车载终端或离线平板设备。
该方案将维护成本降至最低——新增房屋只需在


















