将特定元素的垂直滚动改为水平滚动

8

背景是什么?

我有一个网站,只有一个页面,我将在此页面介绍我的活动和项目。在向下滚动几个部分后,我们会看到一排项目。

我想做什么?

我想在到达项目行时将垂直滚动切换为水平滚动。当您到达行的末尾时,它只需恢复正常的垂直滚动。

代码

<div className="projectsContainer">     // <--- height 100vh
    <div className="row projects">     //  <--- Positioned in the middle of the parent ↑
        <project1  />
        <project2  />
        <project3  />
        <project4  />
        <project5  />
    </div>
</div>

我的代码是什么?我在想些什么?

我有一个名为 inTheMiddle() 的方法,返回布尔值。<div className="row projects"> 如果在视口中间,则返回true,否则返回false

一个名为 scrollDirection() 的方法也返回布尔值,在向下滚动时返回true,在向上滚动时返回false

有许多不同的方法名为disableScroll(),最后一个disableScroll()方法通过重新计算来取消滚动。

componentDidMount() {
     window.addEventListener('wheel', (this.handleScroll));
}
...
disableScroll() {
    // Get the current page scroll position 
    const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
    const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
    // if any scroll is attempted, set this to the previous value 
    window.onscroll = () => {
        window.scrollTo(scrollLeft, scrollTop);
    };
}

而我的handleScroll()方法则负责管理所有这些。

handleScroll(event) {
    const rowProjects = document.querySelector(".row.projects")
    const projectsContainer = document.querySelector(".projectsContainer")
    const isSticky = rowProjects.classList.contains("sticky") 
// isSticky is useless now was try by adding position fixed and no need to use disableScroll()

    if (this.inTheMiddle() && this.state.scrollDown && this.state.count < 1400 ) {
        this.disableScroll()
        this.setState({ count: this.state.count + 10 })
        rowProjects.scroll(this.state.count, 0)
    } else if ((!this.state.scrollDown) && this.state.count > 0) {
        this.setState({ count: this.state.count - 10 })
        rowProjects.scroll(this.state.count, 0)
    }

}

我无法恢复正常状态。当你到达一行的末尾时,我无法重新启用滚动,即使我向上滚动到页面顶部也不能。它卡在了项目行。

我使用了 isSticky 来解决了问题。我取消了 disableScroll() 并添加了一个带有固定位置的类,但是问题是它反弹了。因为当元素位于中间时,我在视口中央固定元素,所以元素不再处于相对位置,就像从堆栈块中取出一个块一样反弹。抱歉,这个例子不太好 :')

如果你有任何想法可以帮助我,那将非常友善。我已经苦思冥想了3天,仍然没有找到完美的解决方案。


https://morioh.com/p/7c097570ecd9 - diedu
那么简单来说,您只希望滚动条水平而不是垂直的对吗? - user13662320
哦,你想在到达项目行时使垂直滚动条消失,是吗?那么,你可以使用JavaScript来实现。 - user13662320
我会尝试使用您给我的代码,并加入一些其他的代码。希望能够顺利运行。 - crg
@crg,你可以进行垂直滚动,并使用window.scrollY值来通过element.style.left水平位移元素。我也是这样做的,它起作用了。 - ac_mmi
显示剩余2条评论
4个回答

9

这应该可以正常工作。您可以进行垂直滚动,并使用window.scrollY值来通过将其值分配给element.style.left来使元素水平偏移,从而产生水平滚动效果。我也是这样做的,它可以正常工作。

(在全屏模式下查看结果)。

var content = document.getElementById('content_2');
window.addEventListener('scroll', function() {
  var scrolledY = window.scrollY;
  var scrolledX = window.scrollX;

  if (scrolledY > 625 && scrolledY < 3112) {
    content.style.marginTop = 150 + 'px';
    content.style.position = "fixed";
    content.style.top = scrolledY * 0.001 + 'px';
    content.style.left = -(scrolledY - 625) * 0.55 + 'px';

  }
  if (scrolledY <= 625) {
    content.style.position = "initial";

  }
  if (scrolledY >= 3112) {

    content.style.position = "absolute";
    content.style.top = 3112 + 'px';

  }


});
* {
  margin: 0px;
  padding: 0px;
  font-family: 'Arial';
  overflow-x: hidden;
  scroll-behavior: smooth;
}

body {
  min-height: 4400px;
}

.content_1,
.content_2 {
  height: 100vh;
  width: 100vw;
}

