当用户滚动到某个部分时,更新位置哈希。

8
我希望当用户到达页面上的某个特定点时,更新window.location.hash值。例如,如果用户滚动到具有ID = 'about'的div,我希望URL更新。与单击自动滚动到页面锚点的链接相同,它会更新URL中的哈希值。
我设想通过检测元素是否可见来实现这一点,如果是,则更新window.location.hash = elementsID。欢迎其他建议。
我正在使用React并尝试避免JQuery,因此非常感谢使用vanilla JS的建议。谢谢。
编辑:
感谢建议。成功用纯JS编写了一个解决方案,并将其实现在React组件中。代码仍需要清理,但你已经了解了要领。
class HomeView extends React.Component{

    constructor () {
    super();

    this.state = {
      hash: '#'
    }

    this.elements = {}
  }

  componentDidMount(){
    this.scrollListener();
  }

  componentDidUpdate(prevProps){
    if(this.props.location.hash !== prevProps.location.hash){
        this.scrollToHash(this.props.location.hash)
    }

  }

  scrollListener(){
    window.addEventListener('scroll', (event) => {

        if(window.pageYOffset > 0 && window.pageYOffset < this.elements.about.offsetTop  - 200){
            const hash = '#';
            this.setState({hash: hash}, () => {
                history.pushState('', '', hash);
                this.updateHashState(hash);

            })

        } else if(window.pageYOffset > this.elements.about.offsetTop - 200 && window.pageYOffset < this.elements.skills.offsetTop - 200) {
            const hash = '#about';
            this.setState({hash: hash}, () => {
                history.pushState('', '', hash);
                this.updateHashState(hash);

            })

        } else if(window.pageYOffset > this.elements.skills.offsetTop - 200 && window.pageYOffset < this.elements.contact.offsetTop - 200) {
            const hash = '#skills';
            this.setState({hash: hash}, () => {
                history.pushState('', '', hash);
                this.updateHashState(hash);

            })

        }else if(window.pageYOffset > this.elements.skills.offsetTop - 200) {
            const hash = '#contact';
            this.setState({hash: hash}, () => {
                history.pushState('', '', hash);
                this.updateHashState(hash);

            })

        }

    })
  }

  updateHashState(hash) {
    switch(hash){
        case '#about':
            this.setState({
                forward: '#skills',
                back: '#'
            })
            break;
        case '#skills':
            this.setState({
                forward: '#contact',
                back: '#about'
            })
            break;
        case '#contact':
            this.setState({
                forward: '',
                back: '#skills'
            })
            break;
        default:
            this.setState({
                forward: '#about',
                back: ''
            })
            break;
    }
  }




    render(){

        return(
            ...
        )

    }

}

export default HomeView

如果div中有文本,滚动位置将无法正常工作。当浏览器窗口变窄时,文本会强制div变长,从而改变下面所有div的滚动位置。 - Kobbe
3
我很喜欢你要求使用React解决方案,而所有的答案都是jQuery的做法。 - pollx
3个回答

4

请看我的建议。jQuery代码会在文档加载后捕获所有<section>选择器,并在你滚动时从data-hash属性中设置适当的哈希值。

$(document).ready(function(){
  var sections = {};
  
  $(".section").each(function(){
   var hash = $(this).data("hash"),
            topOffset = $(this).offset().top;
        sections[topOffset] = hash;
  });
  
  $(window).scroll(function(e){
   var scrollTop = $(window).scrollTop();
        setHash(scrollTop);
  });
  
  function setHash(st){
   var hash = "";
   for(section in sections){
     if (section < st + ($(window).height()/2)) hash = sections[section];
    }
    console.log(`SETTING HASH: ${hash}`);
    window.location.hash = hash;
  }
});
section{
  position: relative;
  display: block;
  width: 100%;
  height: 800px;
  background: #fff;
  border-bottom: 1px solid #000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section class="section" data-hash="about">
  #about
</section>
<section class="section" data-hash="works">
  #works
</section>
<section class="section" data-hash="contact">
  #contact
</section>


这需要去抖动(debouncing)还是节流(throttling)吗?它不是在每个滚动像素上设置window.location.hash吗? - Mike

3

另一个想法是,通过取滚动值来更新哈希更加健壮。可以使用 scrollTop() 在 jQuery 中实现。

$(window).scroll(
    function(){
        if($(this).scrollTop() > 100 && $(this).scrollTop() < 200){
            window.location.hash = "your_hash_name";
        }else{
            window.location.hash = "";
        }
    }
);

当你在滚动(100, 200)像素之间时,这将更新location.hash的值。


你介意解释一下这个条件语句在检查什么吗?在这种情况下,$(this)指的是哪个元素? - Stretch0
1
scrollTop() 返回滚动值(即从顶部滚动到的位置)。 if 条件检查位置,假设您的 about id 距离顶部下方 100px,高度为 100px(这使其距离顶部为 100px200px),那么哈希将自行更改为 "your_hash_name",否则它将为空。 - Saharsh
很酷,谢谢。我已经用原生JS重写了这个。一旦我满意了,就会更新我的帖子。感谢你指引正确的方向。 - Stretch0

0

看一下这个。如果你需要一种获取滚动到的 div 的 id 的方式,请让我知道。Saharsh 上面写的可以起作用,但是如果你调整浏览器大小,并且 div 中有文本,则下面的 div 的滚动位置会改变。此外,请考虑响应式设计,在智能手机、平板电脑和桌面电脑上,div 的滚动位置将完全不同。我用一个按钮简化了我的示例,点击即可转到带有 id(test)的位置。如果您需要更多帮助来实践这个滚动位置,请告诉我。

<!DOCTYPE html>
<html>
    <head>
        <script src="http://code.jquery.com/jquery-latest.min.js"></script>
        <script>
        $(document).ready(function(){
            $("button").click(function(){
                window.location.href = "#test";
            });
        });
        </script>
    </head>
    <body>
    <div style="background:#aaf;width:100%;height:400px;"><button>Go To Test</button></div>
    <div style="background:#afa;width:100%;height:400px;" id="test"></div>
    </body>
</html>

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