题目描述
-
实现一个备忘录,通过搜索框来增加todo事件
-
每个todo都要有对应的删除方法
-
搜索框要实现补全功能
-
补全时,只显示匹配的todo项
-
补全时,匹配的字体要显示为红色
实现效果图
先上图。
开撕代码
样式随便瞎写的,凑合凑合看就好。重点是js方面的逻辑。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
* {
margin: 0;
padding: 0;
border: 0;
}
ul li {
list-style-type: none;
}
main {
width: 90%;
min-height: 800px;
border: 2px solid black;
margin: 0 auto;
background: #f6f1f1;
/*align-content: center;*/
/*justify-content: center;*/
display: grid;
/*主轴居中*/
justify-items: center;
/*交叉轴居中*/
align-items: center;
}
.container {
width: 600px;
background: white;
border: 2px solid black;
box-shadow: 5px 5px 2px black;
text-align: center;
}
.search-box {
display: inline-block;
margin: 20px auto;
/*border: 1px solid black;*/
}
input[name="search-input"] {
font-weight: bold;
font-size: 18px;
border: 2px solid black;
border-radius: 10px;
width: 300px;
height: 40px;
outline: none;
}
button { /* 按钮美化 */
width: 60px; /* 宽度 */
height: 50px; /* 高度 */
border-width: 0; /* 边框宽度 */
border-radius: 3px; /* 边框半径 */
background: #1E90FF; /* 背景颜色 */
cursor: pointer; /* 鼠标移入按钮范围时出现手势 */
outline: none; /* 不显示轮廓线 */
color: white; /* 字体颜色 */
font-size: 17px; /* 字体大小 */
}
button:hover { /* 鼠标移入按钮范围时改变颜色 */
background: #5599FF;
}
ul li {
text-align: left;
font-weight: bold;
font-size: 16px;
padding: 10px;
border-top: 1px solid #666;
}
li .del {
float: right;
}
li .suggest {
color: red;
}
</style>
</head>
<body>
<main>
<div class="container">
<div class="search-box">
<label>
<input id="id-input" name="search-input" type="text"/>
<button id="id-commit">提交</button>
</label>
</div>
<div class="suggest-box">
<ul id="id-suggest">
</ul>
</div>
</div>
</main>
<script>
let eInput = document.getElementById("id-input");
let eCommit = document.getElementById("id-commit");
let eSuggest = document.getElementById("id-suggest");
// 提交
function commit() {
let textStr = eInput.value;
if (textStr === '') {
return;
}
let tLi = document.createElement('li');
let tSpan = document.createElement('span');
let tA = document.createElement('a');
tA.className = "del";
tA.innerText = "删除"
tA.href = "#"
tLi.appendChild(tSpan);
tLi.appendChild(tA);
tSpan.innerText = textStr;
eSuggest.appendChild(tLi);
// 清空输入框
eInput.value = '';
// 绑定删除方法
tA.onclick = function (event) {
event.preventDefault();
eSuggest.removeChild(this.parentNode);
};
}
// 模糊查询
function suggest() {
let str = eInput.value;
let suggestItems = eSuggest.getElementsByTagName("li");
// 匹配到的文字变红色,准备工作
let reg = new RegExp('(' + str + ')', 'g');
for (let i = 0; i < suggestItems.length; i++) {
let tSpan = suggestItems[i].getElementsByTagName("span")[0];
let newStr = tSpan.innerText.replace(reg, '<span class="suggest">$1</span>')
//也选用innerHTML
if (tSpan.innerText.indexOf(str) === -1) {
suggestItems[i].style.display = 'none'; //匹配不到的掩藏
} else {
//匹配到的变红
tSpan.innerHTML = newStr;
}
}
if (str === '') {
for (let i = 0; i < suggestItems.length; i++) {
suggestItems[i].style.display = 'block';//输入框空时全部显示
}
}
}
eInput.onkeyup = function (event) {
if (event.keyCode === 13) {
commit();
}
suggest();
}
eCommit.onclick = function () {
commit();
suggest();
};
suggest();
</script>
</body>
</html>
进阶版 防抖加持
先上效果图
代码仅供参考,因为这只是个临场发挥的雏形,想实现得更完美,还需细细雕琢。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
* {
margin: 0;
padding: 0;
border: 0;
}
ul li {
list-style-type: none;
}
main {
width: 90%;
min-height: 800px;
border: 2px solid black;
margin: 0 auto;
background: #f6f1f1;
/*align-content: center;*/
/*justify-content: center;*/
display: grid;
/*主轴居中*/
justify-items: center;
/*交叉轴居中*/
align-items: center;
}
.container {
width: 600px;
background: white;
border: 2px solid black;
box-shadow: 5px 5px 2px black;
text-align: center;
}
.search-box {
display: inline-block;
margin: 20px auto;
/*border: 1px solid black;*/
}
input[name="search-input"] {
font-weight: bold;
font-size: 18px;
border: 2px solid black;
border-radius: 10px;
width: 300px;
height: 40px;
outline: none;
}
button { /* 按钮美化 */
width: 60px; /* 宽度 */
height: 50px; /* 高度 */
border-width: 0; /* 边框宽度 */
border-radius: 3px; /* 边框半径 */
background: #1E90FF; /* 背景颜色 */
cursor: pointer; /* 鼠标移入按钮范围时出现手势 */
outline: none; /* 不显示轮廓线 */
color: white; /* 字体颜色 */
font-size: 17px; /* 字体大小 */
}
button:hover { /* 鼠标移入按钮范围时改变颜色 */
background: #5599FF;
}
ul li {
text-align: left;
font-weight: bold;
font-size: 16px;
padding: 10px;
border-top: 1px solid #666;
}
li .del {
float: right;
}
li .suggest {
color: red;
}
</style>
</head>
<body>
<main>
<div class="container">
<div class="search-box">
<label>
<input id="id-input" name="search-input" type="text"/>
<button id="id-commit">提交</button>
</label>
</div>
<div class="suggest-box">
<ul id="id-suggest">
</ul>
</div>
</div>
</main>
<script>
let eInput = document.getElementById("id-input");
let eCommit = document.getElementById("id-commit");
let eSuggest = document.getElementById("id-suggest");
// 提交
function commit() {
let textStr = eInput.value;
if (textStr === '') {
return;
}
let tLi = document.createElement('li');
let tSpan = document.createElement('span');
let tA = document.createElement('a');
tA.className = "del";
tA.innerText = "删除"
tA.href = "#"
tLi.appendChild(tSpan);
tLi.appendChild(tA);
tSpan.innerText = textStr;
eSuggest.appendChild(tLi);
// 清空输入框
eInput.value = '';
// 绑定删除方法
tA.onclick = function (event) {
event.preventDefault();
eSuggest.removeChild(this.parentNode);
};
}
// 模糊查询
function suggest() {
let str = eInput.value;
console.log(str)
let suggestItems = eSuggest.getElementsByTagName("li");
// 匹配到的文字变红色,准备工作
let reg = new RegExp('(' + str + ')', 'g');
for (let i = 0; i < suggestItems.length; i++) {
let tSpan = suggestItems[i].getElementsByTagName("span")[0];
let newStr = tSpan.innerText.replace(reg, '<span class="suggest">$1</span>')
//也选用innerHTML
if (tSpan.innerText.indexOf(str) === -1) {
suggestItems[i].style.display = 'none'; //匹配不到的掩藏
} else {
//匹配到的变红
tSpan.innerHTML = newStr;
}
}
if (str === '') {
for (let i = 0; i < suggestItems.length; i++) {
suggestItems[i].style.display = 'block';//输入框空时全部显示
}
}
eSuggest.style.display = "block";
}
// 防抖
function debounce(func, delay = 1000, immediate = false) {
let timer;
let returnFunc = function () {
let context = this;
let args = arguments;
// 每次这个返回的函数被调用,就清除定时器,以保证不执行 fn
if (timer !== null) {
clearTimeout(timer);
}
if (immediate === false) {
// 不立即执行 即 先等待再执行
// 当返回的函数被最后一次调用后(也就是用户停止了某个连续的操作),
// 再过 delay 毫秒就执行 fn
timer = setTimeout(function () {
func.apply(context, args)
}, delay)
} else {
//立即执行 先执行再等待
// 通过该参数控制只执行一次
let rightNow = !timer;
// 此时立刻执行
if (rightNow) {
func.apply(context, args);
}
// 设置定时清理
timer = setTimeout(function () {
timer = null;
}, delay);
}
}
// 不想等待了 现在立即执行
returnFunc.cancel = function () {
console.log("不想等待了,取消等待");
clearTimeout(timer);
timer = null;
}
return returnFunc;
}
// 使用防抖装饰器后的suggest函数
let debounceSuggest = debounce(suggest, 1000);
eInput.onkeyup = function (event) {
if (event.keyCode === 13) {
commit();
}
eSuggest.style.display = "none"
debounceSuggest();
}
eCommit.onclick = function () {
commit();
suggest();
};
suggest();
</script>
</body>
</html>