Почему мой iframe contentEditable сбрасывается? - PullRequest
0 голосов
/ 21 января 2019

У меня есть веб-страница с пустым iframe, которой я хочу назначить источник с javascript и сделать его содержимое редактируемым.Проблема в том, что - хотя я вижу, что содержимое фрейма становится редактируемым на короткое время (браузер начинает подчеркивать слова, которые не проходят проверку орфографии) - что-то сбрасывает это состояние, и у меня остается iframe, который имеетправильное содержимое, но для содержимого frameWindow.document.body.contentEditable фрейма было установлено значение по умолчанию «наследовать».

Настройка свойства contentEditable в консоли работает.Так же как и создание функции ожидания, которая изменяет свойство contentEditable после 1000 мс.Решением, на котором я остановился, было создание XMLHttpRequest для URL, который я хотел бы содержать в iframe, назначение ответа промежуточному html-элементу, изменение свойства contentEditable тела этого элемента, а затем присвоение его InnerHTML для srcdoc iframe.

Итак, у меня есть обходные пути, но я хотел бы понять, что мешает моему первоначальному, более простому подходу.

Полный html:

<!DOCTYPE html>
<html>
<head>
<script>
function setedit(){
    var editableFrame = document.getElementById("editableFrame");
    editableFrame.src = '/b.html'
    editableFrame.contentWindow.document.body.contentEditable = true;
}
</script>
</head>
<body onload="setedit()">
<iframe id="editableFrame"></iframe>
</body>
</html>

b.html:

<!DOCTYPE html>
<html>
<body>
<p>Lorem ipsum yadda yadda</p>
</body>
</html>

Редактировать: Хотя принятое решение с функциями стрелок работает, теперь я не понимаю, почему оно не сработало, когда я писал его как

function setsrc(){
        var theFrame = document.getElementById('the_frame');
        theFrame.src = '/b.html';
        theFrame.onload = setedit();
}
function setedit(){
        var theFrame = document.getElementById('the_frame');
        theFrame.contentWindow.document.body.contentEditable='true';
}

Редактировать 2: Хорошо, теперь я понял.

theFrame.onload = setedit();

Оценивает 'setedit ()' тут же, до загрузки iframe и присваивает его возвращаемое значение 'onload'свойство, которое не является допустимой функцией.

Оно также не работает, если вы пишете

theFrame.onload = "setedit()";

Предположительно, потому что оно пытается присвоить строковое значение литеральному свойству, которое являетсяне действительная функцияна любом из них.

Разочаровывающая вещь и причина, по которой я не смог понять это, так что протокол состоит в том, что ни один из этих подходов не приводит к ошибке, записываемой на консоль, и ни один из них не противоречит способу назначенияОбработчики onload выглядят, когда вы присваиваете их внутри тега, т.е.

<iframe id="the_frame" onload=setedit()></iframe>
<iframe id="the_frame" onload="setedit()"></iframe>

Оба назначают функцию 'setedit ()' в качестве обработчика события onload, за исключением того, что - когда это определено таким образом - они в конечном итоге вызывают обадо и после загрузки родительского окна и по какой-то причине не удалось изменить свойство contentEditable во второй раз.Вы должны сконструировать функцию внутри загрузки окна, как Kaiido с функциями стрелок или в ES5, например:

onload = function(){
    var myFrame = document.getElementById('the_frame');
    myFrame.srcdoc = "<html><body><p>This should be editable</p></body></html>";
    myFrame.onload = function(){
        myFrame.contentDocument.body.contentEditable=true;
    };
}

1 Ответ

0 голосов
/ 21 января 2019

Это связано с тем, что загрузка iframe (как и любого другого ресурса) является асинхронной задачей.
Таким образом, editableFrame.contentWindow, к которому вы обращаетесь (и document.body), не совпадает с тем, который будет после загрузки документа.

В тот момент, когда вы его называете, это пустой документ; это можно проверить, зарегистрировав textContent этого документа, например.

Я должен передать живой пример jsfiddle , потому что исходные кадры StackSnippets с нулевым исходным кодом не позволяют получить доступ к содержимому внутренних кадров.

window.onload = e => {
  the_frame.src = URL.createObjectURL(
    new Blob([`<html><body>An other doc</body></html>`])
  );
  console.log(
    the_frame.contentWindow.document.documentElement.textContent
  ); // ""

  // while in the iframe's onload event
  the_frame.onload = e =>
    console.log(
      the_frame.contentWindow.document.documentElement.textContent
    ); // "An other doc"
};
<iframe id="the_frame"></iframe>

Итак, как вы, возможно, поняли, решение состоит в том, чтобы дождаться, когда событие загрузки iframe сработает после того, как вы изменили src.

https://jsfiddle.net/zwxrpdf8/1/

...