基于JavaScript搜索结果隐藏指定div的实现问题求助
问题解决:搜索栏模式切换时的DOM操作错误
错误原因分析
- 元素获取失败:你尝试通过
document.getElementById("aaa")获取的元素位于<template>标签内,模板内容默认不会被渲染到DOM中,因此初始获取到的是null,访问null的style属性就会抛出TypeError: Cannot read properties of null (reading 'style')。 - 重复ID问题:模板中的
aaa、bbb、ccc是重复ID,克隆多个卡片后会违反HTML中ID唯一的规范,导致后续DOM操作混乱。 - 逻辑错误:全局控制元素显示隐藏的方式不适用,每个搜索结果卡片都是独立克隆的,需要针对每个卡片单独控制。
修正后的代码
HTML(修正重复ID问题)
<div class="search-container"> <input type="search" id="search" data-search> </div> <div class="user-cards" data-user-cards-container></div> <template data-user-template> <div class="card"> <a href=""><div class="header" data-header></div></a> <div class="body_1" data-body_1></div> <div class="body_2" data-body_2></div> <div class="body_3" data-body_3></div> </div> </template>
CSS(无需修改)
.user-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: .25rem; margin-top: 1rem; } .card { border: 0px solid black; background-color: white; padding: .5rem; text-align: center; font-size: 1.5rem; } .card > .header { margin-bottom: .25rem; } .card > .body_1 { font-size: 1rem; color: #777; font-weight: bold; } .card > .body_2 { font-size: 1rem; color: #777; font-weight: bold; } .card > .body_3 { font-size: 1rem; color: #777; font-weight: bold; }
JavaScript(核心逻辑修正)
const userCardTemplate = document.querySelector("[data-user-template]") const userCardContainer = document.querySelector("[data-user-cards-container]") const searchInput = document.querySelector("[data-search]") let users = [] let results = [] searchInput.addEventListener("input", e => { results = []; userCardContainer.innerHTML = ""; const value = e.target.value.trim().toLowerCase() const xy = value.split(' ') // 先判断当前搜索模式 let searchMode = 'text'; // 默认文本搜索 if (xy.length === 3 && xy[0] === 'g') { searchMode = 'g-coord'; // g开头的坐标搜索 } else if (xy.length === 2 && !isNaN(parseFloat(xy[0])) && !isNaN(parseFloat(xy[1]))) { searchMode = 'coord'; // 普通坐标搜索 } if (value.length >= 4) { users.forEach(user => { let isVisible = false; let distance = null; const fvalue = value.replace("1", "9") // 根据搜索模式处理 switch(searchMode) { case 'g-coord': // 计算g开头的距离 distance = Math.sqrt( Math.pow(parseFloat(xy[1]) - parseFloat(user.x1), 2) + Math.pow(parseFloat(xy[2]) - parseFloat(user.y1), 2) ) isVisible = distance <= 5; // 设置当前卡片的显示状态:显示body_2,隐藏1和3 user.body_1.style.display = 'none'; user.body_2.style.display = 'block'; user.body_3.style.display = 'none'; break; case 'coord': // 计算普通坐标距离 distance = Math.sqrt( Math.pow(parseFloat(xy[0]) - parseFloat(user.x2), 2) + Math.pow(parseFloat(xy[1]) - parseFloat(user.y2), 2) ) isVisible = distance <= 5; // 设置当前卡片的显示状态:显示body_3,隐藏1和2 user.body_1.style.display = 'none'; user.body_2.style.display = 'none'; user.body_3.style.display = 'block'; break; case 'text': // 文本搜索 isVisible = user.mnames.includes(fvalue); // 设置当前卡片的显示状态:显示body_1,隐藏2和3 user.body_1.style.display = 'block'; user.body_2.style.display = 'none'; user.body_3.style.display = 'none'; break; } if (isVisible) { user.distance = distance; results.push(user); } }) } // 排序并渲染结果 results.sort((a, b) => (a.distance || 0) - (b.distance || 0)) results.slice(0, 10).forEach(u => { userCardContainer.append(u.element); }); }) fetch("https://raw.githubusercontent.com/ucc23/ucc/main/_clusters/generated.json") .then(res => res.json()) .then(data => { users = data.map(user => { const card = userCardTemplate.content.cloneNode(true).children[0] const header = card.querySelector("[data-header]") const body_1 = card.querySelector("[data-body_1]") const body_2 = card.querySelector("[data-body_2]") const body_3 = card.querySelector("[data-body_3]") card.querySelector("a").setAttribute("href", "https://url/" + user.name) header.textContent = user.name body_1.textContent = user.mnames.split(',') body_2.textContent = user.x1 + ',' + user.y1 body_3.textContent = user.x2 + ',' + user.y2 // 将body元素保存到user对象中,方便后续控制 return { mnames: user.mnames, x1: user.x1, y1: user.y1, x2: user.x2, y2: user.y2, element: card, body_1, body_2, body_3 } }) })
关键改进点
- 移除重复ID:模板中的div不再使用重复ID,改用data属性选择,符合HTML规范。
- 保存元素引用:在生成user对象时,将每个卡片的body元素保存到对象中,避免全局获取的问题。
- 明确搜索模式:先判断当前输入对应的搜索模式,再针对每个模式处理显示逻辑,避免逻辑冲突。
- 单独控制卡片:每个卡片的显示状态独立设置,确保不同搜索模式下的卡片正确显示对应内容。
内容的提问来源于stack exchange,提问作者Gabriel
相关产品推荐
相关产品推荐

