2016-08-19 109 views
1

我的任务是创建一个长页面,用户可以滚动浏览各种小文章。每篇文章部分都有一个类别,我需要使用URL来反映正在查看的类别。我知道history.pushState()可以在触发时用于更改URL。但这是我不清楚的后勤问题。如何在长卷页面上处理更改的URL?

我已经想出了一种方法来让主菜单链接跳转到适当的类别使用下面的代码,它似乎工作正常。

$('a.js-link').on('click',function (e) { 
    e.preventDefault; // dont actually follow the link 
    var category = $(this).data('category-id'); // get the id we should anchor to 
    location.hash = '#' + category; // jump to the location hash id 
    history.pushState("", "", category); // make the url pretty again 
    return false; // dont append #category to the pretty url 
}); 

然而,当用户滚动下来,一个新的类别开始出现的URL应该改变以example.com/category2(如1类为第一,将出现在初始页面加载),用户则保持滚动网址更改为example.com/category3。现在如果用户滚动回来,它应该改回example.com/category2。我只是在听滚动事件,然后检查一个元素是否在视口中?我如何处理页面上半部分显示前一个类别和下一个下半部分的情况?

我的其他障碍是如何处理直接链接到页面上的特定类别。如果用户直接链接到example.com/category5,则应该加载页面并将其锚定到category5部分。

我应该提到,我计划使用jquery.lazy.js来加载主容器div的类别,以减少初始页面加载时间。由于这个原因,我不能使用jquery向下滚动到一个元素,因为它会计算元素/页面的大小并向下滚动该数量,但是一旦内容被加载,它就不再是视图中适当的类别。尽管如果它主要影响更改URL的能力,我愿意改变这种方法。

对不起,对文本的墙!我不是在寻找某人为我编码,而是为了将我推向正确的方向!

+1

_Am我只是听滚动事件,然后检查是否一个元素在检视_是 - ?如果使用唯一的ID,页面将滚动到#ID的URL – mplungjan

+1

它应该是'e.preventDefault()'。 –

+0

@mplungjan它将是唯一的ID,但我需要的是在滚动内容时更改URL,而不是URL来滚动内容。 – cwal

回答

1

简短的回答是我通常使用history.replaceState()来实现这一点,但还有很多事情要做。 MDN描述了这种方法:

更新的历史堆栈上最新的条目有 指定的数据,标题,并且,如果提供的URL。数据被视为DOM不透明的 ;您可以指定任何可以序列化为 的JavaScript对象。

在实践中,这是如何解决的,我创建了一个状态对象,其状态是我的页面部分。我经常将这与优秀的Waypoints plugin一起使用,触发基于航点的状态更改。这段代码很容易理解,请阅读我的评论,这些评论将引导您阅读它。

// 1- Sets up state object that will store each page section 'state' 
var stateObj = { state0: "group" }; 

// 2- Setups up waypoint to indicate a new section 
var yourNameWaypoint = new Waypoint({ 

    // 3- Target an ID for waypoints to watch, corresponds to a page section 
    element: document.getElementById('page-id-target'), 
    handler: function(direction) { 

    // 4- Create down direction handler 
    if (direction === 'down') { 

     // 5- Assign stateObj a page state that corresponds to your page section 
     stateObj = { state1: "page-section-1" }; 
     history.replaceState(stateObj, "Section Title", "#new-page-section-slug-here"); 
    } 

    // 6- Do the same thing in the other direction now, reseting the URL to what it was before the waypoint was hit 
    if (direction === 'up') { 
     stateObj = { state0: "original-state" }; 
     history.replaceState(stateObj, "Original Page Section Title", "original-page-slug-here"); 
    } 
    } 
}); 

让哈希对应滚动位置有点困难。我修改了一个相当不错的脚本来使其工作(http://jsfiddle.net/ianclark001/rkocah23/),但我会在这里发布原文。

这个想法很简单。基本上,您正在读取您在init之内的上述函数中创建的每个网址哈希值,然后使用history.pushState()将这些网址哈希值在scrollToCurrent部分匹配。我发现我喜欢在滚动动画中加入一些延迟,以使行为更加正常(设置在500毫秒以下,但可以调整)。

(function(document, history, location) { 
    var HISTORY_SUPPORT = !!(history && history.pushState); 

    var anchorScrolls = { 
    ANCHOR_REGEX: /^#[^ ]+$/, 
    OFFSET_HEIGHT_PX: 50, 

    /** 
    * Establish events, and fix initial scroll position if a hash is provided. 
    */ 
    init: function() { 
     this.scrollToCurrent(); 
     $(window).on('hashchange', $.proxy(this, 'scrollToCurrent')); 
     $('body').on('click', 'a', $.proxy(this, 'delegateAnchors')); 
    }, 

    /** 
    * Return the offset amount to deduct from the normal scroll position. 
    * Modify as appropriate to allow for dynamic calculations 
    */ 
    getFixedOffset: function() { 
     return this.OFFSET_HEIGHT_PX; 
    }, 

    /** 
    * If the provided href is an anchor which resolves to an element on the 
    * page, scroll to it. 
    * @param {String} href 
    * @return {Boolean} - Was the href an anchor. 
    */ 
    scrollIfAnchor: function(href, pushToHistory) { 
     var match, anchorOffset; 

     if(!this.ANCHOR_REGEX.test(href)) { 
     return false; 
     } 

     match = document.getElementById(href.slice(1)); 

     if(match) { 
     anchorOffset = $(match).offset().top - this.getFixedOffset(); 
     $('html, body').delay(500).animate({ scrollTop: anchorOffset}); 

     // Add the state to history as-per normal anchor links 
     if(HISTORY_SUPPORT && pushToHistory) { 
      history.pushState({}, document.title, location.pathname + href); 
     } 
     } 

     return !!match; 
    }, 

    /** 
    * Attempt to scroll to the current location's hash. 
    */ 
    scrollToCurrent: function(e) { 
     if(this.scrollIfAnchor(window.location.hash) && e) { 
     e.preventDefault(); 
     } 
    }, 

    /** 
    * If the click event's target was an anchor, fix the scroll position. 
    */ 
    delegateAnchors: function(e) { 
     var elem = e.target; 

     if(this.scrollIfAnchor(elem.getAttribute('href'), true)) { 
     e.preventDefault(); 
     } 
    } 
    }; 

    $(document).ready($.proxy(anchorScrolls, 'init')); 
})(window.document, window.history, window.location); 
+0

谢谢!这是一个比我所希望的更完整的答案。我还没有机会尝试,但通读它看起来很强大。我确实有一个问题:是否有可能在URL中没有任何散列的情况下实现所有这些?所以,而不是example.com#category5我们可以有example.com/category5,仍然锚定下来? – cwal

+1

不用担心。我想你可以在不更新网址哈希的情况下做到这一点,但那么人们如何能够唯一地导航到特定区域?我的用例是围绕想要拥有唯一的URL来构建的,所以YMMV。 – staypuftman

+0

我完全同意,我认为我必须提出一个使用散列而不是“漂亮”URL的例子。我只是好奇,如果你有一个关于如何使这个脚本兼容的建议,而不使用散列。非常感激!! – cwal

相关问题