【问题标题】:Smooth Scrolling Interferes with Hash Mark平滑滚动干扰哈希标记
【发布时间】:2012-10-30 04:03:48
【问题描述】:

编辑(2012 年 12 月 26 日)

我发现以下代码完全符合我的要求,除了现在页面的 URL 有一个尾部斜杠(例如 example.com/page/)时,页面不会滚动。如果页面的 URL 以“.php”或“.html”等结尾,则可以正常工作。关于如何让以下脚本与 URL 中的尾部斜杠一起工作有什么想法吗?

jQuery('a[href*=#]').bind('click', function(e) {
    // Get the target
    var target = jQuery(this).attr("href"); 

    // prevent the "normal" behaviour which would be a "hard" jump
    e.preventDefault(); 

    // perform animated scrolling by getting top-position of target-
    // element and set it as scroll target
    jQuery('html, body').stop().animate({
        scrollTop: jQuery(target).offset().top 
    }, 500, function() {
        location.hash = target;  //attach the hash (#jumptarget) to the pageurl
    });

    return false;
});

过去几年我一直在成功使用脚本,但最近遇到了一些问题。基本上脚本所做的是将页面滚动到特定点。这发生在链接锚点上。例如,如果一个链接是:

<a href="#anchor">anchor link</a>

页面将平滑地滚动到页面上的那个锚点:

<a name="anchor"></a>

或者:

<a id="anchor"></a>

在页面中使用其他一些 JS 时出现的问题需要将链接格式化为:

<a href="#">other link</a>

当点击这个“其他链接”时,页面会平滑滚动,但是会滚动到没有锚点的页面顶部或底部。

点击这个“其他链接”会发生什么?应该发生其他 JS 动作(它确实发生了),但不应该发生平滑页面滚动脚本。

这是我获得此脚本的工作示例:

http://www.dezinerfolio.com/wp-content/uploads/smoothscrolldemo/df_smooth_scroll.html

这是完整的 JS:

Scroller = {
    // control the speed of the scroller.
    // dont change it here directly, please use Scroller.speed=50;
    speed: 10,

    // returns the Y position of the div
    gy: function (d) {
        gy = d.offsetTop
        if (d.offsetParent) while (d = d.offsetParent) gy += d.offsetTop
        return gy
    },

    // returns the current scroll position
    scrollTop: function (){
        body = document.body
        d = document.documentElement

        if (body && body.scrollTop) return body.scrollTop
        if (d && d.scrollTop) return d.scrollTop
        if (window.pageYOffset) return window.pageYOffset

        return 0
    },

    // attach an event for an element
    // (element, type, function)
    add: function(event, body, d) {
        if (event.addEventListener) return event.addEventListener(body, d,false)
        if (event.attachEvent) return event.attachEvent('on'+body, d)
    },

    // kill an event of an element
    end: function(e){
        if (window.event) {
            window.event.cancelBubble = true
            window.event.returnValue = false

            return;
        }

        if (e.preventDefault && e.stopPropagation) {
          e.preventDefault()
          e.stopPropagation()
        }
    },

    // move the scroll bar to the particular div.
    scroll: function(d){
        i = window.innerHeight || document.documentElement.clientHeight;
        h = document.body.scrollHeight;
        a = Scroller.scrollTop()

        if (d>a)
            if(h-d>i)
                a += Math.ceil((d-a)/Scroller.speed)
            else
                a += Math.ceil((d-a-(h-d))/Scroller.speed)
        else
            a = a + (d-a)/Scroller.speed;

        window.scrollTo(0,a)

        if (a==d || Scroller.offsetTop==a)
            clearInterval(Scroller.interval)

        Scroller.offsetTop = a
    },

    // initializer that adds the renderer to the onload function of the window
    init: function(){
        Scroller.add(window,'load', Scroller.render)
    },

    // this method extracts all the anchors and validates then as # and attaches the events.
    render: function(){
        a = document.getElementsByTagName('a');

        Scroller.end(this);

        window.onscroll

        for (i=0;i<a.length;i++) {
            l = a[i];

            if (l.href && l.href.indexOf('#') != -1 && ((l.pathname==location.pathname) || ('/'+l.pathname==location.pathname)) ){
                Scroller.add(l,'click',Scroller.end)

                l.onclick = function(){
                    Scroller.end(this);

                    l = this.hash.substr(1);
                    a = document.getElementsByTagName('a');

                    for (i=0;i<a.length;i++) {
                       if (a[i].name == l){
                            clearInterval(Scroller.interval);

                            Scroller.interval = setInterval('Scroller.scroll('+Scroller.gy(a[i])+')',10);
                        }
                    }
                }
            }
        }
    }
}