.content_1 {
  background-color: black;
  color: white;
}

.content_1 h1 {
  font-size: 200px;
  text-align: center;
}

.content_2 {
  margin-top: 150px;
  top: 625px;
  white-space: nowrap;
  display: flex;
  height: 80vh;
  width: 200vw;
  position: fixed;
  flex-direction: row;
  flex-wrap: nowrap;
}

.content_3 {
  font-size: 20px;
  margin-top: 3050px;
}

.card {
  background-color: red;
  color: white;
  white-space: nowrap;
  text-align: center;
  height: 300px;
  width: 300px;
  margin: 10px 30px 10px 10px;
}
<div class="content_1">
  <h1>First Page</h1>
</div>
<div class="content_2" id="content_2">
  <div class="card" style="background-color: #FF7A7A;">Card-1</div>
  <div class="card" style="background-color: #FF3C3C;">Card-2</div>
  <div class="card">Card-3</div>
  <div class="card" style="background-color: #FF3600;">Card-4</div>
  <div class="card" style="background-color: #FF871C;">Card-5</div>
  <div class="card" style="background-color: #FFA91C;">Card-6</div>
  <div class="card" style="background-color: #FFC11D;">Card-7</div>
  <div class="card" style="background-color: #FFF81D;">Card-8</div>
</div>
<div class="content_3">
  <p>Senectus purus, molestie blandit sociis eu leo blandit platea commodo aptent scelerisque cursus. Hac vel himenaeos hendrerit eu pellentesque. Lorem natoque praesent dictum porta, aliquam bibendum laoreet class litora? Class nullam maecenas aliquet.
    Ligula, et enim vel rutrum luctus lorem orci fringilla in erat? Bibendum magnis nec volutpat non netus dignissim. Tempus tempor penatibus nulla egestas semper scelerisque cubilia. Nulla adipiscing per porta consequat et imperdiet posuere magna fringilla
    rhoncus conubia. Sapien proin euismod.
  </p>
  <p>Tempus luctus tempor donec pretium lectus leo facilisis leo, inceptos nostra lorem vel. Orci parturient urna etiam pharetra sit lacus volutpat id sed lacinia. Scelerisque ultrices nisi risus aenean tincidunt, amet arcu tempus id curabitur purus fringilla.
    Eros iaculis vitae vitae rutrum ultricies dolor sociis ante ante ut. Ut nibh primis himenaeos egestas dictumst congue scelerisque!
  </p>
  <p>Blandit sociis quisque ultrices montes tortor. Penatibus risus primis, senectus nam nostra. Egestas, nulla vitae penatibus cursus sed. Luctus, eget dignissim porttitor et curae; accumsan. Accumsan blandit ligula sollicitudin. Ligula mattis ad turpis
    arcu mus laoreet conubia risus accumsan quis lobortis. Nisi sollicitudin penatibus lacus nam justo id commodo sagittis. Leo orci.
  </p>

  <p>Fringilla sociosqu laoreet id, dui lobortis condimentum? Facilisis non, cubilia diam. Egestas aptent ornare et felis morbi senectus molestie, egestas donec himenaeos ultrices himenaeos. Condimentum conubia nisl urna lobortis pharetra adipiscing cras
    eget pellentesque sollicitudin faucibus. Scelerisque lobortis nascetur neque ac quam dignissim fames. Magnis pharetra dignissim nullam sapien eu curabitur, ridiculus dapibus. Aptent tempus nibh eget scelerisque magna ipsum turpis. Taciti nostra morbi
    pharetra montes sagittis posuere mollis.
  </p>
  <p>Taciti tortor phasellus placerat inceptos tristique consectetur accumsan vitae potenti sodales nulla eros. Dapibus scelerisque penatibus nisl accumsan ultricies ridiculus porta. Varius tellus erat laoreet morbi tempor tristique. Sapien, sem morbi libero
    dapibus curabitur. Facilisi habitasse feugiat semper magnis risus id tellus libero semper. Vehicula turpis elit lectus interdum metus ultrices mollis consectetur cubilia.
  </p>
  <p>Senectus purus, molestie blandit sociis eu leo blandit platea commodo aptent scelerisque cursus. Hac vel himenaeos hendrerit eu pellentesque. Lorem natoque praesent dictum porta, aliquam bibendum laoreet class litora? Class nullam maecenas aliquet.
    Ligula, et enim vel rutrum luctus lorem orci fringilla in erat? Bibendum magnis nec volutpat non netus dignissim. Tempus tempor penatibus nulla egestas semper scelerisque cubilia. Nulla adipiscing per porta consequat et imperdiet posuere magna fringilla
    rhoncus conubia. Sapien proin euismod.
  </p>

  <p>Tempus luctus tempor donec pretium lectus leo facilisis leo, inceptos nostra lorem vel. Orci parturient urna etiam pharetra sit lacus volutpat id sed lacinia. Scelerisque ultrices nisi risus aenean tincidunt, amet arcu tempus id curabitur purus fringilla.
    Eros iaculis vitae vitae rutrum ultricies dolor sociis ante ante ut. Ut nibh primis himenaeos egestas dictumst congue scelerisque!
  </p>
  <p>Blandit sociis quisque ultrices montes tortor. Penatibus risus primis, senectus nam nostra. Egestas, nulla vitae penatibus cursus sed. Luctus, eget dignissim porttitor et curae; accumsan. Accumsan blandit ligula sollicitudin. Ligula mattis ad turpis
    arcu mus laoreet conubia risus accumsan quis lobortis. Nisi sollicitudin penatibus lacus nam justo id commodo sagittis. Leo orci.
  </p>
  <p>Fringilla sociosqu laoreet id, dui lobortis condimentum? Facilisis non, cubilia diam. Egestas aptent ornare et felis morbi senectus molestie, egestas donec himenaeos ultrices himenaeos. Condimentum conubia nisl urna lobortis pharetra adipiscing cras
    eget pellentesque sollicitudin faucibus. Scelerisque lobortis nascetur neque ac quam dignissim fames. Magnis pharetra dignissim nullam sapien eu curabitur, ridiculus dapibus. Aptent tempus nibh eget scelerisque magna ipsum turpis. Taciti nostra morbi
    pharetra montes sagittis posuere mollis.
  </p>
  <p>Taciti tortor phasellus placerat inceptos tristique consectetur accumsan vitae potenti sodales nulla eros. Dapibus scelerisque penatibus nisl accumsan ultricies ridiculus porta. Varius tellus erat laoreet morbi tempor tristique. Sapien, sem morbi libero
    dapibus curabitur. Facilisi habitasse feugiat semper magnis risus id tellus libero semper. Vehicula turpis elit lectus interdum metus ultrices mollis consectetur cubilia.
  </p>
