Обратный вызов Fadein не работает должным образом с данными json, загруженными ajax

Это страница дизайнерского портфолио. При загрузке данные JSON извлекаются через ajax, и один из ключей используется для создания списка «.project-links» (при загрузке проект не отображается, а изображения проекта загружаются только при выборе проекта ( см. функцию showProj)). Мой вопрос касается постепенного появления/исчезновения: изображения все еще рисуются на экране после завершения постепенного появления, несмотря на то, что содержимое проекта определяется/загружается в обратном вызове fadeOut; может кто-нибудь просветить меня, как я могу настроить это так, чтобы fadeIn не запускался до тех пор, пока не будут загружены projImages?

Спасибо, свс.

function ajaxReq() {
    var request = new XMLHttpRequest();
    return request;
}


function makeLinks(projects) { // result = getJsonData > request.responseText
    var projectList = document.getElementById("project-list");

    for (var project in projects) {
        if (projects[project].status !== "DNU") {
            var projectId = projects[project].id;
            var listItem = "<li><a class=\"project-link\" id=\""+projects[project].project+"\" href=\"#\">" + projects[project].project + "</a></li>";
            projectList.innerHTML += listItem;
        } // if !DNU
    }

    // ADD EVENT LISTENERS
    var projLink = document.getElementsByClassName("project-link");
    for (var i = 0; i < projLink.length; i++) {
        var projId = projLink[i].id;
        //projLink[i].dataset.projIx = [i];
        projLink[i].addEventListener("click", showProject, false);
    }


    var showNext = document.getElementById("show-next");
    var showPrev = document.getElementById("show-previous");
    showNext.addEventListener("click", showProject, false);
    showPrev.addEventListener("click", showProject, false);

    // ARROW KEYS [not invoking the showProject function]
    $(document).keydown(function(e) {
        if(e.which==37) { // LEFT arrow
            $(showPrev).click(showProject);
            console.log("previous");
        } else
        if(e.which==39) { // RIGHT arrow
            $(showNext).click(showProject);
            console.log("next");
        }
    })


    function showProject(projId) {

        var intro = document.getElementById("intro");
        if (intro) {
            intro.parentNode.removeChild(intro);
        }
        projId.preventDefault();

        var projLinks = document.getElementsByClassName("project-link"); // array

        var selIx = $(".selected").index();


        // ###### CLICK PREVIOUS/NEXT ######
        if (this.id === "show-previous" || this.id === "show-next") {

            // 1a. if nothing is .selected
            if (selIx < 0) {
                if (this.id === "show-previous") {
                    var selIx = projLinks.length-1;
                }
                else if (this.id === "show-next") {
                    var selIx = 0;
                }
            }

            // 1b. if .selected:
            else if (selIx > -1) {
                if (this.id === "show-previous") {
                    if (selIx === 0) { // if @ first slide
                        selIx = projLinks.length-1;
                    }
                    else {
                        selIx --;
                    }
                }
                else if (this.id === "show-next") {
                    if (selIx === projLinks.length-1) { // if @ last slide
                        selIx = 0;
                    }
                    else {
                        selIx ++;
                    }
                }
            }
            var selProjLi = projLinks[selIx]; // => li
        } // click previous/next


        // ###### CLICK .project-link ######
        else if (this.id !== "show-previous" && this.id !== "show-next") {
            var selIx = $(this).closest("li").index();
        }


        // FADE OUT, CALLBACK: LOAD NEW PROJECT
        $("#project-display").fadeTo(450, 0.0, function() {

            // ###### ALL ######
            $(".selected").removeClass("selected");


            var projId = projLink[selIx].id;
            var selProjLi = projLink[selIx].parentElement;
            selProjLi.className = "selected";

            var projectDisplay = document.getElementById("project-display");

            // set vars for the project display elements:
            var projName = document.getElementById("project-name"); // h3
            var projTools = document.getElementById("project-tools");
            var projNotes = document.getElementById("project-notes");
            var projImages = document.getElementById("project-images");

            // disappear the metadata elements 'cause sometimes they'll be empty
            projTools.style.display = "none";
            projNotes.style.display = "none";
            testimonial.style.display = "none";

            for (var project in projects) { // 'Projects array' -> project
                if (projects[project].project === projId) {

                    var activeProj = projects[project];

                    projName.innerHTML = activeProj.project;

                    // maintain centered display of project-metadata: check for a value, else the element remains hidden
                    if(activeProj["tools used"]) {
                        projTools.style.display = "inline-block";
                        projTools.innerHTML = activeProj["tools used"];
                    }
                    if(activeProj.notes) {
                        projNotes.style.display = "inline-block";
                        projNotes.innerHTML = activeProj.notes;
                    }
                    if(activeProj.testimonial) {
                        testimonial.style.display = "inline-block";
                        testimonial.innerHTML = activeProj.testimonial;
                    }

                    // HOW TO ENSURE THESE ARE ALREADY LOADED ***BEFORE #project-display FADES IN***
                    projImages.innerHTML = "";
                    for (var i = 0; i < activeProj.images.length; i++ ) {
                        projImages.innerHTML += "<img src=\"" + activeProj.images[i].url + "\" />";
                    }
                } // if project id ...
            } // for (var obj in data)
        }) // fade out

        $("#project-display").fadeTo(600, 1.0);

    } // showProject
} // makeLinks

function getJsonData() {
    var request = ajaxReq();
    request.open("GET", "/json/projects.json", true);
    request.setRequestHeader("content-type", "application/json");
    request.send(null);
    request.onreadystatechange = function() {
        if (request.readyState === 4) {
            if (request.status === 200) {
                //makeLinks(request.responseText);
                var projects = JSON.parse(request.responseText);
                var projects = projects["Projects"];
                makeLinks(projects); // makeLinks = callback
                return projects;
            }
        }
    } // onreadystatechange
} // getJsonData

getJsonData(makeLinks);

person user1613163    schedule 24.10.2014    source источник


Ответы (1)


Вы можете добавить событие загрузки к изображениям и запустить fadeOut, когда все изображения будут загружены.

Поскольку для завершения загрузки вам потребуется несколько изображений, я решил отслеживать, какие загрузки завершены, используя массив объекты jQuery.Deferred(). Как только все Deferred'ы разрешены, вы можете запустить анимацию затухания.

Вот функция, которая должна работать:

function fadeWhenReady(projImages, images) {
    projImages.innerHTML = "";
    var loads = []; //create holding bin for deferred calls

    //create images and attach load events
    for (var i = 0; i < activeProj.images.length; i++ ) {
        var deferred = $.Deferred();
        var img = $("<img src=\"" + activeProj.images[i].url + "\" />");
        img.on("load", function() { deferred.resolve() }); //after image load, resolve deferred
        loads.push(deferred.promise()); //add the deferred event to the array
        img.appendTo(projImages); //append image to the page
    }

    //when all deferreds are resolved, then apply the fade
    $.when.apply($, loads).done(function() {
        $("#project-display").fadeTo(600, 1.0); 
    });
}

В вашем function showProject удалите свой вызов $("#project-display").fadeTo(600, 1.0); и замените строки ниже вызовом функции fadeWhenReady.

projImages.innerHTML = "";
for (var i = 0; i < activeProj.images.length; i++ ) {
    projImages.innerHTML += "<img src=\"" + activeProj.images[i].url + "\" />";
}

P.S. Вы используете странную смесь jQuery и ванильного javascript. Вызовы document.getElementById() меня не особо беспокоят, но я бы определенно рекомендовал заменить ваши XMLHttpRequest на jQuery. аякс().

person Dave    schedule 24.10.2014
comment
Спасибо, Дэйв, очень признателен. Я бы ответил намного раньше, однако я не очень удачливый владелец MacBook Pro 2011 года, поэтому я теряю много часов на перезапуск. - person user1613163; 26.10.2014
comment
Что касается вашей помощи: во-первых, спасибо за предупреждение: .Deferred; Я думаю, что понимаю суть, однако я испытываю путаницу в области; где именно должна жить функция fadeWhenReady? А что касается моего сочетания js и jq: я изучаю js (я немного знаю jQ), пытаясь свести к минимуму использование jQ. Но в интересах целесообразности и простоты я использую jQ для манипуляций с классами и затухания, которые, кстати, были запоздалыми и которые казались подходящим использованием jQ. По сути, мое невежество заключается в том, как исчезать элементы, которые загружаются через ajax/json. Еще раз спасибо за любую помощь. - person user1613163; 26.10.2014
comment
Мне не очевидно, почему у вас проблемы с областью видимости. Я бы попробовал поместить новую функцию на тот же уровень, что и ваши функции ajaxReq, makeLinks и getJsonData. - person Dave; 28.10.2014
comment
Спасибо, Дэйв. Для меня это тоже не очевидно ;) Если я вызову fadeWhenReady(projImages, images); затем «изображения не определены»; если я опускаю аргументы изображений (или оба), то activeProj не определен ... если только я не загрязню его повторными объявлениями любого var, поэтому моя продолжающаяся путаница в области видимости. - person user1613163; 28.10.2014
comment
Я думаю, что это должно быть fadeWhenReady(projImages, activeProj.images); - person Dave; 28.10.2014