// invoke the initializer of the scroller
Scroller.init();

我认为有一种方法可以编写脚本,这样如果href 等于哈希标记#,在哈希之后没有任何文本,则不会触发滚动条。

有没有人有更好的想法?

提前致谢!

【问题讨论】:

  • 欢迎来到 SO,亚当。首先,我会避免您找到的代码。它有各种各样的问题,并且看起来(对我来说)是由一个陷入 Javascript 代码写得不太好的时期的人编写的,或者是由某个人编写的。你会看到我通过并尝试格式化它以便更容易阅读,但是天哪,它有一堆荒谬的东西和编码风格。让我看看我是否能找到一个纯 JS 平滑滚动脚本,它使用 Javascript 中的“现代”编码方式更新。
  • (附带说明,this is really common in jQuery。如果您已经在使用它或其他类似的库/框架。)
  • 感谢@Jared Farrish,感谢您的帮助!我也有其他意见认为我使用的脚本很旧。 :)

标签: javascript smooth-scrolling


【解决方案1】:

我无法为您的 jQuery 函数提供帮助,但您的原始脚本有两个简单的解决方案。第一个是一个小的修改,告诉脚本忽略锚的 URL 是 only 哈希标记的特殊情况。

render函数中,换行:

if (l.href 
    && l.href.indexOf('#') != -1 
    && (l.pathname == location.pathname
        || '/' + l.pathname == location.pathname)
) {

收件人:

if (l.href
    && l.href != '#' // <<< Added this conditional >>>
    && l.href.indexOf('#') != -1
    && (l.pathname == location.pathname
        || '/' + l.pathname == location.pathname)
){

这将告诉脚本忽略特殊情况,但不会阻止浏览器对链接做出正常反应,因此浏览器仍可能跳转到页面顶部。您提到的特殊情况几乎总是在 javascript 构造中用于提供具有 href 属性的锚标记,因为一些较旧的浏览器会忽略没有标记的标记。 '#' 用作 URL 以防止链接离开页面。

您可以在链接中使用空的 javascript 调用来代替“#”,如下所示:

<a href="javascript:;">other link</a>

这将完全避免您对滚动条的问题。

【讨论】:

  • 我重新格式化了条件块,以便更明显地看到修改/添加/删除的内容。请注意,我既不批评也不提倡使用href="javascript:;",但有,呃,an interesting question with many opinionated answers 的主题。就个人而言,出于优雅降级的原因,我可能会在附加事件侦听器时删除href 属性。但这只是我。
  • 对不起,我没有早点回复。出于某种原因,我没有收到来自 SO 的电子邮件通知。我确实找到了这个问题的答案。我很快就会在这里发布代码......
【解决方案2】:

再次感谢贾里德,感谢您的帮助!我确实遇到了一个脚本,它正是我想要的。这是我发现的更好的脚本:

jQuery('a[href*=#]').bind('click', function(e) {
    e.preventDefault(); //prevent the "normal" behaviour which would be a "hard" jump
    var target = jQuery(this).attr("href"); //Get the target
    // perform animated scrolling by getting top-position of target-element and set it as scroll target
    jQuery('html, body').stop().animate({ scrollTop: jQuery(target).offset().top }, 1000, function() {
        location.hash = target;  //attach the hash (#jumptarget) to the pageurl
    });
    return false;
});

【讨论】:

    猜你喜欢
    • 2018-10-16
    • 2015-12-16
    • 1970-01-01
    • 2013-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-14
    • 2018-11-26
    相关资源
    最近更新 更多