</div>


感谢您的时间。使用“position fixed”,我做了与您完全相同的事情,这是我最好的尝试。但是与您的一样,在全屏模式下存在问题。模块会保持在容器顶部,因为它在屏幕中央。 :/ - crg
@crg 你的意思是由于position:fixed,块在滚动回到相同的坐标位置后没有保留其原始顶部位置。这就是为什么我在IF条件中根据window.scrollY的值设置了一些约束条件,以便元素的位置在下一个段落开始或第一页块结束时立即更改。 - ac_mmi
@crg 我的没有任何故障。 - ac_mmi
1
@crg 我在 Firefox 和 Chrome 中尝试了我的代码,它可以正常工作。在你的视频中,滚动是通过向上推元素开始的。为了解决这个问题,你需要在想要水平滚动效果开始和结束时检查 scrollY 值,并通过在检查中使用 console.log(window.scrollY) 并将其放入 IF 条件的限制中来进行替换。 - ac_mmi
好的,我会尝试。我刚在 Chrome 上看了一下,它正常工作。我之前是在 Microsoft Edge v85 上使用。 - crg
显示剩余4条评论

2

    $(window).scroll(function() {
        var sectionHeight = $(window).height();
        var sectionWidth = $(window).width();
        var section3Width = sectionWidth * 3;
        var totalHeight = sectionHeight * 2
        var totalSection3Width = section3Width * 2
        if ($(document).scrollTop() > totalHeight) {
            //alert("1");
            window.scrollBy(sectionWidth, 0);
            $("body").css("overflow-y", "hidden", "overflow-x", "scroll");
         }
           
    });
.section {
display: block;
width: 100%;
height: 100vh;
}
.section1 {
background: red;
}
.section2 {
background: yellow;
}
.section3 {
display: block;
overflow-x: scroll;
overflow-y: hidden;
}
.scroll-y {width: calc(100vw * 3);display: flex;}


.secitem {
display: inline-block;
height: 100vh;
width: 100vw;
}
.secitem1{
background: green;}
.secitem2 {
background: skyblue;
}
.secitem3 {
background: blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="section section1"></div>
<div class="section section2"></div>
<div class="section section3">
<div class="scroll-y">
<div class="secitem secitem1"></div>
<div class="secitem secitem2"></div>
<div class="secitem secitem3"></div>
</div>
</div>


0
为了让它在所有浏览器上都能工作,我最终使用了pageYOffsetgetBoundingClientRect等其他函数来检测我的项目行在窗口的X/Y位置。
在这里查看完整结果cargouet.com
export default class ProjectsCards extends Component {
    constructor() {
        super();
        this.handleScroll = this.handleScroll.bind(this);
        this.heightIsSet = false
    }

    componentDidMount() {
        if (window.matchMedia("(max-width: 991px)").matches) return
        window.addEventListener('scroll', this.handleScroll, true)
        setTimeout(() => {
            this.offsetTop = window.pageYOffset + document.querySelector(".projectsContainer").getBoundingClientRect().top;
        }, 2000)
    }

    handleScroll() {
        const rowProjects = document.querySelector(".row.projects"),
            projectsContainer = document.querySelector(".projectsContainer"),
            wrapper = document.querySelector(".projectsWrapper"),
            projectsCard = document.querySelectorAll(".row.projects .pcard"),
            scrolledY = window.scrollY,
            lastCardFromRightSideOfTheScreen = projectsCard[projectsCard.length - 1].getBoundingClientRect().right + 100;
            rowProjects.style.willChange = 'transform';

        if ((scrolledY > this.offsetTop && lastCardFromRightSideOfTheScreen > rowProjects.offsetWidth) ||
            (projectsContainer.getBoundingClientRect().y > 0 && lastCardFromRightSideOfTheScreen <= rowProjects.offsetWidth)) {
            projectsContainer.classList.remove("absolute")
            projectsContainer.classList.add("sticky")
            // Get wrapper height
            if(!this.heightIsSet) this.childConainterFromParent = (this.offsetTop - wrapper.getBoundingClientRect().top) - (this.offsetTop - projectsContainer.getBoundingClientRect().top)
            // Set X scroll speed 
            rowProjects.style.transform = "translateX(" + -(scrolledY - this.offsetTop) * 0.55 + "px)"
        } else if (lastCardFromRightSideOfTheScreen <= rowProjects.offsetWidth) {
            this.heightIsSet = true
            // Set wrapper height
            wrapper.style.height = window.innerHeight + this.childConainterFromParent + 'px'
            projectsContainer.classList.remove("sticky")
            projectsContainer.classList.add("absolute")
        } else {
            if(projectsContainer.classList.contains("absolute") || projectsContainer.classList.contains("sticky")) {
                rowProjects.style.transform = "translateX(0)"
                projectsContainer.classList.remove("sticky")
                projectsContainer.classList.remove("absolute")
            }
        }
    }

    render() {
        return (
            <section id="project" className="d-flex align-items-center">
                <div className="projectsWrapper">
                    <div className="projectsContainer">
                        <div className="row projects">
                            <Project  />
                            <Project  />
                            <Project  />
                            <Project  />
                            <Project  />
                        </div>
                    </div>
                </div>
            </section>
        );
    }
}

0

另一个版本:

$(window).scroll(function() {
        var sectionHeight = $(window).height();
        var sectionWidth = $(window).width();
        var section3Width = sectionWidth * 3;
        var totalHeight = sectionHeight * 2
        var totalSection3Width = section3Width * 2
        if ($(document).scrollTop() > totalHeight) {
            //alert("1");
          if(window.scrollBy(0, 0)){
            window.scrollBy(sectionWidth, 0);
            $("body").css("overflow-y", "hidden", "overflow-x", "scroll");
          } 
            
         }
           
    });
.section {
display: block;
width: 100%;
height: 100vh;
}
.section1 {
background: red;
}
.section2 {
background: yellow;
}
.section3 {
display: block;
overflow-x: scroll;
overflow-y: hidden;
}
.scroll-y {width: calc(100vw * 3);display: flex;}


.secitem {
display: inline-block;
height: 100vh;
width: 100vw;
}
.secitem1{
background: green;}
.secitem2 {
background: skyblue;
}
.secitem3 {
background: blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="section section1"></div>
<div class="section section2"></div>
<div class="section section3">
<div class="scroll-y">
<div class="secitem secitem1"></div>
<div class="secitem secitem2"></div>
<div class="secitem secitem3"></div>
  </div>
  
</div>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接