如何使元素切换或跟随中心滚动?

时间:2019-04-30 07:39:12

标签: javascript jquery html css

我想做什么

like this

就像这样,最初是切换滚动条。
当前(活动)元素到达中心时,下一个元素也希望能够在中心滚动。

this

当看到底部元素时,滚动停止,并切换为开关滚动。


当前状态

我已经有一个滚动条和一个获取中心的代码。
demo - JSFiddle

开关滚动(元素切换)的代码:ㅤ*我想在此代码上构建

$(function() {
  var that;
  var i = 0;
  var j = $(".main-p > p").length - 1;
  $('.mai').bind('mousewheel', function(e) {
    if (e.originalEvent.wheelDelta < 0) {
      // scroll down
      i++;
      if (i >= j) {
        i = j;
      }
      if (i <= j) {
        $(".main-p > p").each(function(i) {
          if ($(this).hasClass('active')) {
            if ($(this).hasClass(i)) {
              if (i < j) {
                that = $(this).next();
              } else {
                that = $(this);
              }
            }
          }
          $(this).removeClass('active');
        });
        $(that).addClass('active');
      }
    } else {
      // scroll up
      i--;
      if (i <= 0) {
        i = 0;
      }
      if (i >= 0) {
        $(".main-p > p").each(function(i) {
          if ($(this).hasClass('active')) {
            if (i > 0) {
              that = $(this).prev();
            } else {
              that = $(this);
            }
          }
          $(this).removeClass('active');
        });
        $(that).addClass('active');
      }
    }
    swiperCnt.slideTo(i);
    // cancel page scrolling
    return false;
  });
  swiperCnt.on('scroll', function() {
    onScroll();
  });
  swiperCnt.on('paginationUpdate', function() {
    onScroll();
  });
  onScroll();
});

function onScroll() {
  $(".main-p > p").each(function(i) {
    $(this).removeClass('active');

    if ($(this).attr('class').includes(i) && i === swiperCnt.activeIndex) {
      $(this).addClass('active');
    }


    /* center of .main-p */
    const rect = document.getElementsByClassName('main-p')[0].getBoundingClientRect();
    const mpHCnt = rect.top + (rect.height / 2);
    const mpWCnt = rect.left + (rect.width / 2);

    // get the element in the center of .main-p
    const cntElm = document.elementFromPoint(mpWCnt, mpHCnt);

    if ($("p.active") === cntElm) {
      $('.mai').scroll().css('top',mpHCnt + 'px');
      // It's on the way..

    } else {
      $('.mai').scroll(function(e) {
        e.preventDefault();
      });
    }
  });
}

我之前问过这个问题。 here - StackOverflow
他给了我一个很好的答案,但是我必须指定元素的高度,依此类推,所以毕竟没有用。

在中心滚动的代码:

let wrapper = document.querySelector('.wrapper');
let items = document.querySelector('.items');
let itemAll = document.querySelectorAll('.item');
const wrapperCenter = centerXY(wrapper);
let current = 0;
itemAll[current].classList.add('active');
let dir = 1;
let tick = false;
let count = 0;
let distance;
let step = 1;


items.style.top = 0 + 'px'
wrapper.addEventListener('mousewheel', e => {
  // if we are in moving animation, return
  if (tick) return;

  // scroll direction: down: 1, up -1
  dir = e.wheelDelta < 0 ? 1 : -1;

  // if the next highlight element index is exceeded, return
  if ((current + dir) === -1 || (current + dir) === itemAll.length) return;
  // cancel current highlight
  itemAll[current].classList.remove('active');
  // find next hightlight index
  current += dir;
  itemAll[current].classList.add('active');
  // get current highlight element center to compute how long we need to scroll
  let currentCenter = centerXY(itemAll[current]);
  // the distance is negative when scrolling up
  distance = currentCenter.y - wrapperCenter.y;

  // when scrolling down, if current element is above the center, no need to move list
  // e.g. scrolling from element A to B
  if (dir > 0 && distance < 0) {
    return;
  }
  // when scrolling up, if current element is below the center, no need to move list
  // e.g. scrolling from G to F
  if (dir < 0 && distance > 0) {
    return;
  }

  // If the last element is in view , stop scrolling down
  if ((dir > 0 && isInViewBottom(wrapper, itemAll[itemAll.length - 1]))) {
    return;
  }

  // If the first element is in view , stop scrolling up
  if ((dir < 0 && isInViewTop(wrapper, itemAll[0]))) {
    return;
  }

  // stop response the event to handle current moving
  tick = true;

  requestAnimationFrame(moveList);
})


function moveList() {
  if (count != Math.floor(Math.abs(distance) / step)) {
    count += 1;
    items.style.top = parseInt(items.style.top.slice(0, -2)) - step * dir + 'px';
    requestAnimationFrame(moveList);
  } else {
    count = 0;
    dir = 0;
    // back to response scrolling
    tick = false;
  }
}

// compute coordinate of an element horizontal center
function centerXY (dom) {
  let r = dom.getBoundingClientRect();
  return {
    x: r.x,
    y: r.height / 2 + r.top
  }
}


function isInViewBottom(container, dom) {
  return container.getBoundingClientRect().bottom >= dom.getBoundingClientRect().bottom;
}

function isInViewTop(container, dom) {
  return container.getBoundingClientRect().top <= dom.getBoundingClientRect().top;
}

我尝试过的

您可以稍微滚动一下以查看我的更改位置。

$(function() {
  var that;
  var i = 0;
  var j = $(".main-p > p").length - 1;
  $('.mai').bind('mousewheel', function(e) {
    if (e.originalEvent.wheelDelta < 0) {
      // scroll down
      i++;
      if (i >= j) {
        i = j;
      }
      if (i <= j) {
        $(".main-p > p").each(function(i) {
          if ($(this).hasClass('active')) {
            if ($(this).hasClass(i)) {
              if (i < j) {
                that = $(this).next();
              } else {
                that = $(this);
              }
            }
          }
          $(this).removeClass('active');
        });
        $(that).addClass('active');
      }
    } else {
      // scroll up
      i--;
      if (i <= 0) {
        i = 0;
      }
      if (i >= 0) {
        $(".main-p > p").each(function(i) {
          if ($(this).hasClass('active')) {
            if (i > 0) {
              that = $(this).prev();
            } else {
              that = $(this);
            }
          }
          $(this).removeClass('active');
        });
        $(that).addClass('active');
      }
    }
    swiperCnt.slideTo(i);
    // cancel page scrolling
    return false;
  });
  swiperCnt.on('scroll', function() {
    onScroll();
  });
  swiperCnt.on('paginationUpdate', function() {
    onScroll();
  });
  onScroll();
});


/* from here */
let itemAll = document.querySelectorAll('.main-p > p');
let current = 0;
itemAll[current].classList.add('active');
let dir = 1;
let tick = false;
let count = 0;
let distance;
let step = 4;   // scroll speed

function onScroll() {
  $(".main-p > p").each(function(i) {
    $(this).removeClass('active');

    if ($(this).attr('class').includes(i) && i === swiperCnt.activeIndex) {
      $(this).addClass('active');
    }


        const rect = document.getElementsByClassName('main-p')[0].getBoundingClientRect();
        const mpHCnt = rect.top + (rect.height / 2);
        let currentIs = centerXY(itemAll[current]);
        let distance = currentIs.y - mpHCnt;

        // when scrolling down, if current element is above the center, no need to move list
        // e.g. scrolling from element A to B
        if (dir > 0 && distance < 0) {
            return;
        }
        // when scrolling up, if current element is below the center, no need to move list
        // e.g. scrolling from G to F
        if (dir < 0 && distance > 0) {
            return;
        }

        // If the last element is in view , stop scrolling down
        if ((dir > 0 && isInViewBottom(wrap, itemAll[itemAll.length - 1]))) {
            return;
        }

        // If the first element is in view , stop scrolling up
        if ((dir < 0 && isInViewTop(wrap, itemAll[0]))) {
            return;
        }

        // stop response the event to handle current moving
        tick = true;

        requestAnimationFrame(moveList);
  });
}
/* to here */

function moveList() {
    if (count != Math.floor(Math.abs(distance) / step)) {
        count += 1;
        items.style.top = parseInt(items.style.top.slice(0, -2)) - step * dir + 'px';
        requestAnimationFrame(moveList);
    } else {
        count = 0;
        dir = 0;
        // back to response scrolling
        tick = false;
    }
}

// compute coordinate of an element horizontal center
function centerXY(dom) {
    let r = dom.getBoundingClientRect();
    return {
        x: r.x,
        y: r.height / 2 + r.top
    }
}


function isInViewBottom(container, dom) {
    return container.getBoundingClientRect().bottom >= dom.getBoundingClientRect().bottom;
}

function isInViewTop(container, dom) {
    return container.getBoundingClientRect().top <= dom.getBoundingClientRect().top;
}

此代码无效。

我想将这两个想法很好地结合起来,并且像GIF一样运作良好。
有人可以帮我吗?先感谢您。


代码

function onScroll() {
  $(".main > p").each(function(i) {
    $(this).removeClass('active');

    if ($(this).attr('class').includes(i) && i === swiperCnt.activeIndex) {
      $(this).addClass('active');
    }

/* from here */
// Get the center of the height of .main
    const rect = document.getElementsByClassName("main")[0].getBoundingClientRect();
    const mainHCenter = rect.top + (rect.height / 2);
    const mainWCenter = rect.left + (rect.width / 2);
    
// Get the element at the center of the height of .main
    const centerElm = document.elementFromPoint(mainWCenter, mainHCenter);
    
    if ($("p.active") === centerElm) {
          $(".mai").scroll().css('top',mainHCenter + 'px');
    } else {
      $(".mai").scroll(function(e) {
        e.preventDefault();
      });
    }
/* to here */

  });
}



/* swiper (doesn't matter) */
var swiperCnt = new Swiper('.swiperCnt', {
  direction: 'vertical',
  autoHeight: true,
  pagination: {
    el: '.swiper-pagination',
    type: 'bullets',
    clickable: 'true',
  },
  keyboard: {
    enabled: true,
  },
  mousewheel: {
    forceToAxis: true,
    invert: true,
  },
  renderBullet: function(index, className) {
    return '<span class="' + className + '">' + (index + 1) + '</span>';
  },
});


$(function() {
  var that;
  var i = 0;
  var j = $(".main > p").length - 1;
  $('.mai').bind('mousewheel', function(e) {
    if (e.originalEvent.wheelDelta < 0) {
      //scroll down
      i++;
      if (i >= j) {
        i = j;
      }
      if (i <= j) {
        $(".main > p").each(function(i) {
          if ($(this).hasClass('active')) {
            if ($(this).hasClass(i)) {
              if (i < j) {
                that = $(this).next();
              } else {
                that = $(this);
              }
            }
          }
          $(this).removeClass('active');
        });
        $(that).addClass('active');
      }
    } else {
      //scroll up
      i--;
      if (i <= 0) {
        i = 0;
      }
      if (i >= 0) {
        $(".main > p").each(function(i) {
          if ($(this).hasClass('active')) {
            if (i > 0) {
              that = $(this).prev();
            } else {
              that = $(this);
            }
          }
          $(this).removeClass('active');
        });
        $(that).addClass('active');
      }
    }
    swiperCnt.slideTo(i);
    //prevent page from scrolling
    return false;
  });
  swiperCnt.on('scroll', function() {
    onScroll();
  });
  swiperCnt.on('paginationUpdate', function() {
    onScroll();
  });
  onScroll();
});
/* The corresponding part is at the bottom too. (It is faster to count from the bottom)
(There is a mark in the comment) */


html {
  font-size: 62.5%;
  height: 100%;
}

body {
  font-size: 1.5rem;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  background-color: #c6d2dd;
  color: white;
}

#wrap {
  display: flex;
  width: 100%;
  height: 100vh;
  padding: 1.8rem 4.7rem 2.7rem 2.4rem;
}

h2, h3, h4, h5, h6 {
  display: inline;
}

.mission, .m-p, .concept, .c-p, .what, .target, .t-p, .main-p, .nb, .nb-p, .period, .p-p, .category, .cg-p, .class, .cl-p, .release, .r-p, .nbb, .per, .cat, .cla, .rel {
  display: inline-block;
}

#left, #right {
  display: flex;
  flex-direction: column;
  height: 100%;
  max-height: 100%;
}

#left {
  width: 57%;
}

#right {
  position: relative;
  width: 43%;
  padding-left: 6.5rem;
}

.title {
  height: 3.55rem;
  font-size: 1.8rem;
  padding-bottom: 1.7rem;
}

.solid-ti {
  position: absolute;
  width: 100%;
  border-top: 0.1rem solid white;
  margin-top: 5.35rem;
}

.solid-mc {
  border-bottom: 0.1rem solid white;
  margin-left: -2.4rem;
}

.solid-tm {
  border-bottom: 0.1rem solid white;
  margin-right: -4.7rem;
}

.swiper-pagination {
  top: 6rem;
}

.max {
  position: relative;
  width: 100%;
  flex: 1;
}

.max-inner {
  position: absolute;
  width: 100%;
  height: 100%;
}

.swiper-slide {
  display: flex;
  align-items: center;
}
.swiper-slide img {
  width: 100%;
}

.swiperP {
  height: auto;
}

.swiper-pagination-bullet {
  background: none;
  font-size: 1rem;
  margin-right: 0.5rem;
  opacity: 0.3;
}
.swiper-pagination-bullet::before {
  content: "0";
  font-weight: bold;
}
.swiper-pagination-bullet:hover::before {
  content: "1";
  font-weight: bold;
}

.swiper-pagination-bullet-active {
  background: none;
  transform: scale(1);
  transition-duration: 0.16s;
  opacity: 0.7;
}
.swiper-pagination-bullet-active::before {
  content: "1";
  font-weight: bold;
}

.mis {
  padding: 2.6rem 0 0.7rem 0;
}

.mission {
  padding-right: 2rem;
}

.con {
  padding-top: 0.7rem;
}

.concept {
  padding-right: 2rem;
}

.what {
  margin: 2rem 1.5rem 0 0;
  display: flex;
  align-items: center;
}
.what > img {
  height: 2rem;
  margin-right: 0.3rem;
}
.what > img:last-child {
  margin-right: 1rem;
}
.what span {
  font-size: 1.4rem;
  border: 0.1rem solid white;
  border-radius: 0.3rem;
  margin-right: 1rem;
  padding: 0.5rem 0.4rem 0.4rem;
}

.tar {
  padding: 2.2rem 0 2rem 0;
  flex-grow: 1;
}

.target {
  padding-right: 1.2rem;
}

.t-p {
  vertical-align: top;
}

.heartbox {
  display: flex;
  align-items: center;
}
.heartbox div:last-child {
  user-select: none;
}

input {
  opacity: 0;
}

@keyframes rubberBand {
  from {
    transform: scale(1, 1, 1);
  }
  30% {
    transform: scale3d(1.15, 0.75, 1);
  }
  40% {
    transform: scale3d(0.75, 1.15, 1);
  }
  50% {
    transform: scale3d(1.1, 0.85, 1);
  }
  65% {
    transform: scale3d(0.95, 1.05, 1);
  }
  75% {
    transform: scale3d(1.05, 0.95, 1);
  }
  to {
    transform: scale3d(1, 1, 1);
  }
}
.heart {
  cursor: pointer;
  width: auto;
  height: 25px;
  fill: #E2E2E2;
}

#fav:checked + label .heart {
  fill: #e23b3b;
  animation: rubberBand 0.8s;
}





/*
 * from here
 */
.mai {
  margin: 2.8rem 0 0 0;
  height: 37.8rem;
  overflow-y: scroll;
  overflow-x: hidden;
  -ms-overflow-style: none;
}
.mai::-webkit-scrollbar {
  display: none;
}

.main p {
  opacity: 0.3;
}
.main .active {
  opacity: 1;
}

/*
 * to here
 */





.▼ {
  align-self: flex-end;
  margin: 1.3rem 1.5rem 7.9625rem 0;
}

.R-under {
  text-align: right;
  position: absolute;
  right: 0;
  bottom: 0;
}

.nbb {
  padding-right: 4.8rem;
}

.nb {
  padding-right: 0.8rem;
}

.period {
  padding-right: 1.6rem;
}

.top {
  display: flex;
  justify-content: space-between;
  font-size: 1.1rem;
  padding: 0.3rem 0 2rem;
  text-align: right;
}

.category {
  padding-right: 1.4rem;
}

.class {
  padding-right: 1.4rem;
}

.release {
  padding-right: 1.4rem;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.5.0/css/swiper.min.css" rel="stylesheet"/>

<!-- The corresponding part is at the bottom. (It is faster to count from the bottom)
(There is a mark in the comment) -->

<div class="solid-ti"></div>

<div id="wrap">
  <div id="left">
    <h1 class="title">動と静を共有する椅子「Rollse」</h1>

    <div class="swiper-pagination"></div>
    <div class="swiper-container swiperCnt max">
      <div class="swiper-wrapper imgs max-inner">
        <div class="swiper-slide"><img class="work" src="http://placehold.jp/45/1920a6/ffffff/693x350.png?text=1" alt="Rollse-logo" /></div>
        <div class="swiper-slide"><img class="work" src="http://placehold.jp/45/199fa6/ffffff/693x350.png?text=2" alt="Rollse-killer" /></div>
        <div class="swiper-slide"><img class="work" src="http://placehold.jp/45/a61972/ffffff/693x350.png?text=3" alt="Rollse-data" /></div>
        <div class="swiper-slide"><img class="work" src="http://placehold.jp/45/a6a619/ffffff/693x350.png?text=4" alt="Rollse-image" /></div>
      </div>
    </div>

    <div class="L-under">
      <div class="mis">
        <h3 class="mission">MISSION:</h3>
        <p class="m-p">触覚に訴えるプロダクト   ▶︎ 3人チームの1人が、この触り心地を発見</p>
      </div>

      <div class="solid-mc"></div>

      <div class="con">
        <h2 class="concept">CONCEPT:</h2>
        <p class="c-p">緊張感のある空間をつくる。</p>
      </div>

      <div class="what">
        <img src="http://placehold.jp/45/d4d4d4/d4d4d4/28x20.png?text=_" alt="2nd" /><img src="http://placehold.jp/45/d4d4d4/d4d4d4/20x20.png?text=_" alt="ai" /><img src="http://placehold.jp/45/d4d4d4/d4d4d4/20x20.png?text=_" alt="vw" />

        <span>企画</span>
        <span>雑貨の設計</span>
        <span>ネーミング</span>
        <span>文章</span>
        <span>展開</span>
      </div>
    </div>
  </div>

  <div id="right">
    <div class="top">
      <div class="cat">
        <h5 class="category">CATEGORY:</h5>
        <p class="cg-p">雑貨・プロダクト</p>
      </div>

      <div class="cla">
        <h5 class="class">CLASS:</h5>
        <p class="cl-p">デザイン研究</p>
      </div>

      <div class="rel">
        <h5 class="release">RELEASE:</h5>
        <p class="r-p">2017/06</p>
      </div>
    </div>
    <div class="heartbox">
      <div class="tar">
        <h3 class="target">TARGET:</h3>
        <p class="t-p">生活に刺激を求めている人<br> デザインされたものが好きな人
          <br> 動くのに若干抵抗がある人
        </p>
      </div>
      <div>
        <input type="checkbox" name="fav" id="fav">
        <label for="fav">
            <svg class="heart" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg"
              xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 37 32"
              style="enable-background:new 0 0 37 32;" xml:space="preserve">
              <path class="st0" d="M27,0c-2.5,0-4.9,0.9-6.7,2.6C19.6,3.2,19,4,18.5,4.7C18,4,17.4,3.2,16.7,2.6C14.9,0.9,12.5,0,10,0
            C4.5,0,0,4.5,0,10c0,3.7,1.2,6.7,3.9,9.8c3.9,4.6,13.9,11.6,14.3,11.9c0.1,0.1,0.2,0.1,0.3,0.1s0.2,0,0.3-0.1
            c0.4-0.3,10.4-7.3,14.3-11.9c2.7-3.2,3.9-6.1,3.9-9.8C37,4.5,32.5,0,27,0z" /></svg>
          </label>
      </div>
    </div>

    <div class="solid-tm"></div>





    <!--
from here
-->
    <div class="mai max">
      <section class="main max-inner">
        <p class="active 0">This part is Switch scroll. (move by scrolling) <br> rolls(渦)×rose(バラ)<br> モチーフの見た目から命名しました。
          <br> “R”は小文字より大文字にすることで、凛々しさを演出し、
          <br> 大人の美しさを際立たせました。
        </p>
        <br>
        <p class="1">触覚に訴える。それで日常の問題を解決できたら。ついつい無駄に過ごしてしまいがちな日常。<br> そこであえて触感の悪いものを提供して、その無駄な時間を少しでも減らせる手助けになる商品をつくりました。
        </p>
        <br>
        <p class="2">無数の紙を渦状に丸めた形状によって、片面は固く、もう片面は程よく弾力のある、画期的な椅子になっています。<br> 様々な素材や大きさのロールによるカスタム仕様なので、様々な展開が可能です。
        </p>
        <p class="3">毎日の慣れた生活空間の中に新感覚の刺激を与えてくれ、エキサイティングな感覚と少しのスリルを味わうことができます。</p>
      </section>
    </div>
    <!-- 
to here
-->





    <img src="http://placehold.jp/45/d4d4d4/d4d4d4/14x12.png?text=_" alt="▼" class="▼" width="14" />

    <div class="R-under">
      <div class="nbb">
        <h4 class="nb">N.B.:</h4>
        <p class="nb-p">投票第1位</p>
      </div>

      <div class="per">
        <h4 class="period">PERIOD:</h4>
        <p class="p-p">1週間</p>
      </div>
    </div>
  </div>
</div>


<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.5.0/js/swiper.min.js"></script>

0 个答案:

没有答案