Я создал мобильное веб-приложение в формате html / js и использую «window.onerror» для отслеживания ошибок js на стороне клиента и сообщения о них на сервер.
Недавно я заметил, что получаю много отчетовScriptError on line 0
.
Быстрый поиск в Google привел меня к таким дискуссиям, как Загадочная «Ошибка скрипта».сообщается в Javascript в Chrome и Firefox и https://ravikiranj.net/posts/2014/code/how-fix-cryptic-script-error-javascript/
Для большинства людей такие ошибки, как представляется, вызваны сбоями в сценариях, которые включены из иностранного происхождения.Но, к сожалению, это не так для меня.
После многих часов отладки я придумал следующий минимальный пример для воспроизведения ошибки:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Test</title>
<meta name="google" content="notranslate"/>
<script type="text/javascript">
function init() {
window.onerror = function() {
alert(JSON.stringify(arguments));
}
}
</script>
</head>
<body onload="init()">
<h1>Hello</h1>
<svg width="300" height="300">
<a href="#">
<rect x="50" y="50" width="200" height="200" />
</a>
</svg>
<p>
<a href="#">Link</a>
</p>
</body>
</html>
Как мы видим, это простой HTMLстраница без JavaScript, за исключением самого обработчика ошибки.
В Safari (ios 12.4.1) ошибка не вызывается.Но как в Google Chrome для iOS, так и в Firefox для iOS сообщение ScriptError on line 0
сообщается каждый раз при нажатии на ссылку внутри элемента <svg>
- но не при нажатии на ссылку за пределами <svg>
.Обратите внимание, что к <svg>
.
не подключен обработчик событий js. Живая версия кода доступна онлайн по адресу https://static.laszlokorte.de/scripterror.php
Я знаю, что все сторонние браузеры на iOS на самом деле просто используютСафари под капотом расширяется с несколькими пользовательскими функциями.Я подозреваю, что эти пользовательские функции вызывают ошибку, но я не знаю, как отследить ее дальше.
Почему щелчок по ссылке внутри простого элемента svg вызывает ошибку в iOS Chrome и Firefox, но не в Safari?Есть ли способ подключить инструменты Safari Webdev к мобильным браузерам, отличным от собственного Safari?
Обновление
После более глубокого изучения исходного кода Chrome (iOS) и Firefox (iOS)Теперь я нашел причину проблемы.Оба браузера вводят код JavaScript, который выполняется на touchstart
и обрабатывает целевой узел события.Оба браузера проверяют, были ли затронуты элементы '' или '', и пытаются получить доступ к их атрибуту href
или src
соответственно.Затем они оба пытаются отправить значения атрибутов через webkit.postMessage
хост-приложению.
Ошибка, по-видимому, вызвана тем фактом, что элемент <a>
внутри <svg>
на самом деле является SVGAElement
и атрибут href
- это не String
, а SVGAnimatedString
, который (кроме String
) нельзя клонировать для отправки другому процессу.
Соответствующий код для Firefox можно найти здесь: https://github.com/mozilla-mobile/firefox-ios/blob/826cb396a9eb225b7eb667b47b245e2d98d26ed8/Client/Frontend/UserContent/UserScripts/AllFrames/AtDocumentEnd/ContextMenu.js#L14-L35
Код для Chrome находится здесь: https://github.com/chromium/chromium/blob/master/ios/web/web_state/js/resources/all_frames_context_menu.js#L136-L139
Так что для Chrome решение на самом деле простое, потому чтоэто позволяет явно отказаться от всего этого, установив свойство css -webkit-touch-callout: none
(вы можете проверить это в связанном файле).Например, вот так:
@namespace svg url(http://www.w3.org/2000/svg);
svg|a {
-webkit-touch-callout: none;
}
Для Firefox я пока не нашел простого решения.
Обновление 2
Для Firefox я сейчас пришелсо следующим решением для обезьяны:
(function() {
var origClosest = SVGElement.prototype.closest;
SVGElement.prototype.closest = function (sel) {
var c = origClosest.apply(this, arguments);
if(c && sel === 'a' && c.namespaceURI === this.namespaceURI) {
return c.parentNode && c.parentNode.closest(sel);
} else {
return c;
}
};
})();
Я переопределяю метод closest
(который сам Firefox использует для поиска затронутых <a>
) в SVG-элементах с помощью моего собственного метода, который пропускает все <a>
элементы, принадлежащие пространству имен SVG.
Дополнительно я представил выпуск в репозитории Firefox на Github и выпуск для Chromium.