使用多个类别过滤项目类别 - Javascript

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

我有一个关于通过单击多个按钮在页面上显示多个类别的问题。代码笔: https://codepen.io/alena-chuyankova/pen/YzmWYKZ

  1. 默认情况下所有页面均处于活动状态;
  2. 当我单击和取消单击某些按钮时,具有相同类别的卡片应该显示和隐藏(到目前为止适用于一个类别);
  3. 当我有多个按钮时,它应该显示和隐藏具有相应类别的卡片。就像如果用户想要查看带有鲑鱼和虾的产品一样,应该显示包含鲑鱼和虾的卡片。就像如果某个按钮处于活动状态以显示包含按钮内部文本的所有内容(如果有意义的话)。 非常感谢!

let products = {
  data: [
    {
      productName: "Fantasy",
      heart: "./icons/heart.svg",
      heartCount: 2547,
      category: "Salmon, Shrimp",
      content:
        "Lorem ipsum dolor sit amet, eu mei posse possim atomorum, vix cu fabellas assueverit. Vel ad option partiendo maiestatis, nec affert appetere te, his.",
      picture: "./images/pexels-diego-pontes-901015-2323391.jpg",
    },
    {
      productName: "Spring",
      heart: "./icons/heart.svg",
      heartCount: 2547,
      category: "Veggie",
      content:
        "Lorem ipsum dolor sit amet, eu mei posse possim atomorum, vix cu fabellas assueverit. Vel ad option partiendo maiestatis, nec affert appetere te, his.",
      picture: "./images/pexels-pixabay-357756.jpg",
    },
    {
      productName: "Rainbow",
      heart: "./icons/heart.svg",
      heartCount: 2547,
      category: "Salmon, Tuna, Unagi",
      content:
        "Lorem ipsum dolor sit amet, eu mei posse possim atomorum, vix cu fabellas assueverit. Vel ad option partiendo maiestatis, nec affert appetere te, his.",
      picture: "./images/pexels-freestockpro-3147493.jpg",
    },
    {
      productName: "Unique",
      heart: "./icons/heart.svg",
      heartCount: 2547,
      category: "Salmon, Tuna, Unagi, Shrimp",
      content:
        "Lorem ipsum dolor sit amet, eu mei posse possim atomorum, vix cu fabellas assueverit. Vel ad option partiendo maiestatis, nec affert appetere te, his.",
      picture: "./images/pexels-photo-248444.webp",
    },
    {
      productName: "Perfection",
      heart: "./icons/heart.svg",
      heartCount: 2547,
      category: "Salmon",
      content:
        "Lorem ipsum dolor sit amet, eu mei posse possim atomorum, vix cu fabellas assueverit. Vel ad option partiendo maiestatis, nec affert appetere te, his.",
      picture: "./images/pexels-isabella-mendes-107313-858501.jpg",
    },
    {
      productName: "Style",
      heart: "./icons/heart.svg",
      heartCount: 2547,
      category: "Salmon, Tuna, Unagi, Shrimp",
      content:
        "Lorem ipsum dolor sit amet, eu mei posse possim atomorum, vix cu fabellas assueverit. Vel ad option partiendo maiestatis, nec affert appetere te, his.",
      picture: "./images/pexels-rajesh-tp-749235-2098143.jpg",
    },
    {
      productName: "Dreamy",
      heart: "./icons/heart.svg",
      heartCount: 2547,
      category: "Salmon",
      content:
        "Lorem ipsum dolor sit amet, eu mei posse possim atomorum, vix cu fabellas assueverit. Vel ad option partiendo maiestatis, nec affert appetere te, his.",
      picture: "./images/pexels-viniciusbenedit-3620705.jpg",
    },
    {
      productName: "Spicy",
      heart: "./icons/heart.svg",
      heartCount: 2547,
      category: "Shrimp",
      content:
        "Lorem ipsum dolor sit amet, eu mei posse possim atomorum, vix cu fabellas assueverit. Vel ad option partiendo maiestatis, nec affert appetere te, his.",
      picture: "./images/pexels-catscoming-699544.jpg",
    },
  ],
};

