简体   繁体   English

返回上一页相同的滚动条 position 使用 jquery 在页面上延迟加载图像

[英]Back to previous page same scroll position with lazy load images on page using jquery

Working on scroll position when user goes back to the previous page then same scroll position of the product will show.当用户返回上一页时,在滚动 position 上工作,然后将显示产品的相同滚动 position。 I have tried like this我试过这样

$('.test').on('click', function(e){

        stateData = {
            path: window.location.href,
            scrollTop: $(window).scrollTop()
        };
        const url = new URL(window.location);
        window.history.replaceState(stateData, '', url);
        stateData = {
            path: window.location.href,
            scrollTop: 0
        };
        window.history.pushState(stateData, '', url);
        e.preventDefault();;
    });

But here I'm not getting the exact position due to lazy load images to scroll moving at the bottom of the page.但在这里我没有得到准确的 position,因为延迟加载图像在页面底部滚动移动。 Can anyone suggest to me how to handle it?谁能建议我如何处理它?

In my view, the reason you are not able to reach the exact position is due to image rendering later thus changing the height of the screen.在我看来,您无法达到确切的 position 的原因是图像渲染稍后会改变屏幕的高度。 What if you add a skeleton for all the images to be loaded, that can help you to make the screen height similar to that of the one you have when everything is loaded.如果您为所有要加载的图像添加骨架,那会怎样?这可以帮助您使屏幕高度与加载所有内容时的屏幕高度相似。

Perhaps save the scroll position in localStorage and then go to it when the page is reloaded?也许将滚动 position 保存在localStorage中,然后在重新加载页面时将 go 保存到它?

as seen here这里所见

Check if the key exists (and if it does - scroll to it) right after DOMContentLoaded , i think, otherwise it will wait for all the images to load.DOMContentLoaded之后检查密钥是否存在(如果存在 - 滚动到它),我认为,否则它将等待所有图像加载。

You can also choose to save the scroll position after every scroll, and not only on unload您还可以选择在每次滚动后保存卷轴 position,而不仅仅是在unload

Maybe someone can figure out how to use https://developer.mozilla.org/en-US/docs/Web/API/History/scrollRestoration .. but my basic idea is to remember the scrollTop for each page.也许有人可以弄清楚如何使用https://developer.mozilla.org/en-US/docs/Web/API/History/scrollRestoration .. 但我的基本想法是记住每个页面的 scrollTop。 This means we have to include a value for each URL, upon returning to a page we then need load the lazy items that establish the proper scrollTop.这意味着我们必须为每个 URL 包含一个值,返回页面后我们需要加载建立适当滚动顶部的惰性项目。

I have used this MDN example and this debounce script as base and will only provide the necessary code changes - I included a number of images on "first_page" and "second_page".我使用了这个 MDN 示例和这个 去抖动脚本作为基础,并且只会提供必要的代码更改——我在“first_page”和“second_page”上包含了一些图像。 I used to provide link to a working example, but this was taken offline.我曾经提供一个工作示例的链接,但现在已经离线了。

js/lazyload.js js/lazyload.js

