实现:
我有一个HTML页面,其中包含项目容器:
<section class="products">
<div class="container">
<h2 class="products-title">Some title</h2>
<div class="products-items"></div>
<button class="products-btn">Show more</button>
</div>
</section>
我有一个data.js文件,里面有一个项目数组(16个项目),下面是一个例子:
export const products = [
{
id: 0,
name: 'Product 1',
price: 23,
category: 'Category 1',
imgSrc: './images/product-photo.jpg',
},
];
我使用.map()
解析了data.js文件以填充"products items"div:
const displayProducts = products => {
const productsContainer = document.querySelector('.products-items');
const newProducts = products.map(product => {
const {
id,
name,
price,
category,
imgSrc,
} = product;
return `
<div class="product-item" data-id="${id}">
<p>${name}</p>
<p>${price}</p>
<p>${category}</p>
<img src="${imgSrc}" alt="product photo">
</div>
`;
}).join('');
productsContainer.innerHTML = newProducts;
};
export default displayProducts;
在app.js中,我导入了products变量和displayProducts函数。
如果我传递products变量来显示像displayProducts(products)
这样的产品,它将显示所有16个项目。
所需结果:
我需要的是只显示前4个项目,每次用户点击"显示更多"按钮时加载4个新项目。最后,所有16个项目都应该显示出来,"显示更多"按钮应该隐藏起来。
当我将所有16项都作为HTML中的静态数据时。默认情况下,我使用CSS隐藏项目:.product-item {display: none}
然后,我在前4个项目中添加了类"product item--active",以默认显示它们:.product-item--active {display: block}
,并使用此功能为按钮点击上的剩余项目添加活动类:
const showMoreBtn = document.querySelector('.products-btn');
let currentItems = 4;
showMoreBtn.addEventListener('click', e => {
const elementList = [
...document.querySelectorAll('.products-items .product-item'),
];
for (let i = currentItems; i < currentItems + 4; i++) {
if (elementList[i]) {
elementList[i].classList.add('product-item--active');
}
}
currentItems += 4;
// Hide load more button after all items were loaded
if (currentItems >= elementList.length) {
e.target.style.display = 'none';
}
});
问题:
但是现在,当项目动态加载时,该功能就不起作用了。
我学会了如何使用.slice()
:显示前4项
let firstItems = products.slice(0, 4);
displayProducts(firstItems);
但是,我不知道如何在按钮点击时加载新项目,并在所有项目显示后隐藏它。
更新(已解决):我很感激提供的带有良好解释和示例的答案。非常感谢。在检查了它们之后,我有了以下解决方案(以防有人发现它有用)。此外,我删除了多余的CSS中的"product-item-active"类,现在默认情况下不需要隐藏项目:
import { products } from './data.js';
import displayProducts from './components/displayProducts.js';
const showMoreBtn = document.querySelector('.products-btn');
let currentItems = 0;
const displayNextFour = () => {
displayProducts(products.slice(currentItems, currentItems + 4));
// Display next 4 items until their amount exceeds
// the array length
if (!(currentItems + 4 > products.length)) {
currentItems += 4;
}
// Remove event listener from 'Show more' button and
// hide it after all items from the array are displayed
if (currentItems === products.length) {
showMoreBtn.removeEventListener('click', displayNextFour);
showMoreBtn.style.display = 'none';
}
};
displayNextFour();
showMoreBtn.addEventListener('click', displayNextFour);
使用16个随机字符串的数组来显示内容,可以随意使用这个最小的可复制示例。它使用insertAdjacentHTML
在单击按钮时附加一个由4个项目组成的块。这样可以防止每次点击时覆盖所有html。单击处理程序是使用事件委派分配的。如果显示的项目数等于可用项目数,则该按钮将被禁用。
第二个想法可能是隐藏除[pageSize
]项之外的所有项,然后单击按钮取消隐藏下一个[pageSize
]项。请参阅此stackblitz片段。这个片段更通用:它启用了可变数量的项目,并设置了页面大小(随后显示的项目数)。它不需要额外的跟踪变量。
initRandomStrExt();
document.addEventListener(`click`, handle);
const fakeArray = [...Array(16)].map(v => String.getRandom(32));
// show first 4 items on page load
addFourItems(fakeArray);
function handle(evt) {
if (evt.target.classList.contains(`products-btn`)) {
return addFourItems(fakeArray);
}
}
function addFourItems(fromArr) {
// determine n of currently visible items
const start = document.querySelectorAll(`.product-item`).length;
// disable the button if all items will be visible after running this
if (start === fromArr.length - 4) {
document.querySelector(`.products-btn`).setAttribute(`disabled`, true);
}
// append 4 items of the array to the .product-items container
document.querySelector(`.products-items`)
.insertAdjacentHTML(`beforeend`,
`<div>${fromArr.slice(start, start + 4)
// ^ slice the next 4 items from the array
.map((item, i) => `<div class="product-item">${i + 1 + start} - ${
item}</div>`).join(``)}</div>`);
}
// for demo, random string helper
function initRandomStrExt() {
if (String.getRandom) {
return;
}
const characters = [...Array(26)]
.map((x, i) => String.fromCharCode(i + 65))
.concat([...Array(26)].map((x, i) => String.fromCharCode(i + 97)))
.concat([...Array(10)].map((x, i) => `${i}`));
const getCharacters = excludes =>
excludes && characters.filter(c => !~excludes.indexOf(c)) || characters;
String.getRandom = (len = 12, excludes = []) => {
const chars = getCharacters(excludes);
return [...Array(len)]
.map(() => chars[Math.floor(Math.random() * chars.length)])
.join("");
};
};
<section class="products">
<div class="container">
<h2 class="products-title">Some title</h2>
<div class="products-items"></div>
<p><button class="products-btn">Show more</button></p>
</div>
您可以创建一个全局变量来跟踪哪些项目应该被分配,例如current_index
。然后创建一个函数,例如displayNextFour()
,每次显示四个项目,并相应地更新current_index
。然后点击按钮调用displayNextFour()
函数。
let current_index = 0
const displayNextFour = () => {
displayProducts(products.slice(current_index, current_index+4));
//console.log(products.slice(current_index, current_index+4))
if(current_index + 4 <= products.length)
current_index+=4
}
(在displayProducts
中创建具有product-item--active
类的元素)