-
Notifications
You must be signed in to change notification settings - Fork 3.3k
第 90 题:实现模糊搜索结果的关键词高亮显示 #141
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
考虑节流、缓存。其实还可以上列表diff+定时清理缓存 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>auto complete</title>
<style>
bdi {
color: rgb(0, 136, 255);
}
li {
list-style: none;
}
</style>
</head>
<body>
<input class="inp" type="text">
<section>
<ul class="container"></ul>
</section>
</body>
<script>
function debounce(fn, timeout = 300) {
let t;
return (...args) => {
if (t) {
clearTimeout(t);
}
t = setTimeout(() => {
fn.apply(fn, args);
}, timeout);
}
}
function memorize(fn) {
const cache = new Map();
return (name) => {
if (!name) {
container.innerHTML = '';
return;
}
if (cache.get(name)) {
container.innerHTML = cache.get(name);
return;
}
const res = fn.call(fn, name).join('');
cache.set(name, res);
container.innerHTML = res;
}
}
function handleInput(value) {
const reg = new RegExp(`\(${value}\)`);
const search = data.reduce((res, cur) => {
if (reg.test(cur)) {
const match = RegExp.$1;
res.push(`<li>${cur.replace(match, '<bdi>$&</bdi>')}</li>`);
}
return res;
}, []);
return search;
}
const data = ["上海野生动物园", "上饶野生动物园", "北京巷子", "上海中心", "上海黄埔江", "迪士尼上海", "陆家嘴上海中心"]
const container = document.querySelector('.container');
const memorizeInput = memorize(handleInput);
document.querySelector('.inp').addEventListener('input', debounce(e => {
memorizeInput(e.target.value);
}))
</script>
</html> |
我的大概思路是,用正则替换掉关键词。 let panter = new RegExp(关键词, 'g')
该行字符串.replace(panter, '<b style="color: #2D7BFF">' + 关键词 + '</b>') ps:如果是vue项目,直接与v-html结合使用更爽哦~ |
|
直接把 输入的字符 变蓝, 服务端返回的数据 把输入字符替换掉,然后追加后面那部分 显示。 |
new RegExp 要注意排除有正则含义的字符,比如用户输入 |
用关键词去切分搜索结果为3段 let _head = item.substr(0, first) return _head + |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id='app'>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
var myitem = {
template:`<div class='item'>
<p v-html="info.name"></p>
</div>`,
props:{
info:{
type:Object,
default:()=>{return {}},
}
}
}
var vm = new Vue({
el:'#app',
template:`
<div>
<input @input='inputSearchText'>
<myitem v-for='info in results' :key='info.name' :info='info'></item>
</div>
`,
data(){
return {
infos:[
{name:'地铁1',},
{name:'地铁6',},
{name:'地铁7',},
{name:'地铁10',},
{name:'地铁11',},
{name:'公交112',},
{name:'公交597',},
{name:'公交593',},
],
results:[],
}
},
created() {
this.results = JSON.parse(JSON.stringify(this.infos));
},
methods: {
inputSearchText : (function(timeout){
var timer;
return function(e){
if(timer){
clearTimeout(timer);
}
timer = setTimeout(() => {
this.search(e.target.value);
//this.search_text = e.target.value
}, timeout);
}
})(1000),
search(text){
var reg = RegExp(`(${text})`);
var results = JSON.parse(JSON.stringify(this.infos));
var matches = results.filter(info=>info.name.match(reg));
matches.forEach(info=>{
info.name = info.name.replace(reg,`<span class='highlight'>$1</span>`
)});
this.results = matches;
console.log(this.results);
}
},
components:{
myitem,
},
})
</script>
<style>
.highlight{
color:red;
}
</style>
</html> |
export function addMark(q, val) {
if (/^[\w\s\+\-]+$/.test(q)) {
let reg = q;
if (/(\s-|-\s)+[^\s-]/.test(q)) {
reg = q.split(/(\s-|-\s)/)[0];
} else if (/[\s+]+[^\s+]/.test(q)) {
reg = q.replace(/([\s+]+)/, '|');
}
reg = new RegExp(`(${reg})`,'igm');
return val.replace(reg,`<b>$1</b>`)
} else {
return val.replace(q,`<b>${q}</b>`)
}
} 个人网站在我看到此题前实现了一个,为纯英文时,需要注意不区分大小写.返回值通过vue v-html渲染
|
应用用节流还是防抖? |
debounce不是防抖么? |
mark一下,这个问题真的有意思 |
处理中文输入,再加个防抖。如果用数据驱动视图,可以“原地复用”,才是最优解。 <body>
<input id="input" type="text" />
<div id="box"></div>
<script>
let list = [
{ id: 1, name: "部门A", parentId: 0 },
{ id: 2, name: "部门B", parentId: 0 },
{ id: 3, name: "部门C", parentId: 1 },
{ id: 4, name: "部门D", parentId: 1 },
{ id: 5, name: "部门E", parentId: 2 },
{ id: 6, name: "部门F", parentId: 3 },
{ id: 7, name: "部门G", parentId: 2 },
{ id: 8, name: "部门H", parentId: 4 }
];
input.addEventListener("input", handleSearch);
input.addEventListener("compositionstart", handleStart);
input.addEventListener("compositionend", handleEnd);
function regLikeSearch(str) {
let htmls = "";
list.forEach(item => {
const match = item.name.replace(
new RegExp(str, "ig"),
(all, match) => {
return `<span style="color: red">${all}</span>`;
}
);
htmls += `<p>${match}</p>`;
});
box.innerHTML = htmls;
}
let isZhcn = false;
function handleSearch(e) {
if (!isZhcn) {
const val = e.target.value;
console.log("handleSearch", val);
regLikeSearch(val);
}
}
function handleStart(e) {
isZhcn = true;
}
function handleEnd(e) {
isZhcn = false;
handleSearch(e);
}
</script>
</body> |
|
v-html的xss攻击这样这样解决?
|
厉害,但是有点就是我看到实现的debounce是防抖,确实是使用防抖不能使用节流,只是最上面的文案是要修改一手。赞 |
let list = [
|
function a(str, childStr){ |
|
这不是防抖吗? @lhyt |
结合输入中文:compisitionsart compositionend
|
let panter = new RegExp(关键词, 'ig') |
在这里我有个问题,如果是富文本编辑器返回的内容,如何高亮选中,然后后端怎么在查找的时候,帅选掉那些标签呢 |
'变蓝变红变绿变蓝变'.match(/(变蓝)|((?!变蓝).)+/g) |
React 版本import { useEffect, useRef, useState } from "react";
const allData = ["asdew", "aedf", "123", "asdf"];
export default function App() {
const [inputVal, setInputVal] = useState("");
const data = useData(inputVal);
return (
<div className="App">
<input
value={inputVal}
onChange={(e) => {
const text = e.target.value;
setInputVal(text);
}}
/>
<ul>
{data.map((dataItem) => {
return (
<li>
{dataItem.split("").map((item) => {
return (
<span style={{ color: inputVal.includes(item) ? "red" : "" }}>
{item}
</span>
);
})}
</li>
);
})}
</ul>
</div>
);
}
const useData = (value) => {
const val = useDebounce(value, 500);
const [data, setData] = useState([]);
useEffect(() => {
if (!val) {
setData([]);
return;
}
setData(allData.filter((item) => item.includes(val)));
}, [val]);
return data;
};
const useDebounce = (value, interval = 1000) => {
const [data, setData] = useState(value);
const timer = useRef(null);
useEffect(() => {
clearTimeout(timer.current);
timer.current = setTimeout(() => {
setData(value);
}, interval);
return () => {
clearTimeout(timer.current);
};
}, [value, interval]);
return data;
}; |
|
The text was updated successfully, but these errors were encountered: