Детали карусели, которых вы не знаете~

JavaScript
Детали карусели, которых вы не знаете~

Дело вот в чем, студент два дня назад спросил у меня принцип бесшовной прокрутки карусельных картинок, и сказал, что я привык пользоваться фреймворком, но сам не смогу.
В то время я очень рассердился, когда услышал это Вы привыкли к этому.
Например, когда я изучал интерфейс, карусель была первым спецэффектом, с которого нужно было начать, тогда были только jq, вкладка карусель и т. Д. Все это были базовые навыки.
Теперь все привыкают к тому, что их беспокоят различные фреймворки? Не можете написать код, не выходя из фреймворка?Программирование для API?

Давай, открой его, или что еще ты можешь сделать?

Давайте посмотрим, что такое бесшовная прокрутка:

Похоже, что изображений всего четыре, но независимо от того, перетаскиваете ли вы их вперед или назад, вы можете перетаскивать их бесконечно. Это похоже на бесконечный цикл из четырех изображений. Этот эффект является одним из наиболее распространенных интерактивных эффектов на странице. Прошло 1202 года, а базовые навыки должны быть крепкими~

На самом деле основной принцип реализации очень прост

Первый шаг — сделать копию картинки, четыре на восемь.

Если количество фотографий больше, вы можете сделать другие планы, не имеет значения, если у вас есть несколько фотографий.
Если это десятки картинок, то сразу сделайте 3D-кольцо или это предложение, самое главное, чтобы было решение.

Эту картинку следует понимать так: в момент нажатия мышки сначала посмотреть, какая картинка отображается в данный момент, если это 0-я картинка, подстроить общее положение под 0-ю картинку второй группы в момент нажатие Go, вторая группа является скопированной группой, поэтому нет проблем, перетаскивается ли она влево или вправо

Затем, если текущий дисплей является последним изображением второй группы, в момент нажатия мыши непосредственно отрегулируйте общее положение до последнего изображения первой группы, чтобы его можно было перетаскивать влево и вправо. , Посмотрите на схему:

Заблокируйте другие изображения и сосредоточьтесь только на том, что показано посередине, и вы увидите плавную прокрутку:

Если вы хотите увидеть код, продолжайте оглядываться назад.Количество кода на самом деле очень мало, и это всего более 100 строк вместе с CSS, так что это совсем не сложно, и основное внимание по-прежнему уделяется принципу .

вот структура

<div class="wrap">
    <ul class="list"><!--这里是图片列表-->
        <li class="item"><img src="img/img01.png"></li>
        <li class="item"><img src="img/img02.png"></li>
        <li class="item"><img src="img/img03.png"></li>
        <li class="item"><img src="img/img04.png"></li>
    </ul>
    <ul class="dot"><!--这里是下面的小点-->
        <li class="active"></li>
        <li></li>
        <li></li>
        <li></li>
    </ul>
</div>

Видно, что в исходном списке всего четыре картинки, после непосредственного получения списка можно получить восемь картинок, скопировав содержимое один раз.

Второй шаг — получить элемент и установить переменную

  let wrap = document.querySelector('.wrap');//获取外框,以便设置图片滚动的宽度
  let list = wrap.querySelector('.list');//图片列表
  let dot = wrap.querySelectorAll('.dot li');//小点
  
  let startpoint = {};//鼠标按下的起始点
  let distaince = {};//移动的距离
  
  list.innerHTML += list.innerHTML;//复制图片列表

На самом деле тут и говорить нечего.Написать взаимодействие с нативом это не что иное,как получить элементы и потом добавить элементы операции события,так что дальше будете знать что делать.Вот пишу мобильную версию,поэтому использую touch event

Третий шаг, добавить события

  wrap.addEventListener('touchstart',(ev)=>{//手指按下
      let touch = ev.changedTouches[0];
      startpoint = {//这里记录手指按下的位置
          x:touch.pageX,
          y:touch.pageY
      }
  })
  //在手指按下的时候要做的事情其实很简单,只需要记录手指按下的位置就好了,先让图片能拖动,之后再考虑无缝滚动的事情
  
  wrap.addEventListener('touchmove',(ev)=>{//手指移动
      let touch = ev.changedTouches[0];
      distaince = {//移动的时候计算出移动了多少距离
          x:touch.pageX - startpoint.x,
          y:touch.pageY - startpoint.y
      }

      translatex = startOffset + distaince.x;
      list.style.transform = `translateX(${translatex}px)`;//把计算出来的移动距离附加给图片列表
  })
  //到这一步,图片就已经可以被拖动了

Здесь реализовано, что картинку можно перетаскивать, далее определяется когда переходить на следующую.

Здесь, если у вас не слишком много исследований, вы можете принять решение с оплеухой, но если вы хотите сосредоточиться на пользовательском опыте, то слушайте меня и используйте соотношение для контроля. Например:当图片被拖动的距离超过外框的30%,那么这时候松开手会自动切换到下一张或者上一张, поэтому на данный момент нам нужна переменная для управления этим соотношением, чтобы мы могли многократно его корректировать.

Поэтому, когда палец поднят, следует сделать ряд суждений:

  let now = 0;//当前在那一张
  let imgW = wrap.offsetWidth;//获取一下外框的宽度
  let proportion = 0.3;//当图片拖动超过整体宽度的比例时,跳转到下一张或者上一张
  
  wrap.addEventListener('touchend',()=>{//手指抬起
      if(Math.abs(distaince.x) > imgW * proportion){//这里判断什么时候切换
          now -= distaince.x/Math.abs(distaince.x);//这里判断是切换上一张还是下一张
      }

      translatex = now * -imgW; //判断好了之后计算图片列表需要移动的距离
      list.style.transition = '0.3s';
      list.style.transform = `translateX(${translatex}px)`;
  })

В этот момент мы уже можем перетаскивать картинку, а затем переключать предыдущую на следующую. Но если вы хотите быть бесшовным, вам все равно нужно делать дальнейшие операции, это сказано в принципиальном анализе, вы можете еще раз посмотреть на эту схему принципиального анализа:

Видно, что когда вы нажимаете вниз, если изображение находится на первом изображении, то мгновенно переходите к первому изображению второй группы, поэтому, перетаскиваете ли вы влево или вправо, есть изображения. код:

wrap.addEventListener('touchstart',(ev)=>{
        let touch = ev.changedTouches[0];
        startpoint = {
            x:touch.pageX,
            y:touch.pageY
        }

        if(now == 0){//如果当前是第0张,则直接跳转到第二组的第0张
            now = dot.length;
        }else if(now == dot.length*2 -1){//如果是最后一张,则跳转到第一组的最后一张
            now = dot.length -1;
        }

        translatex = now * -imgW;//计算好之后再挪动图片列表
        startOffset = translatex;
        list.style.transition = 'none';
        list.style.transform = `translateX(${translatex}px)`;
    })

На данный момент с бесшовной прокруткой проблем нет, давайте посмотрим на полный код:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <style>
        body{
            margin: 0;
            background: #fefefe;
        }
        .wrap{
            width: 100vw;
            overflow: hidden;
            box-shadow: 0 0 5px 0 rgba(0,0,0,0.1);
            position: relative;
            background: #000;
        }
        ul{
            margin: 0;
            padding: 0;
            list-style: none;
        }
        .list{
            display: flex;
            float: left;
        }
        .list img{
            width: 100vw;
            vertical-align: top;
            filter: saturate(2);
        }

        .dot{
            width: 100vw;
            display: flex;
            justify-content: center;
            position: absolute;
            bottom: 20px;
        }
        .dot li{
            width: 10px;
            height: 10px;
            border-radius: 10px;
            background: #fff;
            margin: 0 5px;
            transition: 0.2s;
            box-shadow: 0 0 3px 0 rgba(0,0,0,0.3);
        }

        .dot li.active{
            width: 20px;
        }
    </style>
</head>
<body>

<div class="wrap">
    <ul class="list"><!--这里是图片列表-->
        <li class="item"><img src="img/img01.png"></li>
        <li class="item"><img src="img/img02.png"></li>
        <li class="item"><img src="img/img03.png"></li>
        <li class="item"><img src="img/img04.png"></li>
    </ul>
    <ul class="dot"><!--这里是下面的小点-->
        <li class="active"></li>
        <li></li>
        <li></li>
        <li></li>
    </ul>
</div>

<script>
{
    let wrap = document.querySelector('.wrap');//获取外框,以便设置图片滚动的宽度
    let list = wrap.querySelector('.list');//图片列表
    let dot = wrap.querySelectorAll('.dot li');//小点

    let startpoint = {};//鼠标按下的起始点
    let distaince = {};//距离
    let startOffset = 0;//记录鼠标按下时图片列表的位置
    let translatex = 0;//移动的距离
    let now = 0;//当前在那一张
    let imgW = wrap.offsetWidth;//获取一下外框的宽度
    let proportion = 0.3;//当图片拖动超过整体宽度的比例时,跳转到下一张或者上一章
    let isMove = false;
    list.innerHTML += list.innerHTML;//复制图片列表

    wrap.addEventListener('touchstart',(ev)=>{
        let touch = ev.changedTouches[0];
        startpoint = {
            x:touch.pageX,
            y:touch.pageY
        }

        if(now == 0){
            now = dot.length;
        }else if(now == dot.length*2 -1){
            now = dot.length -1;
        }

        translatex = now * -imgW;
        startOffset = translatex;
        list.style.transition = 'none';
        list.style.transform = `translateX(${translatex}px)`;
    })

    wrap.addEventListener('touchmove',(ev)=>{
        let touch = ev.changedTouches[0];
        distaince = {
            x:touch.pageX - startpoint.x,
            y:touch.pageY - startpoint.y
        }

        if(Math.abs(distaince.x) - Math.abs(distaince.y) > 5){
            isMove = true;
            ev.preventDefault();
        }else if(Math.abs(distaince.x) - Math.abs(distaince.y) < 5){
            isMove = false;
        }

        if(isMove){
            translatex = startOffset + distaince.x;
            list.style.transform = `translateX(${translatex}px)`;
        }
    })

    wrap.addEventListener('touchend',()=>{
        if(Math.abs(distaince.x) > imgW * proportion){
            now -= distaince.x/Math.abs(distaince.x);
        }
        Array.from(dot).forEach((item,index)=>{
            item.classList.remove('active');
            if(index === (now%dot.length)){
                item.classList.add('active');
            }
        });

        if(isMove){
            translatex = now * -imgW;
            list.style.transition = '0.3s';
            list.style.transform = `translateX(${translatex}px)`;
        }
    })
}
</script>

</body>
</html>

глазурь на торте

Логически говоря, код почти написан здесь, но я все еще хочу добавить событие клика на маленькую кнопку, и по нажатию маленькой кнопки переходить к соответствующей картинке:

  Array.from(dot).forEach((item,index)=>{
      item.onclick = function(ev){
          Array.from(dot).forEach((item)=>{
              item.classList.remove('active');
          })

          now = index;
          this.classList.add('active');
          translatex = now * -imgW;
          list.style.transition = '0.3s';
          list.style.transform = `translateX(${translatex}px)`;
          ev.preventDefault();
      }
  })

В этом коде не о чем говорить, но затем происходит волшебство:

Понятно? Принципы все общие, если понял ставь лайк...
Если вы хотите узнать о слайд-шоу 3D-кольца, о котором я говорил в начале, см. раздел комментариев...


  • это мыКоманда Хуагошаньпроект с открытым исходным кодомelement3Добро пожаловать, чтобы попробовать и звезду
  • Библиотека компонентов внешнего интерфейса, поддерживающая vue3.