原生实现

# 原生实现

# 需求分析

  1. 自动播放

  2. 鼠标无缝切换

# 设计方案

方案 1:在末尾克隆第 1 张

方案 2:操作 DOM 节点

自动播放没什么好说的,主要是第 1 张和最后 1 张的无缝切换,所以主要讲的是无缝切换的思路。方案 1 克隆 DOM 的操作我们认为不够优雅,并且方案 2 也更加适配虚拟 DOM 的 diff 算法,故我们选取方案 2,但其与方案 1 思想类似,懂一个就都会了。话不多说,直接看图好吧,看不懂打我。(图中紫色的虚线是我们人眼看不到的流程,黄色实线是我们可以看到的)

下一张整体移动流程:

next-total

下一张的单步处理流程:

next-detail

上一张整体移动流程:

pre-total

上一张的单步处理流程:

pre-detail

# 源码

  • html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <div id="container">
      <ul id="banner">
        <li><img src="./image/1.jpg" alt="1" /></li>
        <li><img src="./image/2.jpg" alt="2" /></li>
        <li><img src="./image/3.jpg" alt="3" /></li>
        <li><img src="./image/4.jpg" alt="4" /></li>
        <li><img src="./image/5.jpg" alt="5" /></li>
      </ul>
      <div id="pre"></div>
      <div id="next"></div>
    </div>
    <script src="main.js"></script>
  </body>
</html>
* {
  padding: 0px;
  margin: 0px;
  box-sizing: border-box;
}

body {
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  overflow: hidden;
  background-color: rgb(119, 115, 110);
}

#container {
  width: 400px;
  height: 200px;
  position: relative;
  overflow: hidden;
}

#container:hover {
  cursor: pointer;
}

ul {
  width: 500%;
  height: 100%;
  display: flex;
  list-style: none;
  transition: 0.4s;
}

li {
  width: 20%;
  height: 100%;
}

ul li img {
  width: 100%;
}

#pre {
  width: 30px;
  height: 50px;
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  background: url(./image/preImg.png) no-repeat center;
}

#next {
  width: 30px;
  height: 50px;
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  background: url(./image/nexImg.png) no-repeat center;
}
const ul = document.querySelector("ul");
const liList = document.querySelectorAll("li");
const btnNext = document.getElementById("next");
const btnPre = document.getElementById("pre");

var timer, firstLi, lastLi;

const next = () => {
  firstLi = document.querySelector("li");
  ul.style.transition = "0.4s";
  ul.style.transform = `translateX(${-20}%)`;
  setTimeout(() => {
    ul.appendChild(firstLi);
    ul.style.transition = "none";
    ul.style.transform = `translateX(0%)`;
  }, 400);
};

const pre = () => {
  firstLi = document.querySelector("li");
  lastLi = document.querySelector("li:last-child");
  ul.insertBefore(lastLi, firstLi);
  ul.style.transition = "none";
  ul.style.transform = `translateX(${-20}%)`;
  setTimeout(() => {
    ul.style.transition = "0.4s";
    ul.style.transform = `translateX(0%)`;
  }, 0);
};

function animation() {
  timer = setInterval(next, 2000);
}

function getNext() {
  clearInterval(timer);
  next();
  animation();
}

function getPre() {
  clearInterval(timer);
  pre();
  animation();
}

animation();

ul.onmouseenter = function () {
  clearInterval(timer);
};

ul.onmouseleave = function () {
  animation();
};

btnNext.onclick = function () {
  getNext();
};

btnPre.onclick = function () {
  getPre();
};

window.onclose = function () {
  clearInterval(timer);
};

# 组件封装

正在实现 React 封装,敬请期待 lamb-design...