所以,这是我第一次尝试编写功能性搜索栏。这是我的 html、css 和 js 代码,用于编写一个简单的搜索栏。 HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="search-script.js" defer></script>
<title>Document</title>
<link rel="stylesheet" href="search-styles.css" />
</head>
<body>
<div class="search-wrapper">
<label for="search">Search Books</label>
<input type="search" id="search" data-search />
</div>
<div class="book-cards" data-book-cards-container>
<template data-book-template>
<div class="card">
<div class="header" data-header></div>
<div class="body" data-body></div>
</div>
</template>
</div>
</body>
</html>
CSS:
.search-wrapper {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
input {
font-size: 1rem;
}
.book-cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
gap: 0.25rem;
margin-top: 1rem;
}
/* animated card styling video od web dev simplified */
.card {
border: 1px solid black;
background-color: white;
padding: 0.5rem;
}
.card > .header {
margin-bottom: 0.25rem;
}
.card > .body {
font-size: 0.8rem;
color: #777;
}
.hide {
display: none;
}
JavaScript:
const bookCardTemplate = document.querySelector("[data-book-template]");
const bookCardContainer = document.querySelector("[data-book-cards-container]");
const searchInput = document.querySelector("[data-search]");
let books = [];
searchInput.addEventListener("input", (e) => {
const value = e.target.value.toLowerCase();
books.forEach((book) => {
const isVisible =
book.book_name.toLowerCase().includes(value) ||
book.author_name.toLowerCase().includes(value);
book.element.classList.toggle("hide", !isVisible);
});
});
fetch("http://localhost:3000/books")
.then((res) => res.json())
.then((data) => {
books = data.map((book) => {
const card = bookCardTemplate.content.cloneNode(true).children[0];
const header = card.querySelector("[data-header]");
const body = card.querySelector("[data-body]");
header.textContent = book.book_name;
body.textContent = book.author_name;
bookCardContainer.append(card);
return {
title: book.book_name,
author: book.author_name,
element: card,
};
});
});
它通过模拟 API 连接到 db.json 文件:
{
"books": [
{
"id": 0,
"book_name": "To Kill a Mockingbird",
"author_name": "Harper Lee",
"rating": 4.3,
"rating_count": 3252349,
"price": 11.99
},
{
"id": 1,
"book_name": "1984",
"author_name": "George Orwell",
"rating": 4.28,
"rating_count": 2743585,
"price": 10.99
}
]}
现在,运行此代码时,会显示所有卡片,但在搜索栏中输入内容时,它们不会被过滤。 因此,搜索栏不起作用,这是控制台的错误:
search-script.js:11 Uncaught TypeError: Cannot read properties of undefined (reading 'toLowerCase')
at search-script.js:11:22
at Array.forEach (<anonymous>)
at HTMLInputElement.<anonymous> (search-script.js:9:9)
如果错误消息“无法读取未定义的属性(读取'toLowerCase')”意味着当我尝试调用变量 book 的 toLowerCase() 方法时变量 book 未定义(因为当 searchInput.addEventListener 时 books 数组为空)首先附加 () 事件监听器),然后在附加事件监听器之前用一些数据初始化 books 数组(通过调用 fetch() 函数从 API 获取数据,然后将结果分配给 books 数组)应该修复问题,但事实并非如此。 因为当我更新 js 代码时(我将更新后的代码放在下面),我在控制台中收到此错误:
search-script.js:18 Uncaught TypeError: Cannot read properties of undefined (reading 'classList')
at search-script.js:18:22
at Array.forEach (<anonymous>)
at HTMLInputElement.<anonymous> (search-script.js:14:13)
导致上述错误的更新后的JS代码:
const bookCardTemplate = document.querySelector("[data-book-template]");
const bookCardContainer = document.querySelector("[data-book-cards-container]");
const searchInput = document.querySelector("[data-search]");
let books;
fetch("http://localhost:3000/books")
.then((res) => res.json())
.then((data) => {
books = data;
searchInput.addEventListener("input", (e) => {
const value = e.target.value.toLowerCase();
books.forEach((book) => {
const isVisible =
book.book_name.toLowerCase().includes(value) ||
book.author_name.toLowerCase().includes(value);
book.element.classList.toggle("hide", !isVisible);
});
});
});
我知道这个问题可能听起来很愚蠢,而且我已经阅读了类似问题的页面,但他们的问题对我来说似乎不同,我真的不知道如何让我的搜索栏工作。所以感谢您在这里的任何帮助。 另外,有没有更简单的方法来编写搜索栏,例如已经测试过的组件或类似的东西?
你的事件处理程序应该是这样的:
searchInput.addEventListener("input", function (e) {
const value = e.target.value.toLowerCase();
books.forEach((book) => {
const isVisible =
book.title.toLowerCase().includes(value) ||
book.author.toLowerCase().includes(value);
book.element.classList.toggle("hide", !isVisible);
});
});
书籍对象中没有
book_name
或 author_name
,因为您在设置书籍值时更改了它们的名称。