for (let i of products.data) {
  let card = document.createElement("div");
  card.classList.add("card", "i.category");

  //image

  let imgContainer = document.createElement("div");
  imgContainer.classList.add("image-container");
  let image = document.createElement("img");
  image.classList.add("product-img");
  image.setAttribute("src", i.picture);
  imgContainer.appendChild(image);
  card.appendChild(imgContainer);
  document.getElementById("products").appendChild(card);
  card.setAttribute("title", i.category);

  image.addEventListener("error", () => {
    image.style.display = "none"; // Hide the broken image
    image.parentNode.style.backgroundColor = "#d9d9d9"; // Set background color
  });

  //content

  let content = document.createElement("div");
  content.classList.add("content");
  card.appendChild(content);

  //content title and likes section

  let contentHead = document.createElement("div");
  contentHead.classList.add("contentHead");
  let productTitle = document.createElement("h2");
  productTitle.classList.add("productTitle");
  productTitle.innerText = i.productName;

  let likesSection = document.createElement("div");
  likesSection.classList.add("likesSection");
  let likesIcon = document.createElement("img");
  likesIcon.setAttribute("src", "./icons/heart.svg");
  likesIcon.classList.add("likesIcon");
  let likesCount = document.createElement("p");
  likesCount.classList.add("likeCount");
  likesCount.innerText = i.heartCount;

  content.appendChild(contentHead);
  contentHead.appendChild(productTitle);
  contentHead.appendChild(likesSection);
  likesSection.appendChild(likesIcon);
  likesSection.appendChild(likesCount);

  likesIcon.addEventListener("error", () => {
    likesIcon.setAttribute(
      "src",
      "https://upload.wikimedia.org/wikipedia/commons/f/f1/Heart_coraz%C3%B3n.svg"
    );
  });

  //gray line devider
  let line = document.createElement("hr");
  line.classList.add("product-line");
  content.appendChild(line);

  //item category

  let itemCategory = document.createElement("p");
  itemCategory.classList.add("item-category");
  itemCategory.innerText = i.category;
  content.appendChild(itemCategory);

  //description

  let itemDescription = document.createElement("p");
  itemDescription.classList.add("itemDescription");
  itemDescription.innerText = i.content;
  content.appendChild(itemDescription);

  //read more
  let readMore = document.createElement("p");
  readMore.classList.add("readMore");
  readMore.innerText = "Read more >>>";
  content.appendChild(readMore);
}

let buttons = document.querySelectorAll(".category-button");
let cards = document.querySelectorAll(".card");
let buttonArr = [];
let buttonsString;

buttons.forEach((button) => {
  button.addEventListener("click", () => {
    let buttonValue = button.innerText;
    button.classList.toggle("active-button");
    if (button.classList.contains("active-button")) {
      buttonArr.push(buttonValue);
    }
    if (button.classList.contains("active-button") == false) {
      let unwantedButtonValue = buttonValue;
      let index = buttonArr.indexOf(unwantedButtonValue);
      buttonArr.splice(index, 1);
    }
    buttonArr.sort();
    buttonsString = buttonArr.toString();
    console.log(buttonsString);
  });

  buttons.forEach((button) => {
    button.addEventListener("click", () => {
      cards.forEach((card) => {
        let cardCategories;
        cardCategories = card
          .getAttribute("title")
          .split(",")
          .map(function (value) {
            return value.trim();
          })
          .sort()
          .toString();
        console.log(cardCategories);
        if (cardCategories.includes(buttonsString) == false) {
          card.classList.add("inactive-card");
        }
        if (cardCategories.includes(buttonsString)) {
          card.classList.remove("inactive-card");
        }
      });
    });
  });
});
javascript html filter categories
1个回答
0
投票

问题出在比较两个字符串的这段代码中。它适用于单一类别,因为例如“鲑鱼”包含在“鲑鱼、金枪鱼、虾”中。它因两个类别而失败,因为“鲑鱼,虾”不包含在“鲑鱼,金枪鱼,虾”中。词序不一样。

  if (cardCategories.includes(buttonsString) == false) {
    card.classList.add("inactive-card");
  }
  if (cardCategories.includes(buttonsString)) {
    card.classList.remove("inactive-card");
  }

您可以轻松解决此问题,因为您已经拥有一系列按钮类别。 因此,您可以使用 Array.some 显示包含任何关键字的卡片,或使用 Array.every 显示所有关键字(似乎您想要 every)。并且您可以使用 classList.toggle 根据比赛结果设置类别。

将上述代码替换为以下过滤器之一:

(并注意前导“!”不在切换逻辑中)

  // (1) OR  - card includes any keyword
  card.classList.toggle(
    'inactive-card',
    !buttonArr.some(name => cardCategories.includes(name)) // boolean
   )
  
  // (2) AND - card include all keywords
    card.classList.toggle(
    'inactive-card',
    !buttonArr.every(name => cardCategories.includes(name)) // boolean
   )

let products = {
  data: [
    {
      productName: "Fantasy",
      heart: "./icons/heart.svg",
      heartCount: 2547,
      category: "Salmon, Shrimp",
      content:
        "Lorem ipsum dolor sit amet, eu mei posse possim atomorum, vix cu fabellas assueverit. Vel ad option partiendo maiestatis, nec affert appetere te, his.",
      picture: "./images/pexels-diego-pontes-901015-2323391.jpg",
    },
    {
      productName: "Spring",
      heart: "./icons/heart.svg",
      heartCount: 2547,
      category: "Veggie",
      content:
        "Lorem ipsum dolor sit amet, eu mei posse possim atomorum, vix cu fabellas assueverit. Vel ad option partiendo maiestatis, nec affert appetere te, his.",
      picture: "./images/pexels-pixabay-357756.jpg",
    },
    {
      productName: "Rainbow",
      heart: "./icons/heart.svg",
      heartCount: 2547,
      category: "Salmon, Tuna, Unagi",
      content:
        "Lorem ipsum dolor sit amet, eu mei posse possim atomorum, vix cu fabellas assueverit. Vel ad option partiendo maiestatis, nec affert appetere te, his.",
      picture: "./images/pexels-freestockpro-3147493.jpg",
    },
    {
      productName: "Unique",
      heart: "./icons/heart.svg",
      heartCount: 2547,
      category: "Salmon, Tuna, Unagi, Shrimp",
      content:
        "Lorem ipsum dolor sit amet, eu mei posse possim atomorum, vix cu fabellas assueverit. Vel ad option partiendo maiestatis, nec affert appetere te, his.",
      picture: "./images/pexels-photo-248444.webp",
    },
    {
      productName: "Perfection",
      heart: "./icons/heart.svg",
      heartCount: 2547,
      category: "Salmon",
      content:
        "Lorem ipsum dolor sit amet, eu mei posse possim atomorum, vix cu fabellas assueverit. Vel ad option partiendo maiestatis, nec affert appetere te, his.",
      picture: "./images/pexels-isabella-mendes-107313-858501.jpg",
    },
    {
      productName: "Style",
      heart: "./icons/heart.svg",
      heartCount: 2547,
      category: "Salmon, Tuna, Unagi, Shrimp",
      content:
        "Lorem ipsum dolor sit amet, eu mei posse possim atomorum, vix cu fabellas assueverit. Vel ad option partiendo maiestatis, nec affert appetere te, his.",
      picture: "./images/pexels-rajesh-tp-749235-2098143.jpg",
    },
    {
      productName: "Dreamy",
      heart: "./icons/heart.svg",
      heartCount: 2547,
      category: "Salmon",
      content:
        "Lorem ipsum dolor sit amet, eu mei posse possim atomorum, vix cu fabellas assueverit. Vel ad option partiendo maiestatis, nec affert appetere te, his.",
      picture: "./images/pexels-viniciusbenedit-3620705.jpg",
    },
    {
      productName: "Spicy",
      heart: "./icons/heart.svg",
      heartCount: 2547,
      category: "Shrimp",
      content:
        "Lorem ipsum dolor sit amet, eu mei posse possim atomorum, vix cu fabellas assueverit. Vel ad option partiendo maiestatis, nec affert appetere te, his.",
      picture: "./images/pexels-catscoming-699544.jpg",
    },
  ],
};

for (let i of products.data) {
  let card = document.createElement("div");
  card.classList.add("card", "i.category");

  //image

  let imgContainer = document.createElement("div");
  imgContainer.classList.add("image-container");
  let image = document.createElement("img");
  image.classList.add("product-img");
  image.setAttribute("src", i.picture);
  imgContainer.appendChild(image);
  card.appendChild(imgContainer);
  document.getElementById("products").appendChild(card);
  card.setAttribute("title", i.category);

  image.addEventListener("error", () => {
    image.style.display = "none"; // Hide the broken image
    image.parentNode.style.backgroundColor = "#d9d9d9"; // Set background color
  });

  //content

  let content = document.createElement("div");
  content.classList.add("content");
  card.appendChild(content);

  //content title and likes section

  let contentHead = document.createElement("div");
  contentHead.classList.add("contentHead");
  let productTitle = document.createElement("h2");
  productTitle.classList.add("productTitle");
  productTitle.innerText = i.productName;

  let likesSection = document.createElement("div");
  likesSection.classList.add("likesSection");
  let likesIcon = document.createElement("img");
  likesIcon.setAttribute("src", "./icons/heart.svg");
  likesIcon.classList.add("likesIcon");
  let likesCount = document.createElement("p");
  likesCount.classList.add("likeCount");
  likesCount.innerText = i.heartCount;

  content.appendChild(contentHead);
  contentHead.appendChild(productTitle);
  contentHead.appendChild(likesSection);
  likesSection.appendChild(likesIcon);
  likesSection.appendChild(likesCount);

  likesIcon.addEventListener("error", () => {
    likesIcon.setAttribute(
      "src",
      "https://upload.wikimedia.org/wikipedia/commons/f/f1/Heart_coraz%C3%B3n.svg"
    );
  });

  //gray line devider
  let line = document.createElement("hr");
  line.classList.add("product-line");
  content.appendChild(line);

  //item category

  let itemCategory = document.createElement("p");
  itemCategory.classList.add("item-category");
  itemCategory.innerText = i.category;
  content.appendChild(itemCategory);

  //description

  let itemDescription = document.createElement("p");
  itemDescription.classList.add("itemDescription");
  itemDescription.innerText = i.content;
  content.appendChild(itemDescription);

  //read more
  let readMore = document.createElement("p");
  readMore.classList.add("readMore");
  readMore.innerText = "Read more >>>";
  content.appendChild(readMore);
}

let buttons = document.querySelectorAll(".category-button");
let cards = document.querySelectorAll(".card");
let buttonArr = [];
let buttonsString;

buttons.forEach((button) => {
  button.addEventListener("click", () => {
    let buttonValue = button.innerText;
    button.classList.toggle("active-button");
    if (button.classList.contains("active-button")) {
      buttonArr.push(buttonValue);
    }
    if (button.classList.contains("active-button") == false) {
      let unwantedButtonValue = buttonValue;
      let index = buttonArr.indexOf(unwantedButtonValue);
      buttonArr.splice(index, 1);
    }
    buttonArr.sort();
    buttonsString = buttonArr.toString();
    console.log(buttonsString);

    cards.forEach((card) => {
      let cardCategories;
      cardCategories = card
        .getAttribute("title")
        .split(",")
        .map(function (value) {
          return value.trim();
        })
        .sort()
        .toString();
      
      // ADDED
      
      // OR  - card includes any keyword
      /*
      card.classList.toggle(
        'inactive-card',
        !buttonArr.some(name => cardCategories.includes(name))
       )
      */
      
      // AND - card include all keywords
        card.classList.toggle(
        'inactive-card',
        !buttonArr.every(name => cardCategories.includes(name))
       )
    
      
      
      /* REMOVED
      if (cardCategories.includes(buttonsString) == false) {
        card.classList.add("inactive-card");
      }
      if (cardCategories.includes(buttonsString)) {
        card.classList.remove("inactive-card");
      }
      */
    });
  });
});
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  height: 100%;
  width: 100%;
  display: flex;
  justify-content: center;
  font-family: 'Roboto', sans-serif;
  background-color: #EEEEEE;
}

.wrap {
  position: absolute;
  top: 50%;
  transform: translate(0, -50%);
  background-color: white;
  gap: 1rem;
  width: 45%;
  box-shadow: rgba(50, 50, 93, 0.25) 0px 13px 27px -5px, rgba(0, 0, 0, 0.3) 0px 8px 16px -8px;
  display: flex;
  flex-direction: column;
  padding: 4rem;
}

.logo-phrase {
  color: #FF3D00;
  text-align: center;
}

.logo-phrase-red {
  color: white;
  background-color: #FF3D00;
}

.hr-h1 {
  width: 10%;
  align-self: center;
  border: 1px solid #d9d9d9;
  margin-bottom: 1rem;
}

.nav-buttons {
  display: flex;
  justify-content: center;
  gap: 2rem;
}

.category-button {
  display: flex;
  padding: 1rem 2rem;
  font-size: 1.3rem;
  border-radius: 0.8rem;
  border: 1.5px solid #FF3D00;
  color: #FF3D00;
  background-color: white;
  font-weight: 500;
}

.active-button {
  background-color: #FF3D00;
  color: white;
}

#products {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-column-gap: 1rem;
}

.card {
  width: 100%;
  display: flex;
  gap: 1.5rem;
  background-color: white;
  margin-top: 1rem;
  padding: 1rem;
}

.active-card {
  display: flex;
}

.inactive-card {
  display: none;
}

.image-container {
  width: 35%;
  text-align: center;
  border-radius: 1rem;
}

.product-img {
  background-color: #d9d9d9;
  width: 100%;
  border-radius: 1rem;
  height: 10.5rem;
  object-fit: cover;
  padding: 1px;
}

.content {
  width: 65%;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.contentHead {
  width: 100%;
  display: flex;
  justify-content: space-between;
}

.likesSection {
  display: flex;
  width: 15%;
  justify-content: space-between;
}

.likesIcon {
  width: 20%;
  align-self: center;
}

.likeCount {
  color: #FF3D00;
  align-self: center;
  font-weight: bold;
}

.product-line {
  border: 1px solid #d9d9d9;
}

.item-category {
  font-weight: bold;
}

.readMore {
  font-weight: bold;
  color: #FF3D00;
}

@media screen and (max-width: 3500px) {
  .wrap {
    width: 65%;
  }
}

@media screen and (max-width: 2500px) {
  .wrap {
    width: 75%;
  }
}

@media screen and (max-width: 2100px) {
  .wrap {
    position: static;
    top: 15%;
    transform: none;
    margin: 2rem 0;
    width: 85%;
  }
}

@media screen and (max-width: 1700px) {
  .wrap {
    width: 95%;
  }
}

@media screen and (max-width: 1100px) {
  .wrap {
    margin: 2rem 0;
    max-width: 50%;
    justify-self: center;
  }
  .nav-buttons {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    width: 80%;
    justify-self: center;
    align-self: center;
  }
  .category-button {
    flex-grow: 1;
  }
  #products {
    display: grid;
    grid-template-columns: 1fr;
    grid-column-gap: 1rem;
    width: 100%;
  }
  .card {
    justify-self: center;
    flex-direction: column;
    width: 80%;
    padding: 0;
    padding-top: 1rem;
  }
  .card:first-child {
    padding-top: 0;
  }
  .image-container {
    width: 100%;
    height: 15rem;
  }
  .product-img {
    height: 15rem;
  }
  .content {
    width: 100%;
  }
}

@media screen and (max-width: 1100px) {
  .wrap {
    max-width: 60%;
  }
}

@media screen and (max-width: 1000px) {
  .wrap {
    max-width: 65%;
  }
}

@media screen and (max-width: 1000px) {
  .wrap {
    max-width: 65%;
  }
}

@media screen and (max-width: 900px) {
  .wrap {
    max-width: 70%;
  }
}

@media screen and (max-width: 800px) {
  .wrap {
    max-width: 75%;
  }
}

@media screen and (max-width: 700px) {
  .wrap {
    max-width: 100%;
  }
  .image-container {
    height: 12rem;
  }
  .product-img {
    height: 12rem;
  }
}
<div class="wrap">
  <h1 class="logo-phrase">SayHiSus<span class="logo-phrase-red">Hi</span></h1>
  <hr class="hr-h1">
  <nav class="nav-buttons">
    <button class="category-button">Salmon</button>
    <button class="category-button">Tuna</button>
    <button class="category-button">Unagi</button>
    <button class="category-button">Shrimp</button>
    <button class="category-button">Veggie</button>
  </nav>
  <div id="products"></div>
</div>

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