首页 > 解决方案 > 如何找出具有相似类的块划掉固定块(getBoundingClientRect)?

问题描述

我有这个问题。我有不同颜色的 div 块的轮播。让我们将它们命名为一、二和三。在它们之上有一个名为“INFO”的固定块。所以,它定居在两个街区之间。如果块 ONE 超过 80% 的信息块,我想在控制台“1”中写入。我对如何确定 INFO 下的特定块没有任何想法。PS:如果轮播的块跨越信息块,现在我在控制台“你好”写,但我需要写轮播块的 ID。

HTML:

<body>
    <div class="container">
        <div class="carousel">
            <!-- Carousel -->
            <div class="carousel-content">

                <div class="slide slide-1">
                    <div>1</div>
                </div>
                <div class="slide slide-2">
                    <div>2</div>
                </div>
                <div class="slide slide-3">
                    <div>3</div>
                </div>

            </div>

            <!-- Fixed Block-->
            <div class="infoblock">
                <div>INFO</div>
            </div>

            <!-- Scroll Buttons -->
            <div class="nav nav-left">
                <div class="ion-chevron-left carousel-arrow-icon-left"></div>
            </div>

            <div class="nav nav-right">
                <div class="ion-chevron-right carousel-arrow-icon-right"></div>
            </div>

        </div>
    </div>

    <script src="script.js"></script>
</body>

CSS:

*,
*:before,
*:after {
  box-sizing: border-box;
}

.carousel {
  position: relative;
  width: 50%;
  height: 50px; 
  margin: 0 auto;
}

.carousel-content {
  position: relative;
  overflow: hidden;
  transition: width .4s;
  height: 100%;
}

.slide {
  height: 100%;
  position: absolute;
  z-index: 1;
  transition: left .4s cubic-bezier(.47,.13,.15,.89);
}

.slide-1{
    background-color:cyan;
}

.slide-2 {
    background-color: green;
}

.slide-3 {
    background-color: red;
}


.nav {
  position: absolute;
  top: 50%;
  margin-top: -10px;
  background-color: rgba(150,150,150,.3);
  width: 20px;
  height: 20px;
  z-index: 2;
  cursor: pointer;
  border-radius: 50%;
  border: none;
  outline: none;
  color: white;
}

.nav-left {
  left: -25px;
}

.nav-right {
  right: -25px;
}


.infoblock{
    position: absolute;
    background-color:darkorange;
    z-index: 2;
    margin-top: -5vh;
    margin-left: 10vw;
    height: 100%;
    width: 20%;
    opacity: 0.6;
    text-align: center;
    border: 1px solid black;
  }

JavaScript:

var carousel = document.querySelector('.carousel');
var carouselContent = document.querySelector('.carousel-content');
var slides = document.querySelectorAll('.slide');
var arrayOfSlides = Array.prototype.slice.call(slides);
var carouselDisplaying;
var screenSize;
setScreenSize();
var lengthOfSlide;

function addClone() {
    var lastSlide = carouselContent.lastElementChild.cloneNode(true);
    lastSlide.style.left = (-lengthOfSlide) + "px";
    carouselContent.insertBefore(lastSlide, carouselContent.firstChild);
}

function removeClone() {
    var firstSlide = carouselContent.firstElementChild;
    firstSlide.parentNode.removeChild(firstSlide);
}

function moveSlidesRight() {
    var slides = document.querySelectorAll('.slide');
    var slidesArray = Array.prototype.slice.call(slides);
    var width = 0;

    slidesArray.forEach(function (el, i) {
        el.style.left = width + "px";
        width += lengthOfSlide;
    });
    addClone();
}
moveSlidesRight();

function moveSlidesLeft() {
    var slides = document.querySelectorAll('.slide');
    var slidesArray = Array.prototype.slice.call(slides);
    slidesArray = slidesArray.reverse();
    var maxWidth = (slidesArray.length - 1) * lengthOfSlide;

    slidesArray.forEach(function (el, i) {
        maxWidth -= lengthOfSlide;
        el.style.left = maxWidth + "px";
    });
}

window.addEventListener('resize', setScreenSize);

function setScreenSize() {
    if (window.innerWidth >= 500) {
        carouselDisplaying = 3;
    } else if (window.innerWidth >= 300) {
        carouselDisplaying = 2;
    } else {
        carouselDisplaying = 1;
    }
    getScreenSize();
}

