使用纯 JS 和 JSON 自动完成 - 使 api 获取一次,然后让“输入”事件仅进行过滤
Posted
技术标签:
【中文标题】使用纯 JS 和 JSON 自动完成 - 使 api 获取一次,然后让“输入”事件仅进行过滤【英文标题】:Autocomplete with pure JS and JSON - Make api fetch once, and then have the "input" event merely do the filtering 【发布时间】:2022-01-18 22:48:49 【问题描述】:我有一个纯 JS 和 JSON 的自动完成功能。
我的代码在每次击键时都会触发一个新的 ajax 请求,我不知道如何让我的 api 获取一次,然后让输入事件进行过滤。
我的代码运行良好,但如果我让它保持这样的状态,当我拥有大量 json 内容时,它需要数年时间才能加载。
states.json 数据仍然相同(并且处于自动完成状态),我应该加载一次而不是每次击键。对每个密钥的额外请求不是一个好主意。那么有人可以帮帮我吗?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="css/main.css">
<title>Test</title>
</head>
<body>
<div class="container">
<div class="search-wrapper">
<input type="text" name="" autocomplete="off" id="search" placeholder="Search now">
<ul class="match-list">
</ul>
</div>
</div>
<script src="function.js"></script>
</body>
</html>
这是我的 javascript
const search = document.querySelector("#search");
const matchList = document.querySelector(".match-list");
// search states.json and filter it
const searchStates = async searchText =>
const res = await fetch('data/states.json');
const states = await res.json();
//Get matches to current text input
let matches = states.filter(state =>
const regex = new RegExp(`^$searchText`, 'gi');
return state.name.match(regex) || state.abbr.match(regex);
);
if (searchText.length === 0)
matches = [];
;
outputHtml(matches)
;
//show results in html
const outputHtml = matches =>
if (matches.length > 0)
const html = matches.map(match =>`
<li class="match-list-element">
<h4 class="">$match.name ($match.abbr)</h4>
<span class="">$match.capital</span>
<small class="">Lat:$match.lat/ Long: $match.long</small>
</li>
`
).join('');
matchList.innerHTML = html;
else
matchList.innerHTML = null;
search.addEventListener('input', () => searchStates(search.value));
【问题讨论】:
假设查询结果很小,请在window.onload
上进行提取。将所有结果写入 dom。在输入时,重写 dom,写一些<li>
和一些<li hidden>
。
你能给我一个更详细的例子,以便我更好地理解吗?
好的 - 速写,需要注意的是它没有经过测试甚至编译,当然也没有验证任何 OP 代码。
@danh 你能告诉我可能出了什么问题,这样我就可以获得全部知识了吗?
【参考方案1】:
只需更改这部分;
search.addEventListener('focusout', () => searchStates(search.value));
这样,当您的输入字段即将失去焦点时,这将被触发。例如,在输入外部单击后,这将起作用。你也可以搜索 onblur 方法
如果你想存储和使用它,你也可以查看 localStorage 和 sessionStorage 概念
const searchStates = async searchText =>
const storedStates = JSON.parse(localStorage["states"]);
let states = storedStates;
if(!storedStates)
const res = await fetch('data/states.json');
states = await res.json();
localStorage.setItem("states",JSON.stringfy(states));
//Get matches to current text input
let matches = states.filter(state =>
const regex = new RegExp(`^$searchText`, 'gi');
return state.name.match(regex) || state.abbr.match(regex);
);
if (searchText.length === 0)
matches = [];
;
outputHtml(matches)
;
然后你可以检查你的函数,如果它没有获取
【讨论】:
显然,如果我将其更改为 "onFocus" ,它不再起作用,并且 "onBlur" 也不起作用。我的自动完成下拉菜单不会触发。 对不起,您可以尝试使用 focusout 而不是 onfocusout,或者您可以尝试仅在输入上提供 onfocusout 并分配函数以调用 @Marius 还是不行。我试过 onfocusout。 你能举个例子说明我应该如何添加我的 if 语句吗?我真的很困惑 我更新了我的答案,这样你只会获取一次。如果数据变化不大,这将是解决方案的正确答案。如果您可以共享 data/states.json 我也可以给出工作示例【参考方案2】:如果“数据/状态”的总数在几百个,那么最简单的选择是在页面加载时进行查询,并有选择地设置/取消设置 DOM 中的隐藏道具。
只是一个草图,使用尽可能多的 OP 代码...
const search = document.querySelector("#search");
const matchList = document.querySelector(".match-list");
let states = []
// get the data once
window.onload = async () =>
const res = await fetch('data/states.json');
states = await res.json();
searchStates('');
// run this on input. no fetching here
const searchStates = searchText =>
for (let state of states)
const regex = new RegExp(`^$searchText`, 'gi');
// mark every state with a bool "match" whether it matches the current search text
state.match = state.name.match(regex) || state.abbr.match(regex);
outputHtml()
;
// put the whole list into the dom, but with some elements hidden
const outputHtml =() =>
// note the interpolated string in "<li ...": hidden or not depending on state.match
const html = states.map(state =>`
<li $state.match ? '' : 'hidden' class="match-list-element">
<h4 class="">$state.name ($state.abbr)</h4>
<span class="">$state.capital</span>
<small class="">Lat:$state.lat/ Long: $state.long</small>
</li>
`
).join('');
matchList.innerHTML = html;
search.addEventListener('input', () => searchStates(search.value));
【讨论】:
我不得不改变 const 状态来让状态和它的工作原理!非常感谢! 啊——不错。已编辑。以上是关于使用纯 JS 和 JSON 自动完成 - 使 api 获取一次,然后让“输入”事件仅进行过滤的主要内容,如果未能解决你的问题,请参考以下文章
Jquery UI 和 Bootstrap JS 冲突使自动完成停止工作
jQuery UI 自动完成多个远程(JSON、PHP、JS)