Я пробовал много способов создать заголовок столбца перетаскивания, это может быть сложно, например, когда родительский контейнер имеет переполнение-x. Это лучший способ избежать вычислений и всего остального.
Шаблон Vue
Создайте ‹button› после каждого ‹li› или ‹th› по своему усмотрению и добавьте ссылку для каждой ‹button› и каждой ‹li› и поместите индекс для функции v-for.
<ul @mouseup="mouseUp($event)" @mousemove="mouseMove($event)"> <li v-for="(header, index) in headers" :key="colIndex" :ref="`element-${index}`" > <button @mousedown="mouseDown($event, colIndex)" @mouseup="mouseUp($event)" :ref="`resize-${index}`" class="resize" :class="{ 'dragged': beforeChangeSize.col === index }" > </button> </li> </ul>
Стиль
Кнопка должна появляться, когда вы наводите на нее курсор. При перетаскивании он занимает фиксированное положение.
li { position: relative; } .resize { position: absolute; top: 0; right: 0; height: 45px; background: #7d8ba5; width: 5px; padding: 0; border: 0; cursor: col-resize; box-shadow: none; outline: none; opacity: 0; transition: opacity ease .5s; &.dragged { opacity: 1; position: fixed; top: auto; } &:hover { opacity: 1; } }
JavaScript
Создайте глобальную переменную с именем eventDrag, которая принимает значение true при dragStart и становится false при dragEnd. Эта переменная позволяет для включения или отключения содержимого функции moveDrag, moveEnd.
handleDownChangeSize(event, colIndex) { this.eventDrag = true } handleMoveChangeSize(event) { if (this.eventDrag) { ... } } handleUpDragToFill(event) { if (this.eventDrag) { ... } },
MouseDown
Создайте объект под названием beforeChangeSize, когда dragStart содержит:
- смещение элемента event.clientX.
- индекс элемента colIndex
- ширина элемента, element.innerWidth.
mouseDown(event, colIndex) { this.eventDrag = true; const [element] = this.$refs[`element-${this.beforeChangeSize.col}`] this.beforeChangeSize = { offset: event.clientX, col: colIndex, width: element.offsetWidth }; }
Примените offsetTop parentElement элемента к resizeButton.style.top
const [element] = this.$refs[`element-${this.beforeChangeSize.col}`] const [resizeButton] = this.$refs[`resize-${colIndex}`] resizeButton.style.top = `${element.parentElement.offsetTop}px`
MouseMove
Измените style.left элемента при перетаскивании. Элемент будет иметь перетаскиваемый класс и фиксированное положение.
mouseMove(event) { if (this.eventDrag) { const [resizeButton] = this.$refs[`resize-${this.beforeChangeSize.col}`] resizeButton.style.left = `${event.clientX}px` } }
Если вы переместите курсор за пределы поля, вызывается функция mouseUp.
- Получите offsetTop для resizeButton
- Получить offsetHeight resizeButton
- Добавить offsetTop в offsetHeight
Если offsetTop выше или равен event.clientY, а offsetBottom меньше или равен в event.clientY. Курсор находится в поле.
В противном случае вы находитесь вне рамок, поэтому вызывается функция mouseUp.
const [resizeButton] = this.$refs[`resize-${this.beforeChangeSize.col}`] const offsetTop = resizeButton.offsetTop const offsetBottom = offsetTop + resizeButton.offsetHeight if (offsetTop <= event.clientY && offsetBottom >= event.clientY) { // Change style.left of resizeButton } else { // Called MouseUp function }
MouseUp
Чтобы рассчитать новый размер элемента, вычтите oldOffset из newOffset и обязательно вычтите максимум из минимума, для этого используйте Math.max , Math.min.
const oldOffset = this.beforeChangeSize.offset const newOffset = event.clientX const result = Math.max(newOffset, oldOffset) - Math.min(newOffset, oldOffset)
Как только результат готов, вопрос состоит в том, чтобы добавить или вычесть результат начальной ширины.
- Если newOffset превосходит oldOffset, добавьте результат
- Иначе вычесть результат
if (newOffset > oldOffset) { this.newSize = this.beforeChangeSize.width + result } else { this.newSize = this.beforeChangeSize.width - result }
Затем присвойте элементу newSize
const [element] = this.$refs[`element-${this.beforeChangeSize.col}`] element.style.width = `${newSize}px` this.beforeChangeSize = {}
Сбросить стиль текущей кнопки изменения размера
const [resizeButton] = this.$refs[`resize-${this.beforeChangeSize.col}`] resizeButton.style.left = 'auto'
Сбросьте beforeChangeSize на пустой объект.
this.beforeChangeSize = {};
Полный код
Песочница
Спасибо за чтение 🎉