Запускается ли событие, когда элемент HTML-ссылки (‹a/›), содержащий данные base64 в виде href, готов?

Я создал веб-страницу, которая в основном отображает два изображения рядом.

У него есть кнопка «загрузить», которая запускает обычную функцию Javascript, которая создает <canvas> HTML-элемент и объединяет два изображения внутри него. Затем он создает ссылку с изображением результата в кодировке base64 как href и щелкает по нему:

<a download="image.png" id="dllink" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABQAAAAMnCAYAAABhnf9DAAAgAElEQVR4nOzdR48kD3rn96j03pfv6qo21dVd3qT3JryP9Jll281..."></a>

Вот как выглядит функция, которую я использую:

/** 
 * Create canvas, draw both images in it, create a link with the result
 * image in base64 in the "href" field, append the link to the document,
 * and click on it
 */
function saveImage() {

    // Get left image
    var imgLeft = new Image();
    imgLeft.setAttribute('crossOrigin', 'anonymous');
    imgLeft.src = "imgleft/" + idxImageShownLeft + ".jpg";
    imgLeft.onload = function() {

        // Once the left image is ready, get right image
        var imgRight = new Image()
        imgRight.setAttribute('crossOrigin', 'anonymous');
        imgRight.src = "imgright/" + idxImageShownRight + ".jpg";
        imgRight.onload = function() {

            // Once the right image is ready, create the canvas
            var canv = document.createElement("canvas");
            var widthLeft = parseInt(imgLeft.width);
            var widthRight = parseInt(imgRight.width);
            var width = widthLeft + widthRight;
            var height = imgLeft.height;

            canv.setAttribute("width", width);
            canv.setAttribute("height", height);
            canv.setAttribute("id", "myCanvas");
            canv.setAttribute('crossOrigin', 'anonymous');
            var ctx = canv.getContext("2d");

            // Draw both images in canvas
            ctx.drawImage(imgLeft, 0, 0);
            ctx.drawImage(imgRight, widthLeft, 0);

            // Create PNG image out of the canvas
            var img = canv.toDataURL("image/png");

            // Create link element
            var aHref = document.createElement('a');
            aHref.href = img;
            aHref.setAttribute("id", "dllink");
            aHref.download = "image.png";

            // Append link to document
            var renderDiv = document.getElementById("render");
            renderDiv.replaceChild(aHref, document.getElementById("dllink"));

            // Click on link
            aHref.click();
        }
    }
}

Моя проблема в том, что это отлично работает в Firefox, но не в Chrome.

После небольшого исследования я понял, что установка точки останова перед строкой aHref.click(); в Chrome работает нормально. Я думаю, что это означает, что aHref.click(); вызывается до того, как <a href="data:image/png;base64,...></a> готов для нажатия, но я не знаю наверняка.

  • Мне не удалось найти дубликата этой темы. Какие ключевые слова мне следует использовать, чтобы быть уверенным на 100%?
  • Я веду расследование в правильном направлении?
  • Есть ли событие, на которое я мог бы положиться, чтобы вызвать aHref.click(); только тогда, когда он будет готов?

person Alfred Dupont    schedule 07.12.2015    source источник
comment
У меня работает, я использую chrome 46.0.2490.86 (64-бит) на ubuntu. в чем проблема ??   -  person Alessandro.Vegna    schedule 07.12.2015
comment
Какова цель renderDiv.replaceChild(aHref, document.getElementById("dllink"));? aHref, #dlink тот же элемент?   -  person guest271314    schedule 07.12.2015
comment
@ Alessandro.Vegna: Проблема в том, что когда я нажимаю кнопку загрузки, иногда изображение результата открывается в моем редакторе изображений, а иногда ничего не происходит.   -  person Alfred Dupont    schedule 07.12.2015
comment
@ guest271314: Я заменяю предыдущий элемент #dllink новым (aHref).   -  person Alfred Dupont    schedule 07.12.2015
comment
Не связано с вашей проблемой, но холст не имеет атрибута crossorigin. Что касается вашей проблемы, вы уверены, что изображения onload запускаются? Лично я всегда предпочитаю устанавливать src после объявления обработчиков загрузки. Кроме того, я думаю, что на некоторых UA ссылка должна быть видна, чтобы click() мог работать.   -  person Kaiido    schedule 08.12.2015
comment
@Kaiido: Спасибо, я удалю атрибут crossorigin для своего холста. Я включил отладку трассировки в свой сценарий, и оба onload события запускаются для моих изображений каждый раз. Попробую установить src после onload. Под видимым вы имеете в виду, что он должен быть добавлен в DOM страницы или что пользователь должен иметь возможность действительно видеть его? Спасибо за вашу помощь!   -  person Alfred Dupont    schedule 08.12.2015
comment
Да, под видимым я подразумеваю, что элемент не должен иметь свойство CSS display, установленное на none, а также visibility один на hidden. Но я думаю, что с тех пор он изменился в большинстве современных браузеров, и я не уверен, что в Chrome когда-либо была такая безопасность. Но для части, добавленной к документу, я уверен, что это необходимо, но, согласно вашему заданному коду, это не должно быть вашей проблемой.   -  person Kaiido    schedule 08.12.2015


Ответы (2)


Вы можете обернуть его функцией инициализации, которая вызывается, когда окно завершает загрузку.

function init() {
  aHref.click();
}
window.onload = init; 

Это похоже на ванильный эквивалент метода jQuery .ready ().

person Korgrue    schedule 07.12.2015
comment
К сожалению, у меня уже есть window.onload функция в моем коде .. . Есть ли способ обойти это? - person Alfred Dupont; 07.12.2015
comment
Вы всегда можете поместить его в функцию тайм-аута, чтобы дать SVG возможность загрузиться перед вызовом, щелкнув по нему. Установите как 1 секунду. Не идеально, но это обходной путь. - person Korgrue; 07.12.2015
comment
Спасибо за ваше предложение, это помогло мне пролить свет на проблему. Видимо, использование чего-то вроде этого не помогло: setTimeout(function() { aHref.click(); }, 3000);. Однако по какой-то причине это сработало лучше: setTimeout(function() { alert("About to click..."); aHref.click(); }, 3);. Странный... - person Alfred Dupont; 08.12.2015

aHref, document.getElementById("dllink") кажутся одним и тем же элементом? Хотя "dllink" еще не добавлен к document, когда .replaceChild вызывается?

Попробуйте заменить

renderDiv.appendChild(aHref);

для

renderDiv.replaceChild(aHref, document.getElementById("dllink"));
person guest271314    schedule 07.12.2015
comment
Да, document.getElementById("dllink") - это ранее использовавшийся элемент, а aHref - вновь созданный. Я использую .replaceChild, чтобы заменить старый на новый. До этого я все время добавлял, создавая таким образом новый элемент в моем документе при каждом щелчке. К сожалению, указанная проблема существовала и тогда. - person Alfred Dupont; 07.12.2015
comment
@AlfredDupont Чтобы избежать возможного дублирования id в документе, можно ли удалить существующий #dllink перед добавлением нового #dllink? Может создавать стеки-сниппеты blog.stackoverflow.com/2014/09/, jsfiddle jsfiddle.net, чтобы продемонстрировать проблему? См. stackoverflow.com/help/mcve - person guest271314; 07.12.2015
comment
Я уже использую repaceChild вместо appendChild, так что в любой момент времени есть только один элемент с идентификатором dllink. Я попытался создать jsfiddle, но по какой-то причине мне это не удалось ... Извините. Завтра я прочитаю, как сделать минимальный, полный и проверяемый пример, и попробую еще раз. - person Alfred Dupont; 08.12.2015