'use strict';
// supports older browsers - no arrow functions, spread syntax or such *sigh*
var pLAZY = ( function(){
    var version = "1.1.1"
        , loadOffset = 512
        , animatable = [ "IMG", "IFRAME" ] // tags that may/should be animated, e.g. *not* SOURCE
        , loadingClasses = [] // [ 'animated', 'rubberBand' ] // change/disable animation style here
        , lazyItems = {}
        , lazyHandler_scroll = null
        , lazyHandler_resize = null
        , forceLoad_timer = null
    ;

    function _debug(){ if( arguments.length ){ debug = parseInt( arguments[0] ); } return debug; }
    function _version(){ return version; }
    function docScroll(){ return window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0; } // cross-browser
    function winHeight(){ return window.innerHeight || document.documentElement.clientHeight; }

    function findLazyItems(){
        lazyItems = {};
        var candidates = document.querySelectorAll( '.lazyload,img[data-src],iframe[data-src],source[data-srcset]' );
        for( var idx = 0; idx < candidates.length; idx++ ){
            var domEl = candidates[idx]
                , curTop = domEl.offsetTop // if you fail to ensure lazy loaded items do not force a reflow lower items may be loaded sooner
            ;
            if( lazyItems.hasOwnProperty( curTop ) ){
                lazyItems[curTop].push( domEl );
            }else{
                lazyItems[curTop] = [ domEl ];
            }
        }
    }

    function loadLazy(item){
        var dsrc = item.getAttribute( 'data-src' )
            , dset = item.getAttribute( 'data-srcset' )
            , changed = false
            , worked = false
        ;
        if( dsrc && dsrc.length ){
            item.setAttribute( 'src', dsrc );
            item.removeAttribute( 'data-src' );
            changed = true;
        }
        if( dset && dset.length ){
            item.setAttribute( 'srcset', dset );
            item.removeAttribute( 'data-srcset' );
            changed = true;
        }
        if( changed ){
            worked = true;
            if( animatable.includes( item.nodeName ) ){
                for( var lcx = 0; lcx < loadingClasses.length; lcx++ ){
                    item.classList.add( loadingClasses[lcx] );
                }
            }
        }
        return worked;
    }

    function checkShowItems(){
        var curVisBar = docScroll() + winHeight() + loadOffset // winHeight, not docHeight!!
            , worked = false
            , str_pagePos = "0"
        ;
        for( str_pagePos in lazyItems ){ // pagePos is a DOM.position().top value
            var pagePos = parseInt( str_pagePos );
            var lazy = lazyItems[ pagePos ]; // the items are constantly refreshed, double-effort is considered negligible
            if( pagePos <= curVisBar ){
                for( var idx = 0; idx < lazy.length; idx++ ){
                    if( loadLazy( lazy[idx] ) ) worked = true;
                }
            }
        }
        if( worked ){
            findLazyItems();
            if( Object.keys( lazyItems ).length == 0 ){
                window.removeEventListener( 'scroll', lazyHandler_scroll );
                window.removeEventListener( 'resize', lazyHandler_resize ); // this is not required anymore either
            }
        }
    }

    function waitForLoad(index,callback){
        let count = 0
            , done = 0
            , str_pagePos = "0"
            , worked = false
        ;
        for( str_pagePos in lazyItems ){
            var lazy = lazyItems[ parseInt( str_pagePos ) ];
            for( let lx = 0; lx < lazy.length; lx++ ){
                if( count <= index ){
                    if( lazy[lx].complete ) done++;
                    count++;
                }
            }
        }
        if( done == index ){
            window.clearInterval( forceLoad_timer );
            forceLoad_timer = null;
            checkShowItems();
            if(callback) callback();
        }//else{ console.log( "%d/%d images done.", done, index ); }
    }

    function forceLoad(index,callback){
        let count = 0
            , str_pagePos = "0"
            , worked = false
        ;
        for( str_pagePos in lazyItems ){
            var lazy = lazyItems[ parseInt( str_pagePos ) ];
            for( let lx = 0; lx < lazy.length; lx++ ){
                if( count <= index ){
                    if( loadLazy( lazy[lx] ) ) worked = true;
                    count++;
                }
            }
        }
        forceLoad_timer = window.setInterval( function(){ waitForLoad(index,callback); }, 50 );

    }

    function lowestSeenImage(){
        var curVisBar = docScroll() + winHeight() + loadOffset // winHeight, not docHeight!!
            , str_pagePos = "0"
            , count = 0
        ;
        for( str_pagePos in lazyItems ){
            var pagePos = parseInt( str_pagePos );
            var lazy = lazyItems[ pagePos ];
            if( pagePos <= curVisBar ){
                count += lazy.length;
            }
        }
        return count;
    }

    function duringResizing(){
        findLazyItems();
        checkShowItems();
    }

    function hookListener( evtName, callback ){
        var throttleTimer = arguments.length > 2 ? parseInt( arguments[2] ) : 250;
        if( "Cowboy" in window ){
            window.addEventListener( evtName, Cowboy.throttle( throttleTimer, callback ) );
        }else{
            //console.log( "without the Ben 'Cowboy' Almann throttle plugin we may choke the responsiveness of the user interface" );
            window.addEventListener( evtName, callback );
        }
    }

    function initialise(){
        findLazyItems();
        var seeTBjquery = ( ( "jQuery" in window ) && $.isFunction( $.throttle ) )
            , seeTBplain = ( ( "Cowboy" in window ) && ( "throttle" in window.Cowboy ) )
        ;
        if( seeTBjquery ){
            lazyHandler_scroll = $.throttle( 250, checkShowItems );
            lazyHandler_resize = $.throttle( 250, duringResizing );
        }else{
            if( seeTBplain ){
                lazyHandler_scroll = Cowboy.throttle( 250, checkShowItems );
                lazyHandler_resize = Cowboy.throttle( 250, duringResizing );
            }else{
                lazyHandler_scroll = checkShowItems;
                lazyHandler_resize = duringResizing;
            }
        }
        window.addEventListener( 'scroll', lazyHandler_scroll );
        window.addEventListener( 'resize', lazyHandler_resize );
        checkShowItems();
    }

    if( ! window.hasOwnProperty( "_pLAZY_disable_autoInit" ) ){
        document.addEventListener( "DOMContentLoaded", function(){
            initialise();
        } );
    }

    return {
        "debug": _debug
        , "version": _version
        , "findLazyItems": findLazyItems
        , "checkShowItems": checkShowItems
        , "forceLoad": forceLoad
        , "lowestSeenImage": lowestSeenImage
        , "duringResizing": duringResizing
        , "hookListener": hookListener
        , "initialize": initialise // american spelling
        , "initialise": initialise
    };

} )();

