有一点点酷的swiper

原生js开发一个swiper

前言

最近没啥事儿干,想着在公司闲着也是闲着,写个轮播图来玩玩儿吧,还没手写过呢,想法有了,再来想想思路,嗯......有几张图片,要知道当前浏览的是哪一个,相邻的之间有个大小透明的差异化,再来两个切换按钮,嗯......就很ok啦,开撸!!!

先看效果图

一个可以左右切换,点击图片切换的轮播图

准备

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>轮播图</title>
    <link rel="stylesheet" href="./index.css" />
  </head>
  <body>
    <div class="swiper-wrap">
      <div class="prev">
        <img src="./image/方向-左-双线.png" alt="" />
      </div>
      <div class="swiper-content">
        <div class="swiper-item">
          <span style="position: absolute; top: 50px; left: 50px">
            index:0
          </span>
          <img src="./image/1.png" alt="" />
        </div>
        <div class="swiper-item">
          <span style="position: absolute; top: 50px; left: 50px">
            index:1
          </span>
          <img src="./image/3.png" alt="" />
        </div>
        <div class="swiper-item">
          <span style="position: absolute; top: 50px; left: 50px">
            index:2
          </span>
          <img src="./image/2.png" alt="" />
        </div>
        <div class="swiper-item">
          <span style="position: absolute; top: 50px; left: 50px">
            index:3
          </span>
          <img src="./image/4.png" alt="" />
        </div>
        <div class="swiper-item">
          <span style="position: absolute; top: 50px; left: 50px">
            index:4
          </span>
          <img src="./image/5.png" alt="" />
        </div>
        <div class="swiper-item">
          <span style="position: absolute; top: 50px; left: 50px">
            index:5
          </span>
          <img src="./image/6.png" alt="" />
        </div>
        <div class="swiper-item">
          <span style="position: absolute; top: 50px; left: 50px">
            index:6
          </span>
          <img src="./image/7.png" alt="" />
        </div>
        <div class="swiper-item">
          <span style="position: absolute; top: 50px; left: 50px">
            index:7
          </span>
          <img src="./image/8.png" alt="" />
        </div>
      </div>
      <div class="next">
        <img src="./image/方向-右-双线.png" alt="" />
      </div>
    </div>
    <script src="./index.js"></script>
  </body>
</html>
css 复制代码
body {
  background: rgba(0, 0, 0, 0.7);
}
.swiper-wrap {
  position: relative;
  width: 1000px;
  height: 500px;
}
.swiper-wrap .prev,
.swiper-wrap .next {
  position: absolute;
  width: 50px;
  height: 50px;
  cursor: pointer;
  z-index: 999;
  opacity: 0.5;
}

.swiper-wrap .prev:hover,
.swiper-wrap .next:hover {
  opacity: 1;
}

.swiper-wrap .prev img,
.swiper-wrap .next img {
  width: 100%;
  height: 100%;
}

.swiper-wrap .prev {
  top: 50%;
  left: 20px;
  transform: translateY(-50%);
}

.swiper-wrap .next {
  top: 50%;
  right: 20px;
  transform: translateY(-50%);
}

