При разработке интерфейсов в «1С:Предприятии 8» с использованием Поля HTML документа (например, при создании чатов, истории переписки, систем комментирования или логов) разработчики часто сталкиваются с задачей автоматического позиционирования. По умолчанию при загрузке документа веб-обозреватель отображает его начало (верхнюю часть). Если переписка длинная, пользователю приходится каждый раз вручную прокручивать страницу вниз, чтобы увидеть последние сообщения. Это снижает удобство работы с системой.
В этой статье мы подробно разберем, как программно управлять прокруткой в Поле HTML документа, рассмотрим современные стандарты JavaScript, проанализируем важные изменения в платформе 1С после перехода на новый движок рендеринга и решим сопутствующие проблемы, такие как задержки при отрисовке и резкие скачки интерфейса.
Если перед нами стоит простая задача — всегда показывать самый низ страницы при ее открытии, мы можем использовать прокрутку по вертикальной координате, равной полной высоте содержимого документа. Полную высоту страницы с учетом прокрутки определяет свойство scrollHeight.
Для реализации этого метода мы можем выполнить код JavaScript непосредственно из среды 1С. Давайте посмотрим, как выглядит классический вызов прокрутки:
// Перемещение прокрутки в самый низ документа
Элементы.ПолеHTML.Документ.defaultView.scrollTo(0, Элементы.ПолеHTML.Документ.body.scrollHeight);
Рассмотрим подробнее, что происходит в этой строке:
defaultView возвращает объект window для текущего HTML-документа.scrollTo(x, y) перемещает окно к указанным координатам. Мы передаем 0 по горизонтали и полную высоту документа scrollHeight по вертикали.Этот способ идеален, если структура документа простая и не содержит тяжелых медиафайлов (картинок, фреймов), которые могут догружаться в процессе.
Более точечный и профессиональный подход — прокрутка не просто «в самый низ», а к конкретному контейнеру (например, к блоку последнего сообщения). Для этого каждому сообщению при формировании HTML-кода необходимо присваивать уникальный идентификатор (атрибут id).
Предположим, наш HTML-код сообщения выглядит следующим образом:
<div id="msg_105" class="message-block">
<span class="author">Иван Иванов:</span>
<p class="text">Коллеги, задача успешно выполнена!</p>
</div>
Зная идентификатор этого элемента (msg_105), мы можем вызвать метод scrollIntoView(), который заставит веб-обозреватель автоматически прокрутить экран так, чтобы элемент оказался в поле зрения пользователя.
Давайте проанализируем, как вызвать этот метод из кода 1С:
// Получаем доступ к документу
ДокументHTML = Элементы.ПолеHTML.Документ;
Если ДокументHTML <> Неопределено Тогда
// Находим нужный элемент по его уникальному ID
ЦелевойЭлемент = ДокументHTML.getElementById("msg_105");
Если ЦелевойЭлемент <> Неопределено Тогда
// Прокручиваем документ к элементу
ЦелевойЭлемент.scrollIntoView(Истина);
КонецЕсли;
КонецЕсли;
Параметр Истина в методе scrollIntoView() указывает, что верхняя граница элемента будет выровнена по верхней границе видимой области. Если передать значение Ложь, элемент выровняется по нижней границе видимой области, что часто является более предпочтительным решением для чатов.
При работе с Полем HTML документа крайне важно учитывать версию платформы «1С:Предприятие». Начиная с версии 8.3.14, разработчики 1С отказались от использования устаревшего и небезопасного движка Internet Explorer (MSHTML) в пользу современного встроенного веб-браузера на базе WebKit/Chromium (CEF).
Это нововведение кардинально повлияло на написание кода:
Элементы.ПолеHTML.Документ.body.scrollTop = Координата) в новых версиях платформы может работать нестабильно, возвращать ошибки «Метод не обнаружен» или приводить к существенному падению производительности интерфейса.parentWindow, которое использовалось в Internet Explorer для получения объекта window, в WebKit необходимо использовать кроссплатформенное свойство defaultView.Рекомендация по архитектуре: Чтобы избежать проблем с совместимостью, рекомендуется всю логику прокрутки и манипуляции с DOM реализовывать непосредственно внутри JavaScript-кода самого HTML-документа, а из 1С лишь инициировать выполнение этих скриптов.
Давайте посмотрим, как реализовать правильный вызов JS-функции из 1С:
// Функция в модуле управляемой формы 1С
&НаКлиенте
Процедура ПрокрутитьКСообщению(ИдентификаторСообщения)
ОкноHTML = Элементы.ПолеHTML.Документ.defaultView;
Если ОкноHTML <> Неопределено Тогда
// Вызываем JS-функцию, объявленную внутри нашей HTML-страницы
ОкноHTML.scrollToMessage(ИдентификаторСообщения);
КонецЕсли;
КонецПроцедуры
Внутри самого HTML-документа (в блоке <script>) мы объявляем соответствующую функцию:
function scrollToMessage(messageId) {
var element = document.getElementById(messageId);
if (element) {
element.scrollIntoView(false); // Выравниваем по нижнему краю
}
}
Часто разработчики сталкиваются с неприятным багом: при открытии формы код прокрутки выполняется без ошибок, но страница все равно остается в самом верху. Выясним причину этого поведения.
Когда в 1С срабатывает событие загрузки документа, движок WebKit уже успевает прочитать структуру HTML, но еще не завершил полный визуальный рендеринг (не загрузились внешние картинки, не применились тяжелые стили CSS, не рассчитались физические размеры блоков). В этот микросегмент времени свойство scrollHeight может быть равно нулю или высоте экрана, так как элементы еще не «раздвинули» страницу на ее реальную высоту. Позиционирование происходит, но в «пустоту», после чего страница дорисовывается и сдвигается вверх.
Для решения этой проблемы мы можем использовать два подхода:
1. Использование setTimeout в JavaScript (рекомендуемый способ):
Мы даем браузеру небольшую паузу (например, 100 миллисекунд), чтобы он гарантированно завершил рендеринг страницы перед выполнением прокрутки.
window.onload = function() {
setTimeout(function() {
window.scrollTo(0, document.body.scrollHeight);
}, 100); // 100 мс достаточно для отрисовки
};
2. Использование обработчика ожидания в 1С:
Если код прокрутки запускается из модуля 1С, мы можем перенести его вызов в обработчик ожидания с небольшим интервалом:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
// Подключаем однократный обработчик с задержкой 0.2 секунды
ПодключитьОбработчикОжидания("ВыполнитьПозиционированиеHTML", 0.2, Истина);
КонецПроцедуры
&НаКлиенте
Процедура ВыполнитьПозиционированиеHTML()
// Код прокрутки
ПрокрутитьКСообщению("msg_last");
КонецПроцедуры
Резкое «телепортирование» экрана к последнему комментарию выглядит неестественно и может дезориентировать пользователя. Современные веб-технологии позволяют сделать этот переход плавным и визуально приятным.
Самый простой способ включить плавную прокрутку на уровне всей страницы — добавить одну строчку в CSS-стили вашего HTML-документа:
html {
scroll-behavior: smooth;
}
После добавления этого правила любые перемещения (будь то переходы по якорям или вызовы функций window.scrollTo()) будут сопровождаться мягкой анимацией движения.
Если плавность нужна только при вызове конкретного метода, мы можем передать в scrollIntoView() специальный объект конфигурации вместо булева значения:
function scrollToMessageSmooth(messageId) {
var element = document.getElementById(messageId);
if (element) {
element.scrollIntoView({
behavior: 'smooth', // Плавная прокрутка
block: 'end' // Позиционирование по нижней границе
});
}
}
При использовании стандартного метода scrollIntoView() целевой элемент прижимается вплотную к верхней или нижней границе Поля HTML. Это выглядит неэстетично, так как текст упирается прямо в рамку элемента управления формы 1С.
Для создания комфортных отступов («воздуха») в интерфейсе мы можем использовать современное CSS-свойство scroll-margin. Давайте пропишем его в стилях для блоков наших сообщений:
.message-block {
/* Создает невидимый отступ в 20 пикселей при позиционировании на элемент */
scroll-margin-bottom: 20px;
scroll-margin-top: 20px;
}
Теперь при прокрутке к последнему сообщению оно аккуратно остановится, не доходя 20 пикселей до нижнего края экрана, что значительно повысит визуальное восприятие чата.
Если в процессе работы пользователя в чат добавляются новые сообщения (например, при получении push-уведомлений или интерактивном вводе), полная перезагрузка HTML-документа через присвоение нового текста свойству Поля HTML является грубой ошибкой. Это приводит к постоянному мерцанию экрана, потере выделения текста и лишней нагрузке на процессор.
Давайте разберем правильный паттерн работы с динамическими данными:
<div id="chat-container"></div>.Посмотрим на пример такой JS-архитектуры:
// Функция добавления нового сообщения, вызываемая из 1С
function addNewMessage(messageId, authorName, messageText) {
var container = document.getElementById("chat-container");
if (!container) return;
// Создаем структуру нового сообщения
var messageDiv = document.createElement("div");
messageDiv.id = messageId;
messageDiv.className = "message-block";
messageDiv.innerHTML = "<strong>" + authorName + ":</strong> " + messageText;
// Добавляем элемент на страницу без перезагрузки
container.appendChild(messageDiv);
// Плавно скроллим к новому сообщению
messageDiv.scrollIntoView({
behavior: 'smooth',
block: 'end'
});
}
Этот подход гарантирует мгновенный отклик интерфейса, плавную анимацию добавления и позиционирования новых сообщений, а также стабильную работу Поля HTML документа даже при наличии тысяч записей в истории переписки.