商城自定义评论模块轮播,适配不同的设备
这种样式在网站非常美观,而且用户可以直接点击下面的产品访问产品。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
/* 容器基础样式 */
.custom-review-container {
max-width: 1200px;
margin: 20px auto;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
position: relative;
overflow: hidden;
padding: 20px 0;
user-select: none;
}
/* 轨道:使用 align-items: stretch 确保所有子卡片高度一致 */
.review-track {
display: flex;
align-items: stretch;
transition: transform 0.5s cubic-bezier(0.2, 0, 0.2, 1);
gap: 15px;
will-change: transform;
}
/* 评价卡片样式 */
.review-card {
flex-shrink: 0;
background: #ffffff;
border: 1px solid #ebebeb;
border-radius: 12px;
padding: 18px;
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
display: flex;
flex-direction: column;
justify-content: space-between;
box-sizing: border-box;
transition: transform 0.3s;
/* 确保即使没内容也有基础高度 */
min-height: 250px;
}
.review-card:hover {
transform: translateY(-5px);
}
/* 用户及文字信息 */
.reviewer-info { display: flex; align-items: center; margin-bottom: 12px; }
.avatar-img { width: 40px; height: 40px; border-radius: 50%; object-fit: cover; margin-right: 12px; background: #eee; }
.reviewer-name { font-size: 14px; font-weight: 600; color: #333; }
.stars { color: #FFBC00; font-size: 14px; margin-bottom: 10px; }
/* 文本区域:flex-grow 配合 align-items: stretch 实现等高 */
.review-text {
font-size: 13px; color: #555; line-height: 1.6; margin-bottom: 15px;
display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical;
overflow: hidden; flex-grow: 1;
}
/* 产品链接区 */
.product-link {
text-decoration: none; display: flex; align-items: center;
border-top: 1px solid #f0f0f0; padding-top: 12px; margin-top: auto;
}
.product-img { width: 45px; height: 45px; border-radius: 6px; margin-right: 10px; object-fit: cover; }
.product-info { flex: 1; overflow: hidden; }
.product-name { font-size: 11px; color: #222; font-weight: 500; display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.view-detail { font-size: 10px; color: #0073aa; margin-top: 2px; }
/* 控制按钮 */
.nav-btn {
position: absolute; top: 50%; transform: translateY(-50%);
background: white; border: 1px solid #eee; width: 40px; height: 40px;
border-radius: 50%; cursor: pointer; z-index: 10;
display: flex; align-items: center; justify-content: center;
box-shadow: 0 4px 10px rgba(0,0,0,0.1);
transition: all 0.2s;
outline: none;
font-weight: bold;
}
.nav-btn:hover { background: #f9f9f9; color: #0073aa; }
.nav-btn:active { background: #f0f0f0; transform: translateY(-50%) scale(0.9); }
.prev-btn { left: 10px; }
.next-btn { right: 10px; }
</style>
</head>
<body>
<div class="custom-review-container" id="carouselContainer">
<button class="nav-btn prev-btn" id="prevBtn" aria-label="Previous">❮</button>
<div class="review-track" id="reviewTrack">
<!-- 评价 1-12 组内容 -->
<div class="review-card">
<div class="reviewer-info">
<img src="https://i.pravatar.cc/100?u=1" alt="Avatar" class="avatar-img">
<div class="reviewer-name">Emma Watson</div>
</div>
<div class="stars">★★★★★</div>
<div class="review-text">这款产品的设计感真的太棒了,完全符合我的审美。</div>
<a href="#" class="product-link">
<img src="https://picsum.photos/100/100?random=1" alt="Product" class="product-img">
<div class="product-info"><span class="product-name">高端无线耳机 Pro</span><span class="view-detail">查看详情 ></span></div>
</a>
</div>
<div class="review-card">
<div class="reviewer-info">
<img src="https://i.pravatar.cc/100?u=2" alt="Avatar" class="avatar-img">
<div class="reviewer-name">Liam Chen</div>
</div>
<div class="stars">★★★★★</div>
<div class="review-text">第二次回购了,排版整洁,购物体验极佳!我会推荐给我的所有朋友们。</div>
<a href="#" class="product-link">
<img src="https://picsum.photos/100/100?random=2" alt="Product" class="product-img">
<div class="product-info"><span class="product-name">极简风手机壳</span><span class="view-detail">查看详情 ></span></div>
</a>
</div>
<div class="review-card">
<div class="reviewer-info">
<img src="https://i.pravatar.cc/100?u=3" alt="Avatar" class="avatar-img">
<div class="reviewer-name">Sophia Li</div>
</div>
<div class="stars">★★★★☆</div>
<div class="review-text">包装很用心,颜色正,推荐购买。</div>
<a href="#" class="product-link">
<img src="https://picsum.photos/100/100?random=3" alt="Product" class="product-img">
<div class="product-info"><span class="product-name">产品名称 3</span><span class="view-detail">查看详情 ></span></div>
</a>
</div>
<div class="review-card">
<div class="reviewer-info">
<img src="https://i.pravatar.cc/100?u=4" alt="Avatar" class="avatar-img">
<div class="reviewer-name">User 4</div>
</div>
<div class="stars">★★★★★</div>
<div class="review-text">做工精细,实物比照片还要好看。每一个细节都处理得非常完美。</div>
<a href="#" class="product-link">
<img src="https://picsum.photos/100/100?random=4" alt="Product" class="product-img">
<div class="product-info"><span class="product-name">产品名称 4</span><span class="view-detail">查看详情 ></span></div>
</a>
</div>
<div class="review-card">
<div class="reviewer-info">
<img src="https://i.pravatar.cc/100?u=5" alt="Avatar" class="avatar-img">
<div class="reviewer-name">User 5</div>
</div>
<div class="stars">★★★★★</div>
<div class="review-text">客服态度很好,解答非常有耐心。物流也非常快。</div>
<a href="#" class="product-link">
<img src="https://picsum.photos/100/100?random=5" alt="Product" class="product-img">
<div class="product-info"><span class="product-name">产品名称 5</span><span class="view-detail">查看详情 ></span></div>
</a>
</div>
<div class="review-card">
<div class="reviewer-info">
<img src="https://i.pravatar.cc/100?u=6" alt="Avatar" class="avatar-img">
<div class="reviewer-name">User 6</div>
</div>
<div class="stars">★★★★★</div>
<div class="review-text">物流速度惊人,隔天就收到了!产品质量完全超出预期。</div>
<a href="#" class="product-link">
<img src="https://picsum.photos/100/100?random=6" alt="Product" class="product-img">
<div class="product-info"><span class="product-name">产品名称 6</span><span class="view-detail">查看详情 ></span></div>
</a>
</div>
<div class="review-card">
<div class="reviewer-info">
<img src="https://i.pravatar.cc/100?u=7" alt="Avatar" class="avatar-img">
<div class="reviewer-name">User 7</div>
</div>
<div class="stars">★★★★★</div>
<div class="review-text">已经分享给身边的朋友了。好东西值得被更多人发现。</div>
<a href="#" class="product-link">
<img src="https://picsum.photos/100/100?random=7" alt="Product" class="product-img">
<div class="product-info"><span class="product-name">产品名称 7</span><span class="view-detail">查看详情 ></span></div>
</a>
</div>
<div class="review-card">
<div class="reviewer-info">
<img src="https://i.pravatar.cc/100?u=8" alt="Avatar" class="avatar-img">
<div class="reviewer-name">User 8</div>
</div>
<div class="stars">★★★★★</div>
<div class="review-text">非常精致,这个价格能买到这种品质很划算。</div>
<a href="#" class="product-link">
<img src="https://picsum.photos/100/100?random=8" alt="Product" class="product-img">
<div class="product-info"><span class="product-name">产品名称 8</span><span class="view-detail">查看详情 ></span></div>
</a>
</div>
<div class="review-card">
<div class="reviewer-info">
<img src="https://i.pravatar.cc/100?u=9" alt="Avatar" class="avatar-img">
<div class="reviewer-name">User 9</div>
</div>
<div class="stars">★★★★★</div>
<div class="review-text">好评好评好评,重要的事说三遍。</div>
<a href="#" class="product-link">
<img src="https://picsum.photos/100/100?random=9" alt="Product" class="product-img">
<div class="product-info"><span class="product-name">产品名称 9</span><span class="view-detail">查看详情 ></span></div>
</a>
</div>
<div class="review-card">
<div class="reviewer-info">
<img src="https://i.pravatar.cc/100?u=10" alt="Avatar" class="avatar-img">
<div class="reviewer-name">User 10</div>
</div>
<div class="stars">★★★★★</div>
<div class="review-text">期待后续更多新款产品。这家的风格我太喜欢了。</div>
<a href="#" class="product-link">
<img src="https://picsum.photos/100/100?random=10" alt="Product" class="product-img">
<div class="product-info"><span class="product-name">产品名称 10</span><span class="view-detail">查看详情 ></span></div>
</a>
</div>
<div class="review-card">
<div class="reviewer-info">
<img src="https://i.pravatar.cc/100?u=11" alt="Avatar" class="avatar-img">
<div class="reviewer-name">User 11</div>
</div>
<div class="stars">★★★★★</div>
<div class="review-text">手感不错,没有异味,材质用得很扎实。</div>
<a href="#" class="product-link">
<img src="https://picsum.photos/100/100?random=11" alt="Product" class="product-img">
<div class="product-info"><span class="product-name">产品名称 11</span><span class="view-detail">查看详情 ></span></div>
</a>
</div>
<div class="review-card">
<div class="reviewer-info">
<img src="https://i.pravatar.cc/100?u=12" alt="Avatar" class="avatar-img">
<div class="reviewer-name">User 12</div>
</div>
<div class="stars">★★★★★</div>
<div class="review-text">已经是这家的忠实粉丝了。每次上新都会来看看。</div>
<a href="#" class="product-link">
<img src="https://picsum.photos/100/100?random=12" alt="Product" class="product-img">
<div class="product-info"><span class="product-name">产品名称 12</span><span class="view-detail">查看详情 ></span></div>
</a>
</div>
</div>
<button class="nav-btn next-btn" id="nextBtn" aria-label="Next">❯</button>
</div>
<script>
const track = document.getElementById('reviewTrack');
const container = document.getElementById('carouselContainer');
const nextBtn = document.getElementById('nextBtn');
const prevBtn = document.getElementById('prevBtn');
let originalCount = 0;
let currentIndex = 0;
let cardWidth = 0;
let isTransitioning = false;
let autoPlayTimer = null;
const gap = 15;
function setupCarousel() {
const allCards = Array.from(track.children);
originalCount = allCards.length;
// 构建三组用于无缝循环
const beforeNodes = allCards.map(node => node.cloneNode(true));
const afterNodes = allCards.map(node => node.cloneNode(true));
beforeNodes.forEach(node => track.insertBefore(node, track.firstChild));
afterNodes.forEach(node => track.appendChild(node));
currentIndex = originalCount;
// 确保图片加载或布局稳定后计算
window.addEventListener('load', calculateLayout);
setTimeout(calculateLayout, 100);
startAutoPlay();
}
function calculateLayout() {
const containerWidth = container.offsetWidth;
let visibleCount = 4;
if (window.innerWidth <= 600) visibleCount = 2;
else if (window.innerWidth <= 1024) visibleCount = 3;
cardWidth = (containerWidth - (visibleCount - 1) * gap) / visibleCount;
const allCardsInDom = track.querySelectorAll('.review-card');
allCardsInDom.forEach(card => {
card.style.width = `${cardWidth}px`;
});
updatePosition(false);
}
function updatePosition(animate = true) {
if (animate) {
track.style.transition = 'transform 0.5s cubic-bezier(0.2, 0, 0.2, 1)';
} else {
track.style.transition = 'none';
}
const offset = currentIndex * (cardWidth + gap);
track.style.transform = `translateX(-${offset}px)`;
}
function move(step) {
if (isTransitioning) return;
isTransitioning = true;
currentIndex += step;
updatePosition(true);
}
// 监听过渡结束,处理无缝跳转
track.addEventListener('transitionend', () => {
isTransitioning = false;
if (currentIndex >= originalCount * 2) {
currentIndex = originalCount;
updatePosition(false);
} else if (currentIndex <= 0) {
currentIndex = originalCount;
updatePosition(false);
}
});
// 强力纠偏逻辑,防止长时间运行后的累计误差
function startAutoPlay() {
stopAutoPlay();
autoPlayTimer = setInterval(() => {
if (!isTransitioning) move(1);
}, 3000);
}
function stopAutoPlay() {
if (autoPlayTimer) clearInterval(autoPlayTimer);
}
// 点击事件改为直接处理,并确保重置播放器
nextBtn.addEventListener('click', (e) => {
e.preventDefault();
move(1);
startAutoPlay();
});
prevBtn.addEventListener('click', (e) => {
e.preventDefault();
move(-1);
startAutoPlay();
});
// 鼠标交互
container.addEventListener('mouseenter', stopAutoPlay);
container.addEventListener('mouseleave', startAutoPlay);
// 初始化
setupCarousel();
window.addEventListener('resize', calculateLayout);
// 触屏支持
let startX = 0;
container.addEventListener('touchstart', (e) => {
startX = e.touches[0].clientX;
stopAutoPlay();
}, {passive: true});
container.addEventListener('touchend', (e) => {
const delta = startX - e.changedTouches[0].clientX;
if (Math.abs(delta) > 50) {
move(delta > 0 ? 1 : -1);
}
startAutoPlay();
}, {passive: true});
</script>
</body>
</html>
© 文章版权归白小菌所有,🫰欢迎转发分享。未经允许请勿抄袭转载。
订阅评论
登录
0 评论
最新











