第六天挑战(搜索框)
所有内容均上传至gitee,答案不唯一,仅代表本人思路
该详解是Soyaine及其团队整理编撰的,是对源代码的详解,强烈推荐大家观看学习!!!!!!!
本人gitee:gitee.com/thats-all-r…
效果
-
样式分析
- 组件整体居中,分为两个部分,输入框和展示框,展示框有类3d效果,使用transform实现
-
逻辑分析
- 在输入框输入关键字后,实时检索符合关键字的城市
- 检索出的城市高亮关键字
- 检索后的城市根据后方数字大小进行降序排序
本人代码及思路分析
仅提供布局及逻辑代码
结构:
<div class="main">
<input type="text">
<p></p>
</div>
逻辑:
<script src="message.js">
</script>
<script>
const input = document.querySelector('input')
const main = document.querySelector('.main')
let p = document.querySelectorAll('p')
console.log(p)
input.addEventListener('input', (e) => {
p.forEach(item => main.removeChild(item))
const city = list.filter((item) => {
console.log(e.target.value)
return item.city.toLowerCase().includes(e.target.value) || item.state.includes(e.target.value)
}).sort((a,b) => {
return b.population - a.population
})
console.log(city)
for (let i = 0; i < city.length; i++) {
const p = document.createElement('p')
p.innerText = `${city[i].city} | ${city[i].state} ${city[i].population}`
main.appendChild(p)
}
p = document.querySelectorAll('p')
})
</script>
分析:
-
整体思路: 获取城市数据,获取input元素监听value事件,根据input输入框内的值,通过filter函数进行检索,通过sort进行排序,并且创建p标签添加到main盒子中,在每次添加时,先删除上一次添加的p标签
-
具体实现:
- 首先通过querySelector选定需要监听和修改的元素
- 这里在html结构中写了一个p标签是因为,当添加子元素后,前一次的子元素不会清空,会继续进行累加,所以在添加新的子元素时清空掉上一次添加的子元素,又因为这一步的操作优先级较高,当这一步进行的时候,并没有子元素被生成,所以这里先添加一个p标签作为前置条件进行启动
- 其次这里我将数据放置在另一个js文件中,所以引用了script标签获取数据
- 创建一个数组city,使用filter方法和includes方法将数组内的元素根据输入框内的值进行过滤
- 通过sort方法将数据进行排序
- 循环为数组内的每一个对象都创建一个p标签作为子元素添加到页面中去
- 最后抓取所有的p标签,确保在下次进行输入操作的时候可以先被清除掉
-
弊端分析(与官方方法对比):
- 由于在大规模数据(峰值数据1000条) 中使用了for循环,所以导致该功能性能开销极大(内存占用244MB)
- 频繁的对元素进行删除和添加操作
- 需要在结构上单独使用一个p标签作为前置条件
-
这种写法没有优化,也仅仅是一个快速完成需求的写法,建议仅当个乐子看看,极其不建议应用在实际中
官方代码
官方代码仅代表该案例原作者思路,不唯一
结构
<form class="search-form">
<input type="text" class="search" placeholder="City or State">
<ul class="suggestions">
<li>Filter for a city</li>
<li>or a state</li>
</ul>
</form>
逻辑
const endpoint = 'https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json';
const cities = [];
fetch(endpoint)
.then(blob => blob.json())
.then(data => cities.push(...data));
function findMatches(wordToMatch, cities) {
return cities.filter(place => {
// here we need to figure out if the city or state matches what was searched
console.log(1)
const regex = new RegExp(wordToMatch, 'gi');
return place.city.match(regex) || place.state.match(regex)
});
}
function numberWithCommas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}
function displayMatches() {
const matchArray = findMatches(this.value, cities);
const html = matchArray.map(place => {
const regex = new RegExp(this.value, 'gi');
const cityName = place.city.replace(regex, `<span class="hl">${this.value}</span>`);
const stateName = place.state.replace(regex, `<span class="hl">${this.value}</span>`);
return `
<li>
<span class="name">${cityName}, ${stateName}</span>
<span class="population">${numberWithCommas(place.population)}</span>
</li>
`;
}).join('');
suggestions.innerHTML = html;
}
const searchInput = document.querySelector('.search');
const suggestions = document.querySelector('.suggestions');
searchInput.addEventListener('change', displayMatches);
searchInput.addEventListener('keyup', displayMatches);
分析
仅代表本人对该代码的分析
建议直接去看Soyaine的中文详解 建议直接去看Soyaine的中文详解 建议直接去看Soyaine的中文详解
-
整体思路: 十分巧妙的通过正则表达式对数组内的元素进行过滤,并且通过字符串模板+innerHTML结构的方式的覆盖法解决了多次搜索元素累加的问题
-
具体实现:
-
fetch:fetch方法获取从链接地址获取城市信息,通过 .then操作,在确保信息获取成功后再执行赋值操作
-
tfindMatches:数据筛选函数,对实际操作的数组cities使用filter过滤和正则的方法,对输入条件wordToMatch进行全局且不区分大小写的过滤
-
numberWithCommas:将数字转换成字符串,并且每三位数加一个分隔符
-
displayMatches:渲染函数,首先通过调用findMatches获取到符合条件的数组,并且将这个数组进行二次正则过滤,创建regex正则条件,条件为输入框内的值,并且根据过滤条件,将原来的城市名字中所包含的符合条件的值添加span标签,进行高亮处理
//假设第一次过滤后符合条件的值为 abc //经过第二次匹配过滤,正则条件为 b //经过第二次过滤后,原来的值变为 a<span class='h1'>b</span>c const cityName = place.city.replace(regex, `<span class="hl">${this.value}</span>`); const stateName = place.state.replace(regex, `<span class="hl">${this.value}</span>`); -
返回字符串模板,将其赋值给其父元素
-
获取元素,监听事件
-
-
优点:
- fetch函数避免将数据抓取到本地
- 正则表达式避免了对数组大量进行操作
- map+字符串模板避免了循环的使用,并且避免了多次搜索造成的元素累加
- 节省了性能开销