С выходом платформ 1С:Предприятие версий 8.3.14 и 8.3.15 произошел важный технологический сдвиг: старый движок рендеринга Internet Explorer (Trident) в элементе управления ПолеHTMLДокумента был заменен на современный WebKit (Chromium). Это нововведение принесло поддержку современных стандартов HTML5, CSS3 и быструю работу JavaScript-движка V8, однако полностью сломало старые механизмы интеграции между 1С и JS.
В старых версиях платформы разработчики могли напрямую передать объект формы 1С в контекст браузера (например, через window.externalForm = ЭтаФорма) и вызывать экспортные методы модуля формы из скриптов страницы. В WebKit из соображений безопасности и архитектурных ограничений этот механизм заблокирован. Контекст WebKit полностью изолирован, и передача сложных COM-объектов из 1С в браузер невозможна — переменные будут иметь значение undefined. Нам доступны только примитивные типы данных (строки, числа, булевы значения).
В этой статье мы подробно разберем, как обойти данные ограничения и настроить надежную передачу данных и вызов функций 1С из JavaScript с помощью нескольких альтернативных и современных подходов.
Это классический рабочий подход, предложенный на форуме. Суть метода заключается в том, что JavaScript на веб-странице записывает передаваемые параметры в скрытые теги <div>, после чего программно инициирует событие клика. Платформа 1С перехватывает событие нажатия в стандартном обработчике, считывает данные из DOM-дерева страницы, а затем очищает буферные элементы.
Рассмотрим реализацию этого метода по шагам. Сначала подготовим HTML-код страницы со скриптом инициализации карты (на примере библиотеки Leaflet) и скрытыми полями обмена:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.4/dist/leaflet.css"/>
<script src="https://unpkg.com/leaflet@1.5.1/dist/leaflet.js"></script>
<style>
html, body, #map { height: 100%; width: 100%; margin: 0; padding: 0; }
</style>
</head>
<body>
<div id="map"></div>
<!-- Скрытые элементы для передачи данных в 1С -->
<div id="message_key" style="display: none"></div>
<div id="message_data" style="display: none"></div>
<script type="text/javascript">
var this_webkit = true; // Флаг работы под WebKit (1С 8.3.14+)
var map = L.map('map').setView([55.751244, 37.618423], 12);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 18
}).addTo(map);
// Обработчик клика по карте
map.on('click', function(event) {
var location = event.latlng;
// Передаем имя события и координаты в формате JSON
sendTo1C('map.onclick', JSON.stringify(location));
});
// Функция записи данных в DOM и отправки уведомления в 1С
function sendTo1C(name, data) {
if (this_webkit) {
// На новом движке WebKit записываем данные в скрытые div-ы
document.getElementById('message_key').innerHTML = name;
document.getElementById('message_data').innerHTML = data;
// Программно вызываем событие клика на документе, чтобы 1С его перехватила
var event = document.createEvent('HTMLEvents');
event.initEvent('click', true, true);
document.dispatchEvent(event);
} else {
// Резервный вариант для старого движка IE (Trident)
var evt = document.createEventObject();
evt.propertyName = name;
evt.data = data;
evt.cancelBubble = true;
evt.returnValue = false;
document.fireEvent('onclick', evt);
}
}
</script>
</body>
</html>
Теперь проанализируем модуль управляемой формы 1С, где размещен реквизит ПолеHTML. Нам необходимо перехватить нажатие на документ и извлечь данные:
&НаКлиенте
Перем ОкноКарты;
&НаКлиенте
Процедура ПолеHTMLДокументСформирован(Элемент)
// Получаем окно браузера для последующего прямого вызова JS-функций (если потребуется)
ДокументБраузера = Элемент.Документ;
ОкноКарты = ДокументБраузера.defaultView;
КонецПроцедуры
&НаКлиенте
Процедура ПолеHTMLПриНажатии(Элемент, ДанныеСобытия, СтандартнаяОбработка)
// Блокируем стандартную реакцию браузера на клик
СтандартнаяОбработка = Ложь;
Если ОкноКарты = Неопределено Тогда
Возврат;
КонецЕсли;
// Считываем значения из скрытых div-ов на странице
Попытка
КлючСобытия = ОкноКарты.document.getElementById("message_key").innerHTML;
ЗначениеСобытия = ОкноКарты.document.getElementById("message_data").innerHTML;
// Очищаем буферные элементы, чтобы избежать повторного срабатывания
ОкноКарты.document.getElementById("message_key").innerHTML = "";
ОкноКарты.document.getElementById("message_data").innerHTML = "";
Исключение
// Элементы не найдены на странице
Возврат;
КонецПопытки;
Если Не ПустаяСтрока(ЗначениеСобытия) Тогда
// Обрабатываем полученные данные
ВыполнитьДействие1С(КлючСобытия, ЗначениеСобытия);
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ВыполнитьДействие1С(КлючСобытия, ДанныеJSON)
// Десериализуем данные из JSON-строки в структуру 1С
Данные = ДесериализоватьJSON(ДанныеJSON);
Если КлючСобытия = "map.onclick" Тогда
// Обрабатываем клик по карте и получение координат
Широта = Неопределено;
Долгота = Неопределено;
Если Данные.Свойство("lat") Тогда
Широта = Данные.lat;
КонецЕсли;
Если Данные.Свойство("lng") Тогда
Долгота = Данные.lng;
КонецЕсли;
Сообщить(СтрШаблон("Получены координаты из JS: Широта = %1, Долгота = %2", Широта, Долгота));
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Функция ДесериализоватьJSON(СтрокаJSON)
Чтение = Новый ЧтениеJSON;
Чтение.УстановитьСтроку(СтрокаJSON);
Результат = ПрочитатьJSON(Чтение);
Чтение.Закрыть();
Возврат Результат;
КонецФункции
Важное примечание: Обратите внимание на замену свойства parentWindow на defaultView. В движке WebKit глобальный контекст браузера (объект window) получается исключительно через defaultView.
Предыдущий способ со скрытыми <div> полностью работоспособен, однако он вынуждает разработчика засорять DOM-дерево страницы техническими элементами и постоянно очищать их. Существует более изящный и современный способ передачи данных — использование кастомных псевдо-протоколов (схем URL).
При этом подходе JavaScript-код инициирует изменение адреса страницы через window.location.href, подставляя специальный префикс (например, v8action://) и передавая параметры в URI-кодированном JSON. Платформа 1С перехватывает эту попытку перехода в событии ПриНажатии, предотвращает реальный переход браузера и забирает переданные параметры.
Посмотрим на пример JS-функции на веб-странице:
function sendDataTo1C(actionName, payload) {
const dataTransfer = {
action: actionName,
data: payload
};
// Сериализуем объект в строку JSON и кодируем для безопасной передачи в URL
const jsonString = encodeURIComponent(JSON.stringify(dataTransfer));
// Инициируем переход по нашему кастомному протоколу
window.location.href = "v8action://" + jsonString;
}
// Пример использования при клике на маркер карты:
sendDataTo1C("markerSelected", { id: "000001234", lat: 55.75, lng: 37.61 });
Теперь разберем, как поймать этот вызов на стороне управляемой формы 1С в обработчике события ПоляHTMLДокумента:
&НаКлиенте
Процедура ПолеHTMLПриНажатии(Элемент, ДанныеСобытия, СтандартнаяОбработка)
// Проверяем, что адрес перехода начинается с нашей схемы протокола
Если СтрНачинаетсяС(ДанныеСобытия.Href, "v8action://") Тогда
// Отменяем стандартный переход браузера по ссылке
СтандартнаяОбработка = Ложь;
// Извлекаем закодированную JSON-строку (отбрасываем префикс "v8action://" длиной 11 символов)
ЗакодированныйJSON = Сред(ДанныеСобытия.Href, 12);
// Декодируем URI-последовательность обратно в обычную строку JSON
СтрокаJSON = ДекодироватьСтроку(ЗакодированныйJSON, СпособКодированияСтроки.КодированиеURL);
// Преобразуем JSON в структуру 1С
ПараметрыСобытия = ДесериализоватьJSON(СтрокаJSON);
// Вызываем соответствующий обработчик в зависимости от действия
Если ПараметрыСобытия.action = "markerSelected" Тогда
ОбработатьВыборМаркера(ПараметрыСобытия.data);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ОбработатьВыборМаркера(ДанныеМаркера)
Сообщить("В 1С выбран маркер с ИД: " + ДанныеМаркера.id);
КонецПроцедуры
Данный подход является наиболее чистым, так как не требует работы с разметкой DOM и не вызывает ложных срабатываний кликов на других элементах формы.
Если на вашей HTML-странице размещены стандартные кнопки, ссылки или списки, по нажатию на которые требуется вызывать определенный код в 1С, вы можете использовать стандартные HTML5 data-атрибуты (data-*). Это избавит вас от написания сложного JS-кода отправки событий.
Разметим HTML-элементы на странице следующим образом:
<button class="action-btn" data-action="createDocument" data-type="Invoice" data-id="1054">Создать счет</button>
<button class="action-btn" data-action="openReport" data-type="Sales" data-id="2023">Открыть отчет</button>
В обработчике события 1С мы можем напрямую получить доступ к свойствам нажатого HTML-элемента через свойство ДанныеСобытия.Element:
&НаКлиенте
Процедура ПолеHTMLПриНажатии(Элемент, ДанныеСобытия, СтандартнаяОбработка)
ТекущийЭлемент = ДанныеСобытия.Element;
Если ТекущийЭлемент <> Неопределено Тогда
// Проверяем класс элемента, чтобы обрабатывать только наши кнопки
Если СтрНайти(ТекущийЭлемент.className, "action-btn") > 0 Тогда
СтандартнаяОбработка = Ложь;
// Получаем значения кастомных data-атрибутов
Действие = ТекущийЭлемент.getAttribute("data-action");
ТипДокумента = ТекущийЭлемент.getAttribute("data-type");
Идентификатор = ТекущийЭлемент.getAttribute("data-id");
ВыполнитьКомандуИзИнтерфейса(Действие, ТипДокумента, Идентификатор);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ВыполнитьКомандуИзИнтерфейса(Действие, ТипДокумента, Идентификатор)
Сообщить(СтрШаблон("Команда 1С: Действие - %1, Тип - %2, ИД - %3", Действие, ТипДокумента, Идентификатор));
КонецПроцедуры
Рассмотрим обратную задачу — вызов функций JavaScript из кода 1С. В WebKit этот процесс также претерпел изменения. Нам необходимо учитывать два важных правила:
defaultView вместо устаревшего parentWindow. Например:
Элементы.ПолеHTML.Документ.defaultView.myJSFunction(Параметр1);
eval() из кода встроенного языка 1С. Если вам нужно динамически выполнять произвольный код JS, добавьте на саму HTML-страницу функцию-обертку, выполняющую локальный eval:
function executeEval(codeString) {
return eval(codeString);
}
КодJS = "map.setView([55.75, 37.61], 14);";
Элементы.ПолеHTML.Документ.defaultView.executeEval(КодJS);
При активной разработке интерактивных интерфейсов на WebKit программисты часто сталкиваются с тем, что движок браузера агрессивно кэширует локальные HTML-файлы, скрипты и картинки. Даже если вы изменили код макета или JS-файла на диске, в ПолеHTMLДокумента может отображаться старая закэшированная версия.
Чтобы гарантированно сбросить кэш при загрузке страницы или скрипта, добавляйте к путям файлов уникальный динамический параметр (например, текущую дату и время в виде таймстампа):
// Пример динамической сборки пути к файлу скрипта для обхода кэша
ИмяСкрипта = "my_map_logic.js";
УникальныйПараметр = Формат(ТекущаяДата(), "ДФ=yyyyMMddhhmmss");
ПутьКСкрипту = СтрШаблон("%1?v=%2", ИмяСкрипта, УникальныйПараметр);
// Итог: "my_map_logic.js?v=20231024123045" - браузер воспримет это как новый файл и загрузит заново
Используя предложенные методики (перехват кликов через скрытые div-элементы, кастомную схему URL v8action:// или HTML5 data-атрибуты), вы сможете построить гибкое, быстрое и отказоустойчивое взаимодействие между управляемыми формами 1С и веб-интерфейсом на базе современного и безопасного движка WebKit.