Блог разработчика 1С-Битрикс

Управление DOM-структурой в 1С-Битрикс: BX.setUnselectable() и BX.setSelectable()

Функции ядра 1С-Битрикс позволяют мгновенно запретить или разрешить выделение текста на любом DOM-узле. Это полезно, когда вы создаёте drag-and-drop-интерфейсы, интерактивные меню или карточки, где случайная подсветка портит UX. Ниже — полное руководство с актуальными, проверенными примерами.

Управление DOM-структурой. BX.setUnselectable/BX.setSelectable

Что делают функции

BX.setUnselectable(node); // запрещает выделение всего, что находится внутри node
BX.setSelectable(node);   // возвращает стандартное поведение
  • node — DOM-элемент или его id.
  • Работают сразу после вызова, без ожидания BX.ready, если элемент уже присутствует в DOM.
  • Учитывают все вендорные префиксы (-webkit-, -ms-, -moz-) и добавляют обработчик selectstart для старых IE, поэтому кросс-браузерность уже «вшита».

Пример 1. Запрет выделения заголовка

<h1 id="page-title">CRM и интеграции</h1>
<script>
BX.ready(function () {
    BX.setUnselectable(BX('page-title'));
});
</script>

Пример 2. Массовая обработка коллекции элементов

<ul id="sidebar">
    <li class="sidebar-item">Пункт 1</li>
    <li class="sidebar-item">Пункт 2</li>
    <li class="sidebar-item">Пункт 3</li>
</ul>
<script>
BX.ready(function () {
    /* Ищем ВСЕ дочерние элементы с классом .sidebar-item */
    var items = BX.findChildren(BX('sidebar'), {className: 'sidebar-item'}, true);
    /* Кросс-браузерный классический цикл */
    for (var i = 0; i < items.length; i++) {
        BX.setUnselectable(items[i]);
    }
});
</script>

Работает даже в IE 11 и во всех актуальных браузерах.

Пример 3. Временное отключение выделения при drag-and-drop

<style>
#drag-box{
    width:150px;
    height:150px;
    background:#f4f6f8;
    cursor:move;
    position:absolute;   /* критично для перемещения */
    left:0;
    top:0;
    display:flex;
    align-items:center;
    justify-content:center;
    user-select:none;    /* fallback, если JS не прогрузился */
}
</style>
<div id="drag-box">Перетащи&nbsp;меня</div>
<script>
BX.ready(function () {
    var box    = BX('drag-box');
    var isDrag = false, shiftX = 0, shiftY = 0;
    /* Унификация координат для тач- и мышиных событий */
    function point(e){
        return (e.touches && e.touches[0]) ? e.touches[0] : e;
    }
    function start(e){
        e = point(e);
        e.preventDefault();                 // убираем первичное выделение
        isDrag = true;
        shiftX = e.clientX - box.offsetLeft;
        shiftY = e.clientY - box.offsetTop;
        BX.setUnselectable(document.body);  // глобальный запрет на время перетаскивания
    }
    function move(e){
        if (!isDrag) return;
        e = point(e);
        box.style.left = (e.clientX - shiftX) + 'px';
        box.style.top  = (e.clientY - shiftY) + 'px';
    }
    function end(){
        if (!isDrag) return;
        isDrag = false;
        BX.setSelectable(document.body);    // возвращаем выделение
    }
    /* бинды с учётом passive:true по умолчанию на touch-событиях */
    BX.bind(box,      'mousedown',  start);
    BX.bind(box,      'touchstart', start, {passive:false});
    BX.bind(document, 'mousemove',  move);
    BX.bind(document, 'touchmove',  move,  {passive:false});
    BX.bind(document, 'mouseup',    end);
    BX.bind(document, 'touchend',   end);
});
</script>

Дополнительные лайфхаки

Ситуация Решение
Нужно сохранить запрет даже при отключённом JavaScript Добавьте CSS-класс .noselect { user-select:none; } в верстку, а в скрипте вызывайте BX.addClass(node, 'noselect') совместно с BX.setUnselectable(node).
Требуется инвертировать правило динамически Храните состояние в data-атрибутах и вызывайте нужную функцию при клике/change.
Нужно массово запретить выделение для блоков, создаваемых по AJAX После вставки новых узлов в DOM сразу проходите по коллекции: BX.findChildren(container, {...}, true) и применяйте BX.setUnselectable.

Коротко о производительности

  • Функция меняет только inline-стили выбранного элемента, поэтому не вызывает рекалькуляцию стилей всего документа.
  • Слушатель selectstart добавляется «лениво» — один раз, без дублирования, что полезно для элементов, создаваемых в цикле.

Итоги

BX.setUnselectable() и BX.setSelectable() — быстрый и надёжный способ держать интерфейс «чистым» от случайной подсветки текста. Исправленные примеры выше подтверждают, что при правильной верстке и минимальном коде можно избежать проблем даже в самом консервативном браузере. Используйте функции точечно, комбинируйте с CSS-классами и не забывайте возвращать выделение после drag-операций — это залог дружелюбного UX в любом проекте на 1С-Битрикс.

Теги:  DOM, BX.setUnselectable, BX.setSelectable, JavaScript, веб-разработка, UX, drag-and-drop


Стоимость услуг по разработке и сопровождению сайтов на 1C-Битрикс

Разработка корпоративного сайта

от 7 дней

от 40 000 рублей

Разработка сайта без системы оплаты заказов через корзину

* стоимость зависит от наличия верстки, использования готового решения и т.д.

Лендинг

от 3 дней

от 25 000 рублей

Разработка одностраничного сайта на платформе Битрикс

* стоимость зависит от наличия верстки, использования готового решения и т.д.

Участие в проекте

привлечение в проект на part-time основе

от 20 000 рублей / неделя

Возможно участие в проекте на ежедневной основе, как разработчика. Занятость - до 20 часов в неделю
Минимальный срок - одна неделя.

* сумма фиксированная