js/ajax_nav.js js/ajax_nav.js

"use strict";

const ajaxRequest = new (function () {

    function closeReq () {
        oLoadingBox.parentNode && document.body.removeChild(oLoadingBox);
        bIsLoading = false;
    }

    function abortReq () {
        if (!bIsLoading) { return; }
        oReq.abort();
        closeReq();
    }

    function ajaxError () {
        alert("Unknown error.");
    }

    // NOT PART OF MDN EXAMPLE::
    function restoreScroll(){
        if( oPageInfo.url in oPageInfo.scrollTop ){
            window.scrollTo( 0, oPageInfo.scrollTop[oPageInfo.url] ); // always left-most
        }
    }
    function loadAndScroll(){
        if( "pLAZY" in window ) pLAZY.forceLoad( oPageInfo.lowestSeenImage[oPageInfo.url], restoreScroll ); 
    }
    // ::NOT PART OF MDN EXAMPLE

    function ajaxLoad () {
        var vMsg, nStatus = this.status;
        switch (nStatus) {
            case 200:
                vMsg = JSON.parse(this.responseText);
                document.title = oPageInfo.title = vMsg.page;
                document.getElementById(sTargetId).innerHTML = vMsg.content;
                if (bUpdateURL) {
                    history.pushState(oPageInfo, oPageInfo.title, oPageInfo.url);
                    bUpdateURL = false;
                    // NOT PART OF MDN EXAMPLE::
                    if( "pLAZY" in window ){
                        window.pLAZY.initialise(); 
                        if( oPageInfo.lowestSeenImage[oPageInfo.url] > -1 ){ 
                            loadAndScroll(); 
                        }else{
                            restoreScroll();
                        }
                    }//else console.log("without pLAZY no scrollPos restore possible");
                    ajaxRequest.rebuildLinks();
                    // ::NOT PART OF MDN EXAMPLE
                }
                break;
            default:
                vMsg = nStatus + ": " + (oHTTPStatus[nStatus] || "Unknown");
                switch (Math.floor(nStatus / 100)) {
                    /*
                     case 1:
                     // Informational 1xx
                     console.log("Information code " + vMsg);
                     break;
                     case 2:
                     // Successful 2xx
                     console.log("Successful code " + vMsg);
                     break;
                     case 3:
                     // Redirection 3xx
                     console.log("Redirection code " + vMsg);
                     break;
                     */
                    case 4:
                        /* Client Error 4xx */
                        alert("Client Error #" + vMsg);
                        break;
                    case 5:
                        /* Server Error 5xx */
                        alert("Server Error #" + vMsg);
                        break;
                    default:
                        /* Unknown status */
                        ajaxError();
                }
        }
        closeReq();
    }

    function filterURL (sURL, sViewMode) {
        return sURL.replace(rSearch, "") + ("?" + sURL.replace(rHost, "&").replace(rView, sViewMode ? "&" + sViewKey + "=" + sViewMode : "").slice(1)).replace(rEndQstMark, "");
    }

    function getPage (sPage) {
        if (bIsLoading) { return; }
        oReq = new XMLHttpRequest();
        bIsLoading = true;
        oReq.onload = ajaxLoad;
        oReq.onerror = ajaxError;
        // NOT IN MDN EXAMPLE ::
        oPageInfo.scrollTop[oPageInfo.url] = document.documentElement.scrollTop;
        oPageInfo.lowestSeenImage[oPageInfo.url] = ( "pLAZY" in window ) ? pLAZY.lowestSeenImage() : 0;
        // :: NOT IN MDN EXAMPLE
        if (sPage) { oPageInfo.url = filterURL(sPage, null); }
        oReq.open("get", filterURL(oPageInfo.url, "json"), true);
        oReq.send();
        oLoadingBox.parentNode || document.body.appendChild(oLoadingBox);
    }

    function requestPage (sURL) {
        if (history.pushState) {
            bUpdateURL = true;
            getPage(sURL);
        } else {
            /* Ajax navigation is not supported */
            location.assign(sURL);
        }
    }

    function processLink () {
        if (this.className === sAjaxClass) {
            requestPage(this.href);
            return false;
        }
        return true;
    }

    function init () {
        oPageInfo.title = document.title;
        for (var oLink, nIdx = 0, nLen = document.links.length; nIdx < nLen; document.links[nIdx++].onclick = processLink);
    }

    const

    /* customizable constants */
        sTargetId = "ajax-content", sViewKey = "view_as", sAjaxClass = "ajax-nav",

    /* not customizable constants */
        rSearch = /\?.*$/, rHost = /^[^\?]*\?*&*/, rView = new RegExp("&" + sViewKey + "\\=[^&]*|&*$", "i"), rEndQstMark = /\?$/,
        oLoadingBox = document.createElement("div"), oCover = document.createElement("div"), oLoadingImg = new Image(),
        oPageInfo = {
            title: null,
            scrollTop: {}, // NOT PART OF MDN EXAMPLE
            lowestSeenImage: {}, // NOT PART OF MDN EXAMPLE 
            url: location.href
        }, oHTTPStatus = /* http://www.iana.org/assignments/http-status-codes/http-status-codes.xml */ {
            100: "Continue",
            101: "Switching Protocols",
            102: "Processing",
            200: "OK",
            201: "Created",
            202: "Accepted",
            203: "Non-Authoritative Information",
            204: "No Content",
            205: "Reset Content",
            206: "Partial Content",
            207: "Multi-Status",
            208: "Already Reported",
            226: "IM Used",
            300: "Multiple Choices",
            301: "Moved Permanently",
            302: "Found",
            303: "See Other",
            304: "Not Modified",
            305: "Use Proxy",
            306: "Reserved",
            307: "Temporary Redirect",
            308: "Permanent Redirect",
            400: "Bad Request",
            401: "Unauthorized",
            402: "Payment Required",
            403: "Forbidden",
            404: "Not Found",
            405: "Method Not Allowed",
            406: "Not Acceptable",
            407: "Proxy Authentication Required",
            408: "Request Timeout",
            409: "Conflict",
            410: "Gone",
            411: "Length Required",
            412: "Precondition Failed",
            413: "Request Entity Too Large",
            414: "Request-URI Too Long",
            415: "Unsupported Media Type",
            416: "Requested Range Not Satisfiable",
            417: "Expectation Failed",
            422: "Unprocessable Entity",
            423: "Locked",
            424: "Failed Dependency",
            425: "Unassigned",
            426: "Upgrade Required",
            427: "Unassigned",
            428: "Precondition Required",
            429: "Too Many Requests",
            430: "Unassigned",
            431: "Request Header Fields Too Large",
            500: "Internal Server Error",
            501: "Not Implemented",
            502: "Bad Gateway",
            503: "Service Unavailable",
            504: "Gateway Timeout",
            505: "HTTP Version Not Supported",
            506: "Variant Also Negotiates (Experimental)",
            507: "Insufficient Storage",
            508: "Loop Detected",
            509: "Unassigned",
            510: "Not Extended",
            511: "Network Authentication Required"
        };

    var

        oReq, bIsLoading = false, bUpdateURL = false;

    oLoadingBox.id = "ajax-loader";
    oCover.onclick = abortReq;
    oLoadingImg.src = "data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQJCgAAACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkECQoAAAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQJCgAAACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQJCgAAACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAkKAAAALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA==";
    oCover.appendChild(oLoadingImg);
    oLoadingBox.appendChild(oCover);

    onpopstate = function (oEvent) {
        bUpdateURL = false;
        oPageInfo.title = oEvent.state.title;
        oPageInfo.scrollTop = oEvent.state.scrollTop; // NOT PART OF MDN EXAMPLE
        oPageInfo.lowestSeenImage = oEvent.state.lowestSeenImage; // NOT PART OF MDN EXAMPLE
        oPageInfo.url = oEvent.state.url;
        getPage();
    };

    window.addEventListener ? addEventListener("load", init, false) : window.attachEvent ? attachEvent("onload", init) : (onload = init);

    // Public methods

    this.open = requestPage;
    this.stop = abortReq;
    this.rebuildLinks = init;

})();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM