2016-08-19 105 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

相關問題