搜索栏不会过滤,因为未捕获类型错误:无法读取未定义的属性(读取“toLowerCase”)

问题描述 投票:0回答:1

所以,这是我第一次尝试编写功能性搜索栏。这是我的 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);
      });
    });
  });

我知道这个问题可能听起来很愚蠢,而且我已经阅读了类似问题的页面,但他们的问题对我来说似乎不同,我真的不知道如何让我的搜索栏工作。所以感谢您在这里的任何帮助。 另外,有没有更简单的方法来编写搜索栏,例如已经测试过的组件或类似的东西?

javascript html css filter searchbar
1个回答
0
投票

你的事件处理程序应该是这样的:

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
,因为您在设置书籍值时更改了它们的名称。

© www.soinside.com 2019 - 2024. All rights reserved.