.swiper-wrap .swiper-content {
  perspective: 1000px;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.swiper-wrap .swiper-content .swiper-item {
  position: absolute;
  transition: all 0.33s;
}

.swiper-wrap .swiper-content .swiper-item img {
  width: 400px;
  height: 300px;
}

js核心逻辑

具体的逻辑实现我在注释中已基本说明,主要就是用transform来改变元素的位置,在加点动画,就完事儿。

js 复制代码
// 获取按钮每一张轮播图
const swiperItems = document.querySelectorAll('.swiper-item')

// 获取按钮
const prev = document.querySelector('.prev')
const next = document.querySelector('.next')

// 当前显示的索引号
let index = 3

// 布局
const layout = () => {
    let xStep = 100  // 水平方向的边偏移
    const scaleStep = 0.6  // 缩放的倍数
    const opacitytep = 0.4 // 透明度的倍数
    const len = swiperItems.length // 轮播图数据的长度

    for (let i = 0; i < swiperItems.length; i++) {
        const item = swiperItems[i]
        const diff = i - index // 计算在显示元素的左边或右边的第几个身位
        const sign = Math.sign(diff) // 取正负值 返回 -1 或 1

        let offsetX = xStep * diff // 计算与当前显示元素的边偏移

        if (i !== index) {
            // 这里是为了兼容边偏移距离过近或者过远的补偿,如果倍数与尺寸设计的好,也可以不必这样写,可以直接使用
            offsetX = offsetX + 100 * sign
        }

        // 计算rotate沿y轴的旋转角度,如果是当前显示的则不旋转,旋转45度
        // sign为负数则逆时针,为正数则顺时针 
        // 注意:记得在样式加入perspective属性,好久没写3d了,上了它的鬼日当,不然没有视距差异
        const rotate = i === index ? 0 : 45 * (-sign)

        // 计算缩放大小,这里一定要取绝对值,不然就是放大了,详细见图形分解
        const scale = Math.pow(scaleStep, Math.abs(diff))

        item.style.transform = `translateX(${offsetX}px) scale(${scale}) rotateY(${rotate}deg)`

        // zIndex的计算与scale同理,可以用任何数值来计算,len可以等于1000,也可以100,主要还是看有没有其他元素层级的影响
        item.style.zIndex = len - Math.abs(diff)

        // opacity的计算也与scale同理
        const opacity = Math.pow(opacitytep, Math.abs(diff))
        item.style.opacity = opacity
    }
}

// 初始化布局
layout()

// 事件处理,不过多赘述
for (let i = 0; i < swiperItems.length; i++) {
    const item = swiperItems[i]
    item.addEventListener('click', function () {
        index = i
        layout()
    })
}

prev.addEventListener('click', function () {
    index--
    if (index < 0) {
        index = swiperItems.length - 1
    }
    layout()
})

next.addEventListener('click', function () {
    index++
    if (index >= swiperItems.length) {
        index = 0
    }
    layout()
})

这里主要就是运用了数学的幂次方算法,偏移几个身位,就是多少次方,计算两个相邻的元素的大小,及透明图的变化

计算大小的逻辑实现,图解:

结尾

是不是很简单!!!

别人问我为啥我这个不可以滑动切换,别问,问就是还没想好怎么写,等我想好了再加进来!!!

相关推荐
FungLeo5 小时前
成为全栈·React 管理后台篇·总复盘:从“接口能调通”到“后台值得使用”
前端·react.js·前端框架·项目复盘·成为全栈
Csvn6 小时前
并发模式:让渲染学会排队、插队和让路
前端
可乐鸡翅yeah_7 小时前
新手梳理:M3U8 线上问题,哪些是前端锅,哪些是后端锅
前端·ios·音视频·实时音视频·m3u8·音视频在线播放
Flynt7 小时前
Linear 用 1000 个 PR 换掉 styled-components,我写了 200 个按钮,把这笔账复现了一遍
前端·css·preact
JavaGuide8 小时前
NVIDIA 又开源了!这次给 AI Agent 加上权限管控
前端·后端
excel8 小时前
prisma 如何处理数据库竞态
前端·数据库·后端
莪_幻尘9 小时前
Skill 体检:30 个 Skill 全凭感觉?体检器先自曝了 8 个“假 0 分
前端·人工智能·llm
风骏时光牛马9 小时前
AI模型综合能力评测:性能、指令遵循与多场景实测对比
前端
Frag0ut9 小时前
Chrome与Chromium内核浏览器在Windows 11上的新特性全景解析
前端·chrome·windows·web安全·chromium·gemini ai·playready drm
hiahiahia12310 小时前
实现完整 Tool Dispatcher
开发语言·前端