为什么第一个元素与最后一个元素之间的距离减小了?

问题描述

我正在尝试制作一个image slider。但是如您所见,第一个元素与最后一个元素之间的距离不一致。如果继续向左拖动,则距离会减小;如果继续向右拖动,则距离会增大。看起来代码在不同的缩放级别(有时?)上的行为有所不同,因此每个元素之间的距离有时会发生变化。

//project refers to placeholder rectangular divs

projectContainer = document.querySelector(".project-container")
projects = document.querySelectorAll(".project")

elementAOffset = projects[0].offsetLeft;
elementBOffset = projects[1].offsetLeft;
elementAWidth = parseInt(getComputedStyle(projects[0]).width)
margin = (elementBOffset - (elementAOffset + elementAWidth))

LeftSideBoundary = -(elementAWidth)
RightSideBoundary = (elementAWidth * (projects.length)) + (margin * (projects.length))
RightSidePosition = RightSideBoundary - elementAWidth;

initialPosition = 0; //referring to mouse 
mouseIsDown = false

projectContainer.addEventListener("mousedown",e => {
    mouseIsDown = true
    initialPosition = e.clientX;
})

projectContainer.addEventListener("mouseup",e => {
    mouseExit(e)
})

projectContainer.addEventListener("mouseleave",e => {
    mouseExit(e);
})

function mouseExit(e) {
    mouseIsDown = false

    //updates translateX value of transform
    projects.forEach(project => {
        var style = window.getComputedStyle(project)
        project.currentTranslationX = (new WebKitCSSMatrix(style.webkitTransform)).m41
        project.style.transform = 'translateX(' + (project.currentTranslationX) + 'px)'
    })
}

projectContainer.addEventListener("mousemove",e => {
    if (!mouseIsDown) { return };

    // adds mousemovement to translateX
    projects.forEach(project => {
        project.style.transform = 'translateX(' + ((project.currentTranslationX ?? 0) + (e.clientX - initialPosition)) + 'px)'
        shiftPosition(e,project)
    })
})

//teleports div if it hits left or right boundary to make an infinite loop
function shiftPosition(e,project) {
    projectStyle = window.getComputedStyle(project)
    projectTranslateX = (new WebKitCSSMatrix(projectStyle.webkitTransform)).m41
    //projectVisualPosition is relative to the left border of container div
    projectVisualPosition = project.offsetLeft + projectTranslateX

    if (projectVisualPosition <= LeftSideBoundary) {
        project.style.transform = "translateX(" + ((RightSidePosition - project.offsetLeft)) + "px)"
        updateTranslateX(e);
    }
    if (projectVisualPosition >= RightSidePosition) {
        newPosition = -1 * (project.offsetLeft + elementAWidth)
        project.style.transform = "translateX(" + newPosition + "px)"
        updateTranslateX(e);
    }
}

function updateTranslateX(e) {
    projects.forEach(project => {
        style = window.getComputedStyle(project)
        project.currentTranslationX = (new WebKitCSSMatrix(style.webkitTransform)).m41

        project.style.transform = 'translateX(' + (project.currentTranslationX) + 'px)'
        initialPosition = e.clientX
    })
}
 *,*::before,*::after{
        margin:0px;
        padding:0px;
        box-sizing: border-box;
        font-size:0px;
        user-select: none;
    }
    
    .project-container{
        font-size: 0px;
        position: relative;
        width:1500px;
        height:400px;
        background-color: rgb(15,207,224);
        margin:auto;
        margin-top:60px;
        white-space: nowrap;
        overflow: hidden;
        padding-left:40px;
        padding-right:40px;
    }
    
    .project{
        font-size:100px;
        margin:40px;
        display: inline-block;
        height:300px;
        width:350px;
        background-color:red;
        border: black 3px solid;
        user-select: none;
    }
        <div class="project-container">
            <div class="project">1</div>
            <div class="project">2</div>
            <div class="project">3</div>
            <div class="project">4</div>
            <div class="project">5</div>
            <div class="project">6</div>
            <div class="project">7</div>
            <div class="project">8</div>
        </div>

解决方法

我不确定您将如何解决实施问题。我玩了一段时间,发现了一些东西。更快地拖动会使位移变得更糟,并且位移似乎主要发生在容器两端的元件被传送时。

