-
题目要求
请使用 Vue 或原生DOM ,完成 index.html 文件中的 TODO 部分。
1. 完成数据请求(数据来源 ./data.json),data.json 是宋词数据,poetry_content 表示词句,title 表示词牌名,author 表示词人。
2. 在输入框输入关键词时在 ul(class = suggestions)的元素中实时显示词牌名、词句、词人中包含关键词的完整词句(包含词牌名、词人)列表,当关键词为空或者匹配不到时 ul(class = suggestions)元素的子节点为空。完整词句的 DOM 结构按照如下规定显示:
<!-- 每一首完整词句用一个 li 包裹 -->
<li>
<span class="poet">词句</span>
<span class="title">词牌名 - 词人</span>
</li>
例:
<li>
<span class="poet">常记溪亭日暮,沉醉不知归路。兴尽晚回舟,误入藕花深处。
争渡,争渡,惊起一滩鸥鹭</span>
<span class="title">如梦令 - 李清照</span>
</li>
3. 高亮匹配到的所有词句中的关键词。即使用 <span class="highlight"></span> 标签
包裹所有关键词。例:(关键词:雨)
<li>
<span class="poet">寒蝉凄切,对长亭晚,骤<span class="highlight">雨
</span>初歇。都门帐饮无绪,方留恋处,兰舟催发。执手相看泪眼,竟无语凝噎。念去
去千里烟波,暮霭沉沉楚天阔。多情自古伤离别,更那堪冷落清秋节。今宵酒醒何处,杨柳
岸晓风残月。此去经年,应是良辰美景虚设。便纵有千种风情,更与何人说</span>
<span class="title"><span class="highlight">雨</span>霖铃 - 柳永
</span>
</li>
注意:本题要求的是实时显示,即输入完成的同时显示结果,非失去焦点显示
-
目标分析
目标一:完成数据请求(数据来源 ./data.json)
使用fetch直接获取数据,并且对数据的格式进行处理。
// 获取数据
fetch("./data.json")
.then((res) => res.json())
.then((data) => {
poetdata = data;
// console.log(poetdata);
});
目标二:通过input中的输入,进行实时搜索。完成input中输入的获取,以及需要实时进行搜索。
为了实时获取input中输入的数据,设置一个事件监听器。
input.addEventListener("input", function (e) {
const keyword = e.target.value;
suggestionsList.innerHTML = "";
if (!keyword) {
return;
}
目标三:通过获取到的关键字在获取到的数据中进行搜索。
将用户输入的 keyword
转换为小写(lowerKeyword
),确保搜索不区分大小写。将每个数据项的 poetry_content
、title
、author
也转换为小写,与 lowerKeyword
进行比较。
使用 includes()
方法,检查关键词是否是目标字段的子串(无需完全匹配)。
const results = poetdata.filter((item) => {
const lowerKeyword = keyword.toLowerCase();
return (
item.poetry_content.toLowerCase().includes(lowerKeyword) || // 检查词句
item.title.toLowerCase().includes(lowerKeyword) || // 检查词牌名
item.author.toLowerCase().includes(lowerKeyword) // 检查词人
);
});
目标四:将搜索到的数据按照一定的格式渲染到页面中。
results.forEach((item) => {
const li = document.createElement("li");
li.innerHTML = `
<span class="poet">${item.poetry_content}</span>
<span class="title">${item.title}-${item.author}</span> `;
suggestionsList.appendChild(li);
});
目标五:将结果中的关键字进行高亮处理。
将用户输入的 keyword
包裹在捕获组 ()
中,生成正则表达式,并使用 gi
修饰符(全局匹配 + 不区分大小写)。
function highlight(text, keyword) {
const regex = new RegExp(`(${keyword})`, "gi");
return text.replace(regex, `<span class="highlight">$1</span>`);
}
然后再输出代码中添加高亮。
-
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>绝美宋词</title>
<link rel="stylesheet" href="css/style.css" />
<script src="./js/axios.min.js"></script>
</head>
<body>
<div class="container">
<h1 style="text-align: center">输入关键字,找一首词</h1>
<div class="search-form">
<input
type="text"
id="searchInput"
class="search"
placeholder="词牌名 词句 词人"
/>
<ul class="suggestions" id="suggestionsList">
<li>
<!-- 示例 -->
<!-- <span class="poet"></span> -->
<!-- <span class="title"></span> -->
</li>
</ul>
</div>
</div>
<script>
// TODO:待补充代码
window.onload = function () {
let poetdata = [];
// 获取数据
fetch("./data.json")
.then((res) => res.json())
.then((data) => {
poetdata = data;
// console.log(poetdata);
});
// 获取输入框
const input = document.querySelector("#searchInput");
const suggestionsList = document.querySelector("#suggestionsList");
// input监听器
input.addEventListener("input", function (e) {
const keyword = e.target.value;
suggestionsList.innerHTML = "";
if (!keyword) {
return;
}
// 数组一部分的浅拷贝
const results = poetdata.filter((item) => {
const lowerKeyword = keyword.toLowerCase();
return (
item.poetry_content.toLowerCase().includes(lowerKeyword) || // 检查词句
item.title.toLowerCase().includes(lowerKeyword) || // 检查词牌名
item.author.toLowerCase().includes(lowerKeyword) // 检查词人
);
});
// console.log(results);
results.forEach((item) => {
const li = document.createElement("li");
li.innerHTML = `
<span class="poet">${highlight(
item.poetry_content,
keyword
)}</span>
<span class="title">${highlight(item.title, keyword)}-${highlight(
item.author,
keyword
)}</span>
`;
suggestionsList.appendChild(li);
});
});
// 高亮处理
function highlight(text, keyword) {
const regex = new RegExp(`(${keyword})`, "gi");
return text.replace(regex, `<span class="highlight">$1</span>`);
}
};
</script>
</body>
</html>