繁体   English   中英

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

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

当用户返回上一页时,在滚动 position 上工作,然后将显示产品的相同滚动 position。 我试过这样

$('.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();;
    });

但在这里我没有得到准确的 position,因为延迟加载图像在页面底部滚动移动。 谁能建议我如何处理它?

在我看来,您无法达到确切的 position 的原因是图像渲染稍后会改变屏幕的高度。 如果您为所有要加载的图像添加骨架,那会怎样?这可以帮助您使屏幕高度与加载所有内容时的屏幕高度相似。

也许将滚动 position 保存在localStorage中,然后在重新加载页面时将 go 保存到它?

这里所见

DOMContentLoaded之后检查密钥是否存在(如果存在 - 滚动到它),我认为,否则它将等待所有图像加载。

您还可以选择在每次滚动后保存卷轴 position,而不仅仅是在unload

也许有人可以弄清楚如何使用https://developer.mozilla.org/en-US/docs/Web/API/History/scrollRestoration .. 但我的基本想法是记住每个页面的 scrollTop。 这意味着我们必须为每个 URL 包含一个值,返回页面后我们需要加载建立适当滚动顶部的惰性项目。

我使用了这个 MDN 示例和这个 去抖动脚本作为基础,并且只会提供必要的代码更改——我在“first_page”和“second_page”上包含了一些图像。 我曾经提供一个工作示例的链接,但现在已经离线了。

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

"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