DevGang
Авторизоваться

Как управлять DOM на чистом JavaScript?

Управление DOM с помощью JavaScript в современных браузерах и IE 11+

Добавить или удалить класс из элемента Разрешить ввод только определенных символов Добавить к элементу Подписаться на событие Вычислить положение мыши относительно элемента Рассчитать размер полосы прокрутки Изменить favicon Проверить элемент по селектору Проверка наличия класса у элемента Проверьте, является ли элемент потомком другого Проверьте, находится ли элемент в области просмотра Проверка, является ли элемент прокручиваемым Проверка, поддерживается ли ввод даты Клонировать элемент Связь между iframe и его родительским окном Скопировать текст в буфер обмена Подсчитайте количество символов текстовой области Создать элемент Создать слайдер сравнения изображений Создать одноразовый обработчик событий Создание изменяемых размеров разделенных видов Обнаружение кликов за пределами элемента Определить, находится ли элемент в фокусе Определите, включен ли caps-lock Как определить Mac OS браузер Определить высоту и ширину элемента Определение левый и правый клик мыши Скачать файл Перетаскивание элементов в списоке Перетаскивание столбецов таблицы Перетаскивание строки таблицы Выполнить код, когда документ готов Экспорт таблицы в CSV Получить CSS-стили элемента Получить или установить заголовок документа Получить или установить HTML-элемент Получить, установить и удалить атрибуты Получить установить и удалить атрибуты data Получить братьев и сестер элемента Получить размер выбранного файла Получить ближайший элемент по данному селектору Получить значение по умолчанию для свойства css Получиту высоту и ширину документа Получить первый прокручиваемый родительский элемент Получить родительский элемент Получить положение элемента относительно другого Получить позицию элемента относительно документа Получить размер изображения Получить текстовое содержимое элемента Вернуться на предыдущую страницу Выделите элемент при перетаскивании файла поверх него Вставить элемент после или перед другим элементом Вставить данный HTML после или перед элементом Загрузить файл CSS динамически Загрузить файл JavaScript динамически Цикл по нодлисту Сделать изменяемый размер элемента Вставить изображение из буфера обмена Placeholder для contenteditable Нажмите Shift и введите новую строку Предварительный просмотр изображения перед его загрузкой Поместить курсор в конец ввода Перенаправить на другую страницу Перезагрузить текущую страницу Удалить все дочерние узлы Удалить элемент Заменить элемент Заменить элемент Заменить сломанные изображения Измените размер фрейма, чтобы он соответствовал его содержанию Изменить размер изображения Изменить размер столбцов таблицы Измените ширину текстового поля, чтобы оно автоматически соответствовало его содержимому Масштабировать текст, чтобы он поместился внутри элемента Прокрутить до верхней части страницы Выберите элемент или список элементов Выберите дочерние элементы Сериализация данных формы в строку запроса Показывать фальшивый элемент при перетаскивании элемента Сортировка таблицы, нажав на ее заголовки Поменять местами два узла Скрыть / показать элемент Переключить видимость пароля Запустить событие Развернуть элемент Загрузить файлы с помощью AJAX Обернуть элемент вокруг данного элемента

В этом посте мы добавим элемент для изменения размера дочерних элементов данного элемента. Исходный элемент может быть организован следующим образом:

<div style="display: flex">
    <!-- Left element -->
    <div>Left</div>

    <!-- The resizer -->
    <div class="resizer" id="dragMe"></div>

    <!-- Right element -->
    <div>Right</div>
</div>

Чтобы поместить элементы left, resizer и right в одну строку, мы добавляем стиль display: flex к родительскому элементу.

Обновление ширины левой стороны при перетаскивании элемента изменения размера

Рекомендуется посмотреть этот пост, чтобы увидеть, как мы можем сделать элемент перетаскиваемым.

В нашем случае ресайзер можно перетаскивать горизонтально. Во-первых, мы должны сохранить положение мыши и ширину левой стороны, когда пользователь начинает нажимать на изменение размера:

// Query the element
const resizer = document.getElementById('dragMe');
const leftSide = resizer.previousElementSibling;
const rightSide = resizer.nextElementSibling;

// The current position of mouse
let x = 0;
let y = 0;

// Width of left side
let leftWidth = 0;

// Handle the mousedown event
// that's triggered when user drags the resizer
const mouseDownHandler = function(e) {
    // Get the current mouse position
    x = e.clientX;
    y = e.clientY;
    leftWidth = leftSide.getBoundingClientRect().width;

    // Attach the listeners to `document`
    document.addEventListener('mousemove', mouseMoveHandler);
    document.addEventListener('mouseup', mouseUpHandler);
};

// Attach the handler
resizer.addEventListener('mousedown', mouseDownHandler);

Глядя на структуру нашей разметки, слева и справа находятся предыдущий и следующий родственник resizer. Их можно получить, как вы видите выше:

const leftSide = resizer.previousElementSibling;
const rightSide = resizer.nextElementSibling;

Затем, когда пользователь перемещает мышь, мы определяем, насколько далеко она была перемещена, а затем обновляем ширину для левой стороны:

const mouseMoveHandler = function(e) {
    // How far the mouse has been moved
    const dx = e.clientX - x;
    const dy = e.clientY - y;

    const newLeftWidth = (leftWidth + dx) * 100 / resizer.parentNode.getBoundingClientRect().width;
    leftSide.style.width = `${newLeftWidth}%`;
};

Есть две важные вещи, которые я хотел бы отметить здесь:

  • Ширина левой стороны устанавливается в зависимости от количества процентов ширины родительского элемента. Он сохраняет соотношение левой и боковой ширины и делает две стороны хорошо выглядящими, когда пользователь изменяет размер браузера.
  • Нет необходимости обновлять ширину правой стороны, если мы всегда заставляем ее принять оставшуюся ширину:
<div style="display: flex">
    <!-- Left element -->
    ...

    <!-- The resizer -->
    ...

    <!-- Right element -->
    <div style="flex: 1 1 0%;">Right</div>
</div>

Исправить проблему мерцания

Когда пользователь перемещает resizer, мы должны обновить его курсор:

const mouseMoveHandler = function(e) {
    ...
    resizer.style.cursor = 'col-resize';
};

Но это вызывает другую проблему. Как только пользователь переместит мышь, мы увидим курсор мыши по умолчанию, потому что мышь не находится над изменяющим размер. Пользователь увидит мерцание экрана, потому что курсор постоянно меняется.

Чтобы это исправить, мы устанавливаем курсор на всю страницу:

const mouseMoveHandler = function(e) {
    ...
    document.body.style.cursor = 'col-resize';
};

Мы также предотвращаем события мыши и выделение текста с обеих сторон, устанавливая значения для user-select и pointer-events:

const mouseMoveHandler = function(e) {
    ...
    leftSide.style.userSelect = 'none';
    leftSide.style.pointerEvents = 'none';

    rightSide.style.userSelect = 'none';
    rightSide.style.pointerEvents = 'none';
};

Эти стили удаляются сразу после того, как пользователь перестает двигать мышь:

const mouseUpHandler = function() {
    resizer.style.removeProperty('cursor');
    document.body.style.removeProperty('cursor');

    leftSide.style.removeProperty('user-select');
    leftSide.style.removeProperty('pointer-events');

    rightSide.style.removeProperty('user-select');
    rightSide.style.removeProperty('pointer-events');

    // Remove the handlers of `mousemove` and `mouseup`
    document.removeEventListener('mousemove', mouseMoveHandler);
    document.removeEventListener('mouseup', mouseUpHandler);
};
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться