开发者问题收集

未捕获的类型错误:无法读取 null Javascript 的属性“classList”

2021-07-09
162

我有一个对象列表或数组,我通过模板将其传递给 HTML 元素。我有一个 removeItem 函数。它正在删除项目。但在最后一项上,它不会隐藏它。我试图在菜单中没有项目时隐藏菜单。但在最后一项上,它卡住了,没有做任何进一步的事情。模板导致了所有问题。除了模板隐藏之外,其他所有项目都是如此。但事实并非如此。我的 shoppingCart.js 将 cartRemove.classList.add("hide") 设置为 null。.hide 具有 display:none 属性。 错误:

Uncaught TypeError: Cannot read property 'classList' of null
    at hideCart (shoppingCart.js:74)
    at renderCart (shoppingCart.js:54)
    at removeFromCart (shoppingCart.js:68)
    at HTMLDocument.<anonymous> (shoppingCart.js:29)

我的问题的 Gif

shoppingCart.js

import items from "./items.json";
import { formatCurrency } from "./utils/formatCurrency.js";

const menu = document.querySelector(".menu");
const cart = document.querySelector("#cart");
const cartRemove = document.querySelector("[data-cart-item]");

const storeCartContainer = document.querySelector("[data-cart-container]");
const cartItemTemplate = document.querySelector("#cart-item-template");
const cartQuantity = document.querySelector("[data-cart-quantity]");
const cartTotal = document.querySelector("[data-cart-total]");
const cartHide = document.querySelector(".ahmad");
// total.innerHTML = cartTotal.innerText
   

let shoppingCart = [];
const IMAGE_URL = "https://dummyimage.com/420x220";

export const toggleCard = cart.addEventListener("click", () => {
  menu.classList.toggle("show");
});

export function setupShoppingCart() {
    document.addEventListener("click", (e) => {
      e.preventDefault()
    if (e.target.matches("[data-remove-to-cart-button]")) {
      const id = parseInt(e.target.closest("[data-cart-item]").dataset.itemId);
        removeFromCart(id);
        if (id === null) {
            renderCart()
        }
    }
  });
    renderCart();
}

export function addToCart(id) {

    const existingItem = shoppingCart.find(entry => entry.id === id)
    if (existingItem) {
        existingItem.quantity++
    }
    else {
     shoppingCart.push({ id: id, quantity: 1 });
    }


  renderCart();
}

function renderCart() {
    if (shoppingCart.length === 0) {
        hideCart()
        // hideData()

    }
    else {
        showCart()
        renderCartItems();
    }
}

function removeFromCart(id) {
  const existingItem = shoppingCart.find((entry) => entry.id === id);
  if (existingItem == null) return;
  shoppingCart = shoppingCart.filter((entry) => entry.id !== id);
  renderCart();

    }
    
    function hideCart() {
      cartHide.classList.add("hide");
    
  cartRemove.classList.add("hide"); // This is getting Null
    }
function showCart() {
    cart.classList.remove("hide")

}

function renderCartItems() {
    cartQuantity.innerText = shoppingCart.length;

    const totalCents = shoppingCart.reduce((sum, entry) => {
        const item = items.find((i) => entry.id === i.id);
        return sum + item.priceCents * entry.quantity

    },0)

    cartTotal.innerText = formatCurrency(totalCents / 100)
    storeCartContainer.innerHTML = "";

    shoppingCart.forEach((entry) => {
        console.log(items, entry);

        const item = items.find((i) => entry.id === i.id);
        const cartItem = cartItemTemplate.content.cloneNode(true);

        const container = cartItem.querySelector("[data-cart-item]");
        container.dataset.itemId = item.id;

        const name = cartItem.querySelector("[data-cart-name]");
        name.innerText = item.name;
        if (entry.quantity > 1) {
            const quantity = cartItem.querySelector("[data-cart-quantity]");
            quantity.innerText = `x${entry.quantity}`;
        }

        const image = cartItem.querySelector("[data-cart-img]");
        image.src = `${IMAGE_URL}/${item.imageColor}/${item.imageColor}`;

    const price = cartItem.querySelector("[data-cart-price]");

    price.innerText = formatCurrency((item.priceCents * entry.quantity) / 100);

    storeCartContainer.appendChild(cartItem);
  });
};

store.index

</head>
  <body>
    <div class="container">
      <div class="front-page">
        <!-- Section 1 -->
        <section class="section-1">
          <a href="#" id="cart" class="ahmad">
            <i class="fas fa-shopping-cart"></i>
            <span data-cart-quantity></span>
          </a>
          <div>
              <div class="menu">
              <div data-cart-container> //Template is under this div
                  <div>
                  </div>
                   </div>
                    <div class="details">
                        <h5>Total</h5>
                         <div data-cart-total>
                         </div> </div>
                </div>
        </section>
</body>
</head>
     <template id="cart-item-template">
             <div data-cart-item class="palette">
            <button data-remove-to-cart-button>Close</button>
                <img data-cart-img class="bgc-menu"></img>
                <div class="palette-detail">
                <div data-cart-name class="palette-color"></div>
                <div data-cart-quantity></div>
                <div data-cart-price class="palette-price"></div>
                </div>
                <!-- <span data-cart-amount class="plz">$0.00</span> -->        
        </template>
2个回答

根据 此答案 ,要定位模板内的元素,您需要使用模板的 content 关键字进行 querySelector ,如下所示:

const template = document.querySelector("#cart-item-template");
const cartRemove = template.content.querySelector("[data-cart-item]");
cartRemove.classList.add("hide"); // Now it works fine
Amadou Beye
2021-07-09

您正尝试在脚本开头引用模板中的元素:

const cartRemove = document.querySelector("[data-cart-item]");

这发生在您的模板被克隆并放入 DOM 之前,因此此时未找到具有属性 data-cart-item 的元素 - 您在 cartRemove 变量中得到 null

renderCartItems 函数中实例化模板后,尝试通过特定实例选择此元素,就像您在这两行中所做的那样:

const cartItem = cartItemTemplate.content.cloneNode(true);
const container = cartItem.querySelector("[data-cart-item]");
Tomasz
2021-07-09