Управление DOM с помощью JavaScript в современных браузерах и IE 11+
В этом посте мы добавим элемент для изменения размера дочерних элементов данного элемента. Исходный элемент может быть организован следующим образом:
<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);
};