function getScreenSize() {
    var slides = document.querySelectorAll('.slide');
    var slidesArray = Array.prototype.slice.call(slides);
    lengthOfSlide = (carousel.offsetWidth / carouselDisplaying);
    var initialWidth = -lengthOfSlide;
    slidesArray.forEach(function (el) {
        el.style.width = lengthOfSlide + "px";
        el.style.left = initialWidth + "px";
        initialWidth += lengthOfSlide;
    });
}


var rightNav = document.querySelector('.nav-right');
rightNav.addEventListener('click', moveLeft);

var moving = true;
function moveRight() {
    if (moving) {
        moving = false;
        var lastSlide = carouselContent.lastElementChild;
        lastSlide.parentNode.removeChild(lastSlide);
        carouselContent.insertBefore(lastSlide, carouselContent.firstChild);
        removeClone();
        var firstSlide = carouselContent.firstElementChild;
        firstSlide.addEventListener('transitionend', activateAgain);
        moveSlidesRight();
    }
}

function activateAgain() {
    var firstSlide = carouselContent.firstElementChild;
    moving = true;
    firstSlide.removeEventListener('transitionend', activateAgain);
}

var leftNav = document.querySelector('.nav-left');
leftNav.addEventListener('click', moveRight);


function moveLeft() {
    if (moving) {
        moving = false;
        removeClone();
        var firstSlide = carouselContent.firstElementChild;
        firstSlide.addEventListener('transitionend', replaceToEnd);
        moveSlidesLeft();
    }
}

function replaceToEnd() {
    var firstSlide = carouselContent.firstElementChild;
    firstSlide.parentNode.removeChild(firstSlide);
    carouselContent.appendChild(firstSlide);
    firstSlide.style.left = ((arrayOfSlides.length - 1) * lengthOfSlide) + "px";
    addClone();
    moving = true;
    firstSlide.removeEventListener('transitionend', replaceToEnd);
}




carouselContent.addEventListener('mousedown', seeMovement);

var initialX;
var initialPos;
function seeMovement(e) {
    initialX = e.clientX;
    getInitialPos();
    carouselContent.addEventListener('mousemove', slightMove);
    document.addEventListener('mouseup', moveBasedOnMouse);
}

function slightMove(e) {
    if (moving) {
        var movingX = e.clientX;
        var difference = initialX - movingX;
        if (Math.abs(difference) < (lengthOfSlide / 4)) {
            slightMoveSlides(difference);
        }
    }
}

function getInitialPos() {
    var slides = document.querySelectorAll('.slide');
    var slidesArray = Array.prototype.slice.call(slides);
    initialPos = [];
    slidesArray.forEach(function (el) {
        var left = Math.floor(parseInt(el.style.left.slice(0, -2)));
        initialPos.push(left);
    });
}

function slightMoveSlides(newX) {
    var slides = document.querySelectorAll('.slide');
    var slidesArray = Array.prototype.slice.call(slides);
    slidesArray.forEach(function (el, i) {
        var oldLeft = initialPos[i];
        el.style.left = (oldLeft + newX) + "px";
    });
}

function moveBasedOnMouse(e) {
    var finalX = e.clientX;
    if (initialX - finalX > 0) {
        moveRight();
    } else if (initialX - finalX < 0) {
        moveLeft();
    }
    document.removeEventListener('mouseup', moveBasedOnMouse);
    carouselContent.removeEventListener('mousemove', slightMove);
}
/* Blocks Overlapping*/
const boxes = document.querySelectorAll(".slide");

function checkOverlap(ele1, ele2) {
    const boundings1 = ele1.getBoundingClientRect();
    const boundings2 = ele2.getBoundingClientRect();

    const top1 = parseInt(boundings1.top);
    const height1 = parseInt(boundings1.height);
    const top2 = parseInt(boundings2.top);

    const overlap = 1 - (top2 - top1) / height1;

    if (overlap >= 0.8) {
        ele2.classList.add("overlap-80");
        console.log('hello');
    }


}

checkOverlap(boxes[0], boxes[1]);
checkOverlap(boxes[2], boxes[3]);
checkOverlap(boxes[4], boxes[5]);

标签: javascripthtmlcsscarouseloverlay

解决方案


如果INFO框总是小于幻灯片,则可以document.elementsFromPoint()在四个角上使用它来获取这些点的幻灯片列表:

var carousel = document.querySelector('.carousel');
var carouselContent = document.querySelector('.carousel-content');
var slides = document.querySelectorAll('.slide');
var arrayOfSlides = Array.prototype.slice.call(slides);
var carouselDisplaying;
var screenSize;
setScreenSize();
var lengthOfSlide;

function addClone() {
    var lastSlide = carouselContent.lastElementChild.cloneNode(true);
    lastSlide.style.left = (-lengthOfSlide) + "px";
    carouselContent.insertBefore(lastSlide, carouselContent.firstChild);
}

function removeClone() {
    var firstSlide = carouselContent.firstElementChild;
    firstSlide.parentNode.removeChild(firstSlide);
}

function moveSlidesRight() {
    var slides = document.querySelectorAll('.slide');
    var slidesArray = Array.prototype.slice.call(slides);
    var width = 0;

    slidesArray.forEach(function (el, i) {
        el.style.left = width + "px";
        width += lengthOfSlide;
    });
    addClone();
}
moveSlidesRight();

function moveSlidesLeft() {
    var slides = document.querySelectorAll('.slide');
    var slidesArray = Array.prototype.slice.call(slides);
    slidesArray = slidesArray.reverse();
    var maxWidth = (slidesArray.length - 1) * lengthOfSlide;

    slidesArray.forEach(function (el, i) {
        maxWidth -= lengthOfSlide;
        el.style.left = maxWidth + "px";
    });
}

window.addEventListener('resize', setScreenSize);

function setScreenSize() {
    if (window.innerWidth >= 500) {
        carouselDisplaying = 3;
    } else if (window.innerWidth >= 300) {
        carouselDisplaying = 2;
    } else {
        carouselDisplaying = 1;
    }
    getScreenSize();
}

function getScreenSize() {
    var slides = document.querySelectorAll('.slide');
    var slidesArray = Array.prototype.slice.call(slides);
    lengthOfSlide = (carousel.offsetWidth / carouselDisplaying);
    var initialWidth = -lengthOfSlide;
    slidesArray.forEach(function (el) {
        el.style.width = lengthOfSlide + "px";
        el.style.left = initialWidth + "px";
        initialWidth += lengthOfSlide;
    });
}


var rightNav = document.querySelector('.nav-right');
rightNav.addEventListener('click', moveLeft);

var moving = true;
function moveRight() {
    if (moving) {
        moving = false;
        var lastSlide = carouselContent.lastElementChild;
        lastSlide.parentNode.removeChild(lastSlide);
        carouselContent.insertBefore(lastSlide, carouselContent.firstChild);
        removeClone();
        var firstSlide = carouselContent.firstElementChild;
        firstSlide.addEventListener('transitionend', activateAgain);
        moveSlidesRight();
    }
}

function activateAgain() {
    var firstSlide = carouselContent.firstElementChild.nextSibling; /*changed*/
    moving = true;
    firstSlide.removeEventListener('transitionend', activateAgain);
}


var leftNav = document.querySelector('.nav-left');
leftNav.addEventListener('click', moveRight);


function moveLeft() {
    if (moving) {
        moving = false;
        removeClone();
        var firstSlide = carouselContent.firstElementChild;
        firstSlide.addEventListener('transitionend', replaceToEnd);
        moveSlidesLeft();
    }
}

function replaceToEnd() {
    var firstSlide = carouselContent.firstElementChild;
    firstSlide.parentNode.removeChild(firstSlide);
    carouselContent.appendChild(firstSlide);
    firstSlide.style.left = ((arrayOfSlides.length - 1) * lengthOfSlide) + "px";
    addClone();
    moving = true;
    firstSlide.removeEventListener('transitionend', replaceToEnd);
}




carouselContent.addEventListener('mousedown', seeMovement);

var initialX;
var initialPos;
function seeMovement(e) {
    initialX = e.clientX;
    getInitialPos();
    carouselContent.addEventListener('mousemove', slightMove);
    document.addEventListener('mouseup', moveBasedOnMouse);
}

function slightMove(e) {
    if (moving) {
        var movingX = e.clientX;
        var difference = initialX - movingX;
        if (Math.abs(difference) < (lengthOfSlide / 4)) {
            slightMoveSlides(difference);
        }
    }
}

function getInitialPos() {
    var slides = document.querySelectorAll('.slide');
    var slidesArray = Array.prototype.slice.call(slides);
    initialPos = [];
    slidesArray.forEach(function (el) {
        var left = Math.floor(parseInt(el.style.left.slice(0, -2)));
        initialPos.push(left);
    });
}

function slightMoveSlides(newX) {
    var slides = document.querySelectorAll('.slide');
    var slidesArray = Array.prototype.slice.call(slides);
    slidesArray.forEach(function (el, i) {
        var oldLeft = initialPos[i];
        el.style.left = (oldLeft + newX) + "px";
    });
}

function moveBasedOnMouse(e) {
    var finalX = e.clientX;
    if (initialX - finalX > 0) {
        moveRight();
    } else if (initialX - finalX < 0) {
        moveLeft();
    }
    document.removeEventListener('mouseup', moveBasedOnMouse);
    carouselContent.removeEventListener('mousemove', slightMove);
}
/* Blocks Overlapping*/
/*changed*/
const infoBox = document.querySelector(".infoblock>div");
function checkOverlap() {
    const info = infoBox.getBoundingClientRect();

    let data = [],
        slide = document.querySelector('.slide').getBoundingClientRect(),
        list = [];

    // check elements at each corner of info block and several points within
    for(let x = 0, cache = {}; x < Math.round(info.width / (slide.width/3)); x++)
    {
      for(let y = 0; y < Math.round(info.height / (slide.height/3)); y++)
      {
        const  X = Math.min(info.right-1, info.left + slide.width * x),
               Y = Math.min(info.bottom-1, info.top + slide.height * y);

        if (cache[X + "x" + Y])
          continue;

        list = list.concat(cache[X + "x" + Y] = document.elementsFromPoint(X, Y));
      }
    }
    //leave only slides and remove any duplicates
    list = list.filter((item, pos) => item.classList.contains("slide") && list.indexOf(item) === pos);
    for(let i = 0; i < list.length; i++)
    {
      const slide = list[i];
      const box = slide.getBoundingClientRect(),
            width = Math.max(Math.min(box.right, info.right) - Math.max(box.left, info.left), 0),
            height = Math.max(Math.min(box.bottom, info.bottom) - Math.max(box.top, info.top), 0),
            overlapX = width / info.width,
            overlapY = height / info.height,
            overlapArea = (width * height) / (info.width * info.height);

      data[data.length] = {slide: slide, area: overlapArea, x: overlapX, y: overlapY}
    }
    return data;
}

/* demo */
let infoRect = infoBox.getBoundingClientRect(),
    theta = Math.random() * 10,
    gamma = Math.random() * 1,
    dragX = 0,
    dragY = 0,
    pause = true;

document.onmousedown = function(e)
{
  if (e.target === infoBox.parentNode)
    return infoBox.parentNode.classList.add("resize");

  if (e.target != infoBox)
    return;

  dragX = e.x - infoBox.parentNode.offsetLeft;
  dragY = e.y - infoBox.parentNode.offsetTop;
  document.body.classList.add("drag");
}
document.onmouseup = function(e)
{
  if (!document.body.classList.contains("drag") && !infoBox.parentNode.classList.contains("resize"))
    return;

  document.body.classList.remove("drag");
  infoBox.parentNode.classList.remove("resize");
  demoInfo(true);
}
document.onmousemove = function(e)
{
  const isMove =  document.body.classList.contains("drag");
  if (!isMove && !infoBox.parentNode.classList.contains("resize"))
    return;

  if (isMove)
  {
    infoBox.parentNode.style.left = (e.x - dragX) + "px";
    infoBox.parentNode.style.top = (e.y - dragY) + "px";
  }
  demoInfo();
}

//we can use parent container to listen for transition events
document.querySelector(".carousel-content").addEventListener("transitionend", demoInfo);

function isOverlapped(node, data)
{
  for(let i = 0; i < data.length; i++)
  {
    if (data[i].slide === node)
      return true;
  }
  return false;
}
function demoInfo(moved)
{
  const r = infoBox.getBoundingClientRect();
  document.documentElement.style.setProperty('--size', Math.min(r.height, Math.min(r.width, 100)) / 76 + 'em')
  const data = checkOverlap();
  data.sort((a,b) => b.area - a.area); //sorted by area
  const slides = document.querySelectorAll(".slide");
  for(let i = 0; i < slides.length; i++)
  {
    slides[i].classList.toggle("overlapMost", data.length && slides[i] === data[0].slide)
    slides[i].classList.toggle("overlap", isOverlapped(slides[i], data))
  }
  if (data.length)
  {
    infoBox.textContent = "Slide " + data[0].slide.textContent.trim() + " overlap\nArea:" + Math.round(data[0].area * 100) + "%\nWidth:" + Math.round(data[0].x * 100) + "%\nHeight:" + Math.round(data[0].y * 100) + "%";
  }
  else
  {
    infoBox.textContent = "no overlap\n\ndrag me";
  }
  if (moved)
  {
    console.clear();
    for(let i = 0; i < data.length; i++)
    {
      console.log("Slide " + data[i].slide.textContent.trim() + " ( " + Array.prototype.indexOf.call(data[i].slide.parentNode.children, data[i].slide) + " child) overlap area: " + Math.round(data[i].area * 100) + "%, X: " + Math.round(data[i].x *100) + "%, Y: " + Math.round(data[i].y *100) + "%");
    }
  }
}
demoInfo();
*,
*:before,
*:after {
  box-sizing: border-box;
}

.carousel {
  position: relative;
  width: 50%;
  height: 50px; 
  margin: 0 auto;
}

.carousel-content {
  position: relative;
  overflow: hidden;
  transition: width .4s;
  height: 100%;
}

.slide {
  height: 100%;
  position: absolute;
  z-index: 1;
  transition: left .4s cubic-bezier(.47,.13,.15,.89);
}

.slide > div
{
  vertical-align: middle;
  text-align: center;
}
.slide-1{
    background-color:cyan;
}

.slide-2 {
    background-color: green;
}

.slide-3 {
    background-color: red;
}
.slide-4 {
    background-color: lightblue;
}
.slide-5 {
    background-color: lightpink;
}


.nav {
  position: absolute;
  top: 50%;
  margin-top: -10px;
  background-color: rgba(150,150,150,.3);
  width: 20px;
  height: 20px;
  z-index: 2;
  cursor: pointer;
  border-radius: 50%;
  border: none;
  outline: none;
  color: white;
}

.nav-left {
  left: -25px;
}

.nav-right {
  right: -25px;
}


.infoblock{
    position: absolute;
    background-color:darkorange;
    z-index: 2;
/*    margin-top: -5vh;
    margin-left: 10vw;*/
    height: 100%;
    width: 25%;
    opacity: 0.6;
    text-align: center;
    border: 1px solid black;
font-size: 0.7em;
font-size: var(--size);
white-space: pre;
min-width: 20%;
min-height: 80%;
cursor: move;
top: 5vh;
left: 10vw;
text-shadow: 0 0 1px gray;
resize: both;
overflow: hidden;
display: flex;
  }

.infoblock > div
{
  width: 100%;
  height: 100%;
}
.overlap
{
  box-shadow: 0 0 20px 0 black inset;
  z-index: 2;
}

.overlapMost
{
  box-shadow: 0 0 20px 10px blue inset;
  z-index: 2;
}

body.drag
{
  user-select: none;
}
<div class="container">
        <div class="carousel">
            <!-- Carousel -->
            <div class="carousel-content">

                <div class="slide slide-1">
                    <div>1</div>
                </div>
                <div class="slide slide-2">
                    <div>2</div>
                </div>
                <div class="slide slide-3">
                    <div>3</div>
                </div>
                <div class="slide slide-4">
                    <div>4</div>
                </div>
                <div class="slide slide-5">
                    <div>5</div>
                </div>

            </div>

            <!-- Fixed Block-->
            <div class="infoblock">
                <div>Drag Me</div>
            </div>

            <!-- Scroll Buttons -->
            <div class="nav nav-left">
                <div class="ion-chevron-left carousel-arrow-icon-left"></div>
            </div>

            <div class="nav nav-right">
                <div class="ion-chevron-right carousel-arrow-icon-right"></div>
            </div>

        </div>
    </div>

PS 在您的代码中有一个错误,即transitionend当移动到右侧时事件没有被删除,因为它试图从第一张幻灯片中删除它,但是到那时带有事件侦听器的幻灯片已经移动到第二个位置。


推荐阅读