Appearance
Swiper 轮播框
在有限空间内,循环播放同一类型的图片、文字等内容。
CSS样式
全部 swiper 样式代码:
查看代码
css
/* HnuiIcon */
@import url('./icon.css');
/* 全局css变量 */
:root {
/* #region vars-BrandColor */
/* 品牌色 */
--hnui-brand-color: #1f78ff;
--hnui-brand-color1: #005ce5;
--hnui-brand-color2: #4b83f7;
--hnui-brand-color3: #3384ff;
--hnui-brand-color4: #599bff;
--hnui-brand-color5: #80b2ff;
--hnui-brand-color6: #b2d1ff;
--hnui-brand-color7: #cce0ff;
--hnui-brand-color8: #d9e8ff;
--hnui-brand-color9: #ebf3ff;
--hnui-brand-color10: #f2f7ff;
/* 状态颜色 */
--hnui-brand-color-normal: var(--hnui-brand-color);
--hnui-brand-color-hover: var(--hnui-brand-color3);
--hnui-brand-color-active: var(--hnui-brand-color1);
--hnui-brand-color-elected: var(--hnui-brand-color9);
--hnui-brand-color-disabled: var(--hnui-brand-color7);
--hnui-brand-color-disabled-border: var(--hnui-brand-color6);
--hnui-brand-color-disabled-bg: var(--hnui-brand-color10);
/* #endregion vars-BrandColor */
/* #region vars-DomainColor */
/* 功能色 */
--hnui-success-color: #2ba471;
--hnui-success-hover-color: #51bd90;
--hnui-success-active-color: #2ba471;
--hnui-warning-color: #faad14;
--hnui-warning-hover-color: #ffc146;
--hnui-warning-active-color: #db960b;
--hnui-danger-color: #ff4d4d;
--hnui-danger-hover-color: #ff7676;
--hnui-danger-active-color: #d82a2a;
--hnui-info-color: #8d97a6;
--hnui-info-hover-color: #b2b7c0;
--hnui-info-active-color: #707a89;
/* #endregion vars-DomainColor */
/* #region vars-NeutralColor */
/* 中性色 */
/* 标题文字 */
--hnui-neutral-color-1: #2d2e33;
/* 正文、重要信息文字、按钮文字、输入框正常状态文字等 */
--hnui-neutral-color-2: #43454d;
/* 内容文字、说明叙述文字 */
--hnui-neutral-color-3: #5d606a;
/* 提示性文字、辅助文本 */
--hnui-neutral-color-4: #9298a0;
/* 禁用文本 */
--hnui-neutral-color-5: #b7bdc7;
/* 描边格描边、输入文本描边、下拉选择描边等 */
--hnui-neutral-color-6: #dfe2e7;
/* 全局背景、禁用状态、分割线等 */
--hnui-neutral-color-7: #f0f2f5;
/* 最低颜色等 */
--hnui-neutral-color-8: #fafbfc;
/* #endregion vars-NeutralColor */
/* 默认文字颜色 */
--hnui-text-color: var(--hnui-neutral-color-2);
--hnui-info-bg: #eceff4;
--hnui-info-bg2: #e7e7e7;
--hnui-color-white: #fff;
--hnui-color-black: #000;
--hnui-border-width: 1px;
--hnui-border-dashed-width: 2px;
--hnui-border-color: var(--hnui-neutral-color-6);
--hnui-disabled-bg-color: var(--hnui-neutral-color-7);
--hnui-disabled-color: var(--hnui-neutral-color-5);
--hnui-control-height: 32px;
--hnui-control-height-sm: 24px;
--hnui-control-height-lg: 40px;
--hnui-control-transparent: transparent;
}
.dark {
--hnui-brand-color6: rgb(50, 59, 74);
--hnui-brand-color7: #30353d;
--hnui-brand-color8: #42484f;
--hnui-brand-color9: #4c4f54;
--hnui-brand-color10: #29292c;
/* 中性色 */
/* 标题文字 */
--hnui-neutral-color-1: #c4c8dc;
/* 正文、重要信息文字、按钮文字、输入框正常状态文字等 */
--hnui-neutral-color-2: #b9bed3;
/* 内容文字、说明叙述文字 */
--hnui-neutral-color-3: #afb5c7;
/* 提示性文字、辅助文本 */
--hnui-neutral-color-4: #6a6f75;
/* 禁用文本 */
--hnui-neutral-color-5: #53565b;
/* 描边格描边、输入文本描边、下拉选择描边等 */
--hnui-neutral-color-6: #59595a;
/* 全局背景、禁用状态、分割线等 */
--hnui-neutral-color-7: #343535;
/* 最低颜色等 */
--hnui-neutral-color-8: #151516;
--hnui-info-bg: #393b3d;
--hnui-color-white: #000;
--hnui-color-black: #fff;
--hnui-control-transparent: transparent;
}
*,
::before,
::after {
box-sizing: border-box;
}
body {
color: var(--hnui-neutral-color-2);
}
/* #region vars-FontFamily */
@font-face {
font-family: 'DIN';
src: url('/fonts/D-DIN-PRO/D-DIN-PRO.woff2') format('woff2'),
url('/fonts/D-DIN-PRO/D-DIN-PRO.woff') format('woff'),
url('/fonts/D-DIN-PRO/D-DIN-PRO.ttf') format('truetype'),
url('/fonts/D-DIN-PRO/D-DIN-PRO.eot') format('embedded-opentype'),
url('/fonts/D-DIN-PRO/D-DIN-PRO.svg') format('svg');
font-weight: normal;
font-style: normal;
}
/* 使用数字字体 */
.use-font {
font-family: DIN;
}
/* #endregion vars-FontFamily */
/* #region vars-BoxShadow */
/* 一级投影(默认向下) */
.hnui-box-shadow {
box-shadow: 0px 6px 16px 6px rgba(0, 0, 0, 0.18);
}
.hnui-box-shadow.hover,
.hnui-box-shadow:hover {
box-shadow: 0px 6px 16px 6px rgba(31, 120, 255, 0.18);
}
/* 二级投影(默认向下) */
.hnui-box-shadow_l2 {
box-shadow: 0px 6px 16px 6px rgba(0, 0, 0, 0.12);
}
.hnui-box-shadow_l2.hover,
.hnui-box-shadow_l2:hover {
box-shadow: 0px 6px 16px 6px rgba(31, 120, 255, 0.12);
}
/* 三级投影(默认向下) */
.hnui-box-shadow_l3 {
box-shadow: 0px 6px 16px 6px rgba(0, 0, 0, 0.06);
}
.hnui-box-shadow_l3.hover,
.hnui-box-shadow_l3:hover {
box-shadow: 0px 6px 16px 6px rgba(31, 120, 255, 0.06);
}
/* #endregion vars-BoxShadow */css
/* === 基础轮播容器 === */
.hnui-swiper {
--hnui-swiper-height: 400px;
--hnui-swiper-bg: #3c3c3c;
--hnui-swiper-arrow-bg: transparent;
--hnui-swiper-arrow-hover-bg: transparent;
--hnui-swiper-arrow-color: #ffffff;
--hnui-swiper-pagination-bg: rgba(255, 255, 255, 0.3);
--hnui-swiper-pagination-active-bg: #ffffff;
position: relative;
width: 100%;
height: var(--hnui-swiper-height);
overflow: hidden;
border-radius: 6px;
}
/* === 轮播包装器 === */
.hnui-swiper-wrapper {
position: relative;
width: 100%;
height: 100%;
display: flex;
transition: transform 0.3s ease;
}
/* === 轮播项 === */
.hnui-swiper-slide {
flex-shrink: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background: var(--hnui-swiper-bg);
color: #ffffff;
font-size: 48px;
font-weight: bold;
}
/* === 切换箭头 === */
.hnui-swiper-button-prev,
.hnui-swiper-button-next {
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
background: var(--hnui-swiper-arrow-bg);
border: none;
border-radius: 50%;
color: var(--hnui-swiper-arrow-color);
font-size: 20px;
cursor: pointer;
transition: background 0.3s;
z-index: 10;
user-select: none;
}
.hnui-swiper-button-prev:hover,
.hnui-swiper-button-next:hover {
background: var(--hnui-swiper-arrow-hover-bg);
}
.hnui-swiper-button-prev {
left: 16px;
}
.hnui-swiper-button-next {
right: 16px;
}
.hnui-swiper-button-prev::before {
content: "‹";
}
.hnui-swiper-button-next::before {
content: "›";
}
/* === 分页器(条状指示器) === */
.hnui-swiper-pagination {
position: absolute;
bottom: 16px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 8px;
z-index: 10;
}
.hnui-swiper-pagination-bullet {
width: 32px;
height: 4px;
background: var(--hnui-swiper-pagination-bg);
border-radius: 2px;
cursor: pointer;
transition: all 0.3s;
}
.hnui-swiper-pagination-bullet-active {
background: var(--hnui-swiper-pagination-active-bg);
}
/* === 卡片式轮播 === */
.hnui-swiper-cards {
--hnui-swiper-pagination-bg: rgba(0, 0, 0, 0.2);
--hnui-swiper-pagination-active-bg: rgba(0, 0, 0, 0.6);
--hnui-swiper-arrow-color: #666666;
perspective: 1200px;
}
.hnui-swiper-cards .hnui-swiper-wrapper {
display: flex;
align-items: center;
justify-content: center;
}
.hnui-swiper-cards .hnui-swiper-slide {
position: absolute;
width: 30%;
aspect-ratio: 1 / 1;
height: auto;
transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
border-radius: 8px;
}
/* 卡片位置 - 左侧 */
.hnui-swiper-cards .hnui-swiper-slide-prev {
left: 2%;
transform: translateX(0) scale(0.85);
opacity: 0.6;
z-index: 1;
}
/* 卡片位置 - 当前激活 */
.hnui-swiper-cards .hnui-swiper-slide-active {
left: 50%;
transform: translateX(-50%) scale(1);
opacity: 1;
z-index: 2;
}
/* 卡片位置 - 右侧 */
.hnui-swiper-cards .hnui-swiper-slide-next {
right: 2%;
left: auto;
transform: translateX(0) scale(0.85);
opacity: 0.6;
z-index: 1;
}
/* 隐藏其他卡片 */
.hnui-swiper-cards .hnui-swiper-slide:not(.hnui-swiper-slide-prev):not(.hnui-swiper-slide-active):not(.hnui-swiper-slide-next) {
opacity: 0;
transform: scale(0.5);
}
/* === 暗色模式适配 === */
.dark .hnui-swiper {
--hnui-swiper-bg: #2c2c2c;
--hnui-swiper-arrow-bg: transparent;
--hnui-swiper-arrow-hover-bg: transparent;
--hnui-swiper-pagination-bg: rgba(255, 255, 255, 0.2);
}js
~(function () {
'use strict';
const ACTIVE_BULLET_CLASS = 'hnui-swiper-pagination-bullet-active';
const SLIDE_ACTIVE_CLASS = 'hnui-swiper-slide-active';
const SLIDE_PREV_CLASS = 'hnui-swiper-slide-prev';
const SLIDE_NEXT_CLASS = 'hnui-swiper-slide-next';
const INITIALIZED_FLAG = 'data-swiper-initialized';
/**
* 初始化轮播组件
* @param {HTMLElement} swiper - 轮播容器元素
*/
function initSwiper(swiper) {
// 防止重复初始化
if (swiper.hasAttribute(INITIALIZED_FLAG)) return;
swiper.setAttribute(INITIALIZED_FLAG, 'true');
const wrapper = swiper.querySelector('.hnui-swiper-wrapper');
const slides = swiper.querySelectorAll('.hnui-swiper-slide');
const prevBtn = swiper.querySelector('.hnui-swiper-button-prev');
const nextBtn = swiper.querySelector('.hnui-swiper-button-next');
const bullets = swiper.querySelectorAll('.hnui-swiper-pagination-bullet');
const isCardsMode = swiper.classList.contains('hnui-swiper-cards');
if (!wrapper || slides.length === 0) return;
let currentIndex = 0;
let timer = null;
const slideCount = slides.length;
// 更新轮播状态
function updateSlider() {
if (isCardsMode) {
// 卡片模式 - 更新 slide 类名
const prevIndex = currentIndex === 0 ? slideCount - 1 : currentIndex - 1;
const nextIndex = (currentIndex + 1) % slideCount;
slides.forEach((slide, index) => {
slide.classList.remove(SLIDE_ACTIVE_CLASS, SLIDE_PREV_CLASS, SLIDE_NEXT_CLASS);
if (index === currentIndex) {
slide.classList.add(SLIDE_ACTIVE_CLASS);
} else if (index === prevIndex) {
slide.classList.add(SLIDE_PREV_CLASS);
} else if (index === nextIndex) {
slide.classList.add(SLIDE_NEXT_CLASS);
}
});
} else {
// 普通模式 - 更新 transform
wrapper.style.transform = `translateX(-${currentIndex * 100}%)`;
}
// 更新分页指示器
bullets.forEach((bullet, index) => {
bullet.classList.toggle(ACTIVE_BULLET_CLASS, index === currentIndex);
});
}
// 切换到指定 slide
function goToSlide(index) {
currentIndex = index;
updateSlider();
}
// 上一张
function prevSlide() {
currentIndex = currentIndex === 0 ? slideCount - 1 : currentIndex - 1;
updateSlider();
}
// 下一张
function nextSlide() {
currentIndex = (currentIndex + 1) % slideCount;
updateSlider();
}
// 自动播放
function startAutoPlay() {
stopAutoPlay();
timer = setInterval(nextSlide, 3000);
}
function stopAutoPlay() {
if (timer) {
clearInterval(timer);
timer = null;
}
}
// 绑定事件
if (prevBtn) {
prevBtn.addEventListener('click', prevSlide);
}
if (nextBtn) {
nextBtn.addEventListener('click', nextSlide);
}
bullets.forEach((bullet, index) => {
bullet.addEventListener('click', () => goToSlide(index));
});
// 鼠标悬停暂停自动播放
swiper.addEventListener('mouseenter', stopAutoPlay);
swiper.addEventListener('mouseleave', startAutoPlay);
// 初始化状态
updateSlider();
startAutoPlay();
}
// 初始化所有未初始化的轮播组件
function initAllSwipers() {
const swipers = document.querySelectorAll('.hnui-swiper:not([' + INITIALIZED_FLAG + '])');
swipers.forEach(initSwiper);
}
// DOM 加载完成后初始化
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initAllSwipers);
} else {
initAllSwipers();
}
// 使用 MutationObserver 监听 DOM 变化,自动初始化动态添加的组件
const observer = new MutationObserver((mutations) => {
let shouldInit = false;
for (const mutation of mutations) {
if (mutation.addedNodes.length) {
shouldInit = true;
break;
}
}
if (shouldInit) {
initAllSwipers();
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
// 暴露全局方法
window.HnuiSwiper = {
init: initSwiper,
initAll: initAllSwipers
};
})();仅幻灯片 Slides Only
最基础的轮播效果,仅展示幻灯片内容,支持自动播放和鼠标悬停暂停。
查看代码
vue
<div class="hnui-swiper">
<div class="hnui-swiper-wrapper">
<div class="hnui-swiper-slide">1</div>
<div class="hnui-swiper-slide">2</div>
<div class="hnui-swiper-slide">3</div>
<div class="hnui-swiper-slide">4</div>
<div class="hnui-swiper-slide">5</div>
</div>
</div>指示器&切换箭头 条状(bars)
带有分页指示器和左右切换箭头的轮播效果,用户可以通过箭头或指示器控制切换。
查看代码
vue
<div class="hnui-swiper">
<div class="hnui-swiper-wrapper">
<div class="hnui-swiper-slide">1</div>
<div class="hnui-swiper-slide">2</div>
<div class="hnui-swiper-slide">3</div>
<div class="hnui-swiper-slide">4</div>
<div class="hnui-swiper-slide">5</div>
</div>
<!-- 切换箭头 -->
<button class="hnui-swiper-button-prev"></button>
<button class="hnui-swiper-button-next"></button>
<!-- 分页指示器 -->
<div class="hnui-swiper-pagination">
<span class="hnui-swiper-pagination-bullet hnui-swiper-pagination-bullet-active"></span>
<span class="hnui-swiper-pagination-bullet"></span>
<span class="hnui-swiper-pagination-bullet"></span>
<span class="hnui-swiper-pagination-bullet"></span>
<span class="hnui-swiper-pagination-bullet"></span>
</div>
</div>卡片式 Cards
卡片式轮播效果,当前卡片居中显示,前后卡片以缩小和半透明的形式显示,提供更好的视觉层次感。
查看代码
vue
<div class="hnui-swiper hnui-swiper-cards">
<div class="hnui-swiper-wrapper">
<div class="hnui-swiper-slide hnui-swiper-slide-prev">5</div>
<div class="hnui-swiper-slide hnui-swiper-slide-active">1</div>
<div class="hnui-swiper-slide hnui-swiper-slide-next">2</div>
<div class="hnui-swiper-slide">3</div>
<div class="hnui-swiper-slide">4</div>
</div>
<!-- 切换箭头 -->
<button class="hnui-swiper-button-prev"></button>
<button class="hnui-swiper-button-next"></button>
<!-- 分页指示器 -->
<div class="hnui-swiper-pagination">
<span class="hnui-swiper-pagination-bullet hnui-swiper-pagination-bullet-active"></span>
<span class="hnui-swiper-pagination-bullet"></span>
<span class="hnui-swiper-pagination-bullet"></span>
<span class="hnui-swiper-pagination-bullet"></span>
<span class="hnui-swiper-pagination-bullet"></span>
</div>
</div>