Я создаю вымышленный интернет-магазин растений и в настоящее время работаю над их фильтрацией, комбинируя различные параметры (требование света, потребление воды, токсичность и т. д.).
Используя отдельный файл JSON, я создаю карточки на основе данных после получения файла JSON:
getPlants().then((data) => {
data.forEach((data) => {
plantcards.insertAdjacentHTML(
"afterbegin",
`<article class = "plantcard ${getPlantLight(data.Light)} ${getPlantWater(
data.WaterDemand
)}wasser ${getPlantToxic(data.Toxic)}">
<div class = "article-wrapper">
<figure>
<img src = "../images/plant_types/${data.Image}" alt = "${data.Name}" />
</figure>
<div class = "article-body">
<h2>${data.Name}</h2>
<h3>${data.NameLatin}</h3>
<p>
Standort: ${getPlantLight(data.Light)}<br/>
Wasserbedarf: ${getPlantWater(data.WaterDemand)}<br/>
Schwierigkeitsgrad: ${getPlantMaintenance(data.Maintenance)}<br/>
Giftig: ${getPlantToxic(data.Toxic)}<br/>
</p>
<a href = "#" class = "read-more">
Read more <span class = "sr-only">about this is some title</span>
<svg xmlns = "http://www.w3.org/2000/svg" class = "icon" viewBox = "0 0 20 20" fill = "currentColor">
<path fill-rule = "evenodd" d = "M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z" clip-rule = "evenodd" />
</svg>
</a>
</div>
</div>
</article>`
);
});
});
let allPlantcards = Array.from(document.querySelectorAll(".plantcard"));
allPlantcards
всегда пустой массив длиной 0, я думаю, потому что allPlantcards
создается до или во время загрузки карточек.
Я также пытался разместить let allPlantcards = Array.from(document.querySelectorAll(".plantcard"));
внутри других функций, но тогда я не смогу использовать их вне функции, верно?
🤔 А знаете ли вы, что...
JavaScript позволяет создавать собственные серверные приложения с использованием платформы Node.js.
Похоже, вы столкнулись с проблемой синхронизации: вы пытаетесь выбрать элементы, которые еще не добавлены в DOM, потому что ваш вызов document.querySelectorAll(".plantcard")
выполняется до вставки карточек.
Вот скромное предложение рабочего кода:
Этот HTML-шаблон устанавливает базовую структуру и функциональность для отображения карточек растений и управления ими в интернет-магазине. Настройте пути к изображениям и данным в соответствии с потребностями вашего приложения.
getPlants()
имитирует получение данных о заводе. Замените это фактическим вызовом API. getPlantLight()
, getPlantWater()
, getPlantToxic()
и getPlantMaintenance()
определяют классы CSS на основе атрибутов растений. displayPlantCards(data)
добавляет карточки растений в DOM и затем выбирает их.
async function getPlants() {
return [{
Name: "Aloe Vera",
NameLatin: "Aloe barbadensis",
Light: "Bright",
WaterDemand: "Low",
Maintenance: "Easy",
Toxic: "No",
Image: "https://fastly.picsum.photos/id/649/200/300.jpg?hmac=3hfKZ0fzc7Ie_jSDrRCLD-bO3e71sZ_5xyZmJQXyNFg"
},
{
Name: "Spider Plant",
NameLatin: "Chlorophytum comosum",
Light: "Indirect",
WaterDemand: "Medium",
Maintenance: "Easy",
Toxic: "No",
Image: "https://fastly.picsum.photos/id/649/200/300.jpg?hmac=3hfKZ0fzc7Ie_jSDrRCLD-bO3e71sZ_5xyZmJQXyNFg"
}
// Add more plant objects as needed
];
}
function getPlantLight(light) {
return light === "Bright" ? "bright-light" : "indirect-light";
}
function getPlantWater(waterDemand) {
return waterDemand === "Low" ? "low-water" : "medium-water";
}
function getPlantToxic(toxic) {
return toxic === "Yes" ? "toxic" : "non-toxic";
}
function getPlantMaintenance(maintenance) {
return maintenance === "Easy" ? "easy-maintenance" : "hard-maintenance";
}
function displayPlantCards(data) {
const plantcards = document.getElementById("plantcards");
data.forEach((plant) => {
plantcards.insertAdjacentHTML(
"beforeend",
`<article class = "plantcard ${getPlantLight(plant.Light)} ${getPlantWater(
plant.WaterDemand
)} ${getPlantToxic(plant.Toxic)}">
<div class = "article-wrapper">
<figure>
<img src = "${plant.Image}" alt = "${plant.Name}" />
</figure>
<div class = "article-body">
<h2>${plant.Name}</h2>
<h3>${plant.NameLatin}</h3>
<p>
Standort: ${getPlantLight(plant.Light)}<br/>
Wasserbedarf: ${getPlantWater(
plant.WaterDemand
)}<br/>
Schwierigkeitsgrad: ${getPlantMaintenance(
plant.Maintenance
)}<br/>
Giftig: ${getPlantToxic(plant.Toxic)}<br/>
</p>
<a href = "#" class = "read-more">
Read more
<svg xmlns = "http://www.w3.org/2000/svg" class = "icon" viewBox = "0 0 20 20" fill = "currentColor">
<path fill-rule = "evenodd" d = "M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z" clip-rule = "evenodd" />
</svg>
</a>
</div>
</div>
</article>`
);
});
// After inserting the plant cards, you can select them
const allPlantcards = Array.from(document.querySelectorAll(".plantcard"));
// Example: Add your logic to filter or manipulate plant cards here
console.info(allPlantcards); // Check if cards are correctly selected
}
// Fetch data and display plant cards
getPlants().then((data) => {
displayPlantCards(data);
});
#plantcards {
display: flex;
flex-wrap: wrap;
gap: 20px;
padding: 20px;
justify-content: center;
}
.plantcard {
width: 200px;
background-color: #f0f0f0;
border: 1px solid #ddd;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
}
.article-wrapper {
display: flex;
flex-direction: column;
flex: 1;
}
.article-body {
padding: 10px;
flex: 1;
display: flex;
flex-direction: column;
}
.article-body h2 {
margin: 0;
font-size: 1.2em;
}
.article-body h3 {
margin: 5px 0;
color: #555;
font-size: 1em;
}
.article-body p {
margin: 10px 0;
font-size: 0.9em;
color: #333;
}
.read-more {
display: flex;
align-items: center;
text-decoration: none;
color: #007bff;
font-weight: bold;
margin-top: auto;
padding: 10px;
border-top: 1px solid #ddd;
background-color: #fff;
}
.read-more .icon {
margin-left: 5px;
width: 16px;
height: 16px;
}
.plantcard img {
width: 100%;
height: auto;
display: block;
}
<div id = "plantcards">
<!-- Plant cards will be dynamically inserted here -->
</div>
Проблема, с которой вы столкнулись, на самом деле связана с тем, что querySelectorAll вызывается до того, как элементы были добавлены в DOM с помощью InsertAdjacentHTML. Чтобы решить эту проблему, нужно убедиться, что код выбора элементов выполняется после добавления всех карточек растений в DOM.
Просто переместите вызов querySelectorAll в конец getPlants().then(...), чтобы он выполнялся после добавления всех карточек в DOM:
getPlants().then((data) => {
data.forEach((data) => {
plantcards.insertAdjacentHTML(
"afterbegin",
`<article class = "plantcard ${getPlantLight(data.Light)} ${getPlantWater(
data.WaterDemand
)}wasser ${getPlantToxic(data.Toxic)}">
<div class = "article-wrapper">
<figure>
<img src = "../images/plant_types/${data.Image}" alt = "${data.Name}" />
</figure>
<div class = "article-body">
<h2>${data.Name}</h2>
<h3>${data.NameLatin}</h3>
<p>
Standort: ${getPlantLight(data.Light)}<br/>
Wasserbedarf: ${getPlantWater(data.WaterDemand)}<br/>
Schwierigkeitsgrad: ${getPlantMaintenance(data.Maintenance)}<br/>
Giftig: ${getPlantToxic(data.Toxic)}<br/>
</p>
<a href = "#" class = "read-more">
Read more <span class = "sr-only">about this is some title</span>
<svg xmlns = "http://www.w3.org/2000/svg" class = "icon" viewBox = "0 0 20 20" fill = "currentColor">
<path fill-rule = "evenodd" d = "M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z" clip-rule = "evenodd" />
</svg>
</a>
</div>
</div>
</article>`
);
});
// Now the cards have already been added to the DOM and we can select them
let allPlantcards = Array.from(document.querySelectorAll(".plantcard"));
console.info(allPlantcards); // Now allPlantcards will not be empty
});