Ответ 1
Проблема заключается в том, что data:
URL-адреса рассматриваются как имеющие уникальное происхождение, которые отличаются от источника контекста, который создал встроенный data:
контекст:
Примечание. URL-адреса данных считаются уникальными непрозрачными источниками современных браузеров, а не наследуют происхождение объекта настроек, ответственного за навигацию.
Спецификация WHATWG описывает способ доступа к документам контента, который включает проверку перекрестного происхождения. Сравнение WHATWG одинакового происхождения никогда не будет относиться к традиционному происхождению кортежа традиционной схемы-хозяина как к "непрозрачному" data:
происхождению.
Вместо этого используйте Blob
с URL.createObjectURL
для создания временного URL-адреса того же происхождения, содержимое которого будет доступно для чтения внешней средой:
var svgUrl = URL.createObjectURL(new Blob([svg], {'type':'image/svg+xml'}));
obj.setAttribute('data', svgUrl);
Я не знаю причины безопасности, почему этот подход разрешен, а raw data:
- нет, но он работает. (Я думаю, потому что сгенерированный URL-адрес доступен только для источника, который сгенерировал его, тогда как URL data:
не знает, как читать только оригинал его исходного контекста.)
Обратите внимание, что некоторые версии Internet Explorer поддерживают createObjectURL
, но ошибочно обрабатывают сгенерированные URL-адреса как имеющие нулевое начало, что приведет к сбою этого подхода.
Другие варианты:
-
Не используйте URL
data:
и вместо этого используйте SVG-контент из того же источника, что и ваша страница, которая создает элемент<object>
. -
Отключить
<object>
иcontentDocument
в целом и вместо встроенный<svg>
элемент (fiddle):const obj = document.createElement('div'); obj.innerHTML = svg; app.appendChild(obj); setTimeout(() => { console.log(obj.querySelector('svg')); }, 1500);
Большинство браузеров поддерживают встроенные элементы
<svg>
(особенно IE 9.0+, другие браузеры намного раньше). Это означает, что вы можете сделать<div> <svg> ... </svg> </div>
и он просто отобразит документ SVG внутри
<div>
, как и следовало ожидать. -
В зависимости от того, что вы хотите сделать с SVG, вы можете загрузить его в
DOMParser
и выполнить DOM-исследование/манипуляции внутри парсера.var oParser = new DOMParser(); var svgDOM = oParser.parseFromString(svg, "text/xml"); console.log(svgDOM.documentElement.querySelector('path')); svgDOM.documentElement.querySelector('path').remove();
Но модель DOM будет отделена от SVG, представленной в
<object>
. Чтобы изменить<object>
, вам необходимо сериализовать проанализированную структуру DOM и повторно нажать ее в свойствеdata
:var oSerializer = new XMLSerializer(); var sXML = oSerializer.serializeToString(svgDOM); obj.setAttribute('data', `data:image/svg+xml; base64,${btoa(sXML)}`);
Это не кажется суперэффективным, потому что браузер нуждается в повторном анализе совершенно нового документа SVG, но он обойдутся ограничениями безопасности.
Подумайте о
<object>
как односторонней черной дыре, которая может получать информацию SVG для рендеринга, но не будет выводить какую-либо информацию обратно. Однако это неинформационная проблема, поскольку у вас есть информация, которую вы только что подали в<object>
: ничего, чтоcontentDocument
не может сказать вам, что вы еще не знаете.Однако, если вы хотите сделать компоненты в SVG-интерактивном, подключив слушателей к компонентам в структуре SVG, которые выполняют код на главной странице, я не думаю, что этот подход будет работать. Разделение между
<object>
и его окружением страницы имеет такое же отношение вложения, как и<iframe>
.