我想这的主要原因是您遍历所有元素并将它们单独隔开。鼠标移动事件通常间隔20毫秒以内发生,并且您依赖于所有DOM元素在注册下一个移动之前重新绘制其新的变换位置。

我确实提出了另一种使用绝对放置元素和IntersectionObserver API的方法,现在所有现代浏览器都支持该方法。这里的想法基本上是,当每个元素与容器的边缘相交时,它会触发数组查找,以查看序列中的下一个元素是否在正确的末端上,如果没有,则将其移动到正确的末端。元素仅由静态变量隔开,而滑动它们的工作将传递到新的父包装器.project-slider

window.addEventListener('DOMContentLoaded',() => {
  // Style variables
  const styles = {
    width: 350,margin: 40
  };
  const space = styles.margin*2 + styles.width;

  // Document variables
  const projectContainer = document.querySelector(".project-container");
  const projectSlider = document.querySelector(".project-slider");
  const projects = Array.from(document.querySelectorAll(".project"));

  // Mouse interactions
  let dragActive = false;
  let prevPos = 0;

  projectContainer.addEventListener('mousedown',e => {
    dragActive = true;
    prevPos = e.clientX;
  });

  projectContainer.addEventListener('mouseup',() => dragActive = false);

  projectContainer.addEventListener('mouseleave',() => dragActive = false);

  projectContainer.addEventListener('mousemove',e => {
    if (!dragActive) return;

    const newTrans = projectSlider.currentTransX + e.clientX - prevPos;

    projectSlider.style.transform = `translateX(${newTrans}px)`;
    projectSlider.currentTransX = newTrans;
    prevPos = e.clientX;
  });
  
  // Generate initial layout
  function init() {
    let workingLeft = styles.margin;

    projects.forEach((project,i) => {
      if (i === projects.length - 1) {
        project.style.left = `-${space - styles.margin}px`;
      } else {
        i !== 0 && (workingLeft += space);
        project.style.left = `${workingLeft}px`;
      };
    });

    projectSlider.currentTransX = 0;
  };

  // Intersection observer
  function observe() {

    const callback = (entries,observer) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {

          // Find intersecting edge
          const { left } = entry.boundingClientRect;
          const isLeftEdge = left < projectContainer.clientWidth - left;

          // Test and reposition next element
          const targetIdx = projects.findIndex(project => project === entry.target);
          let nextIdx = null;
          const nextEl = () => projects[nextIdx];

          const targetLeft = parseInt(entry.target.style.left);
          const nextLeft = () => parseInt(nextEl().style.left);

          if (isLeftEdge) {
            nextIdx = targetIdx === 0 ? projects.length-1 : targetIdx - 1;
            nextLeft() > targetLeft && (nextEl().style.left = `${targetLeft - space}px`);
          } else {
            nextIdx = targetIdx === projects.length-1 ? 0 : targetIdx + 1;
            nextLeft() < targetLeft && (nextEl().style.left = `${targetLeft + space}px`);
          };
        };
      });
    };

    const observer = new IntersectionObserver(callback,{root: projectContainer});

    projects.forEach(project => observer.observe(project));
  };

  init();
  observe();
});
*,*::before,*::after{
    margin:0px;
    padding:0px;
    box-sizing: border-box;
    font-size:0px;
    user-select: none;
}
    
.project-container {
    font-size: 0px;
    width: 100%;
    height: 400px;
    background-color: rgb(15,207,224);
    margin:auto;
    margin-top:60px;
    white-space: nowrap;
    overflow: hidden;
}

.project-slider {
  position: relative;
}
    
.project {
    font-size:100px;
    display: block;
    position: absolute;
    top: 40px;
    height:300px;
    width:350px;
    background-color:red;
    border: black 3px solid;
    user-select: none;
}
<div class="project-container">
  <div class="project-slider">
    <div class="project">1</div>
    <div class="project">2</div>
    <div class="project">3</div>
    <div class="project">4</div>
    <div class="project">5</div>
    <div class="project">6</div>
    <div class="project">7</div>
    <div class="project">8</div>
  </div>
</div>

这里仍然存在一个问题,即如何为较小的屏幕调整元素的大小以及如何在浏览器上调整大小。您必须为窗口调整大小添加另一个事件侦听器,该事件侦听器将在某些断点处重置位置和样式,并在页面首次加载时以编程方式确定样式变量。我认为,对于原始实施方案来说,这仍然是一个局部问题,因此您必须在某种程度上以某种方式解决它。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...