From 947ba5b6c71ac3489106d40afe09345569e0238c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E7=AB=8B=E5=B8=AE?= <3294713004@qq.com> Date: Tue, 28 Oct 2025 17:02:24 +0800 Subject: [PATCH] =?UTF-8?q?feat(core):=20Mixly.Drag=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=AF=B9=E7=A7=BB=E5=8A=A8=E7=AB=AF=E8=A7=A6=E6=91=B8=E6=89=8B?= =?UTF-8?q?=E5=8A=BF=E7=9A=84=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/css/drag.css | 36 +++++++---- common/modules/mixly-modules/common/drag.js | 71 +++++++++++++++++++++ 2 files changed, 95 insertions(+), 12 deletions(-) diff --git a/common/css/drag.css b/common/css/drag.css index d707c6d0..a1a17152 100644 --- a/common/css/drag.css +++ b/common/css/drag.css @@ -4,6 +4,10 @@ width: 100%; cursor: s-resize; z-index: 100; + transition: opacity 0.2s ease; + touch-action: none; + user-select: none; + -webkit-user-select: none; } .vertical-line { @@ -12,35 +16,39 @@ height: 100%; cursor: w-resize; z-index: 100; + transition: opacity 0.2s ease; + touch-action: none; + user-select: none; + -webkit-user-select: none; } @-webkit-keyframes drag-fadein { - 0% {opacity: 0;} - 100% {opacity: 1;} + 0% { opacity: 0; } + 100% { opacity: 1; } } @keyframes drag-fadein { - 0% {opacity: 0;} - 100% {opacity: 1;} + 0% { opacity: 0; } + 100% { opacity: 1; } } .horizontal-line:hover, .vertical-line:hover { -webkit-animation-name: drag-fadein; + animation-name: drag-fadein; animation-duration: 0.2s; - animation-delay: .3s; + animation-delay: .2s; animation-fill-mode: forwards; } .horizontal-line:active, -.vertical-line:active { - -webkit-animation-name: drag-fadein; - animation-duration: 0.2s; - animation-delay: .3s; - animation-fill-mode: forwards; +.vertical-line:active, +.drag-s-container.dragging > .horizontal-line, +.drag-w-container.dragging > .vertical-line { + opacity: 1; + animation: none; } -/* 由于拖拽而产生尺寸改变元素的容器 */ .drag-s-container { display: flex; flex-direction: column; @@ -53,22 +61,26 @@ flex-wrap: nowrap; } -/* 拖拽元素的容器 */ .drag-elem { position: absolute; opacity: 0; + touch-action: none; + user-select: none; + -webkit-user-select: none; } .drag-s-elem { width: 100%; height: 4px; cursor: s-resize; + touch-action: none; } .drag-w-elem { width: 4px; height: 100%; cursor: w-resize; + touch-action: none; } html[data-bs-theme=light] .horizontal-line, diff --git a/common/modules/mixly-modules/common/drag.js b/common/modules/mixly-modules/common/drag.js index 7e746686..fb29dc13 100644 --- a/common/modules/mixly-modules/common/drag.js +++ b/common/modules/mixly-modules/common/drag.js @@ -81,6 +81,17 @@ class Drag { this.#addEventListener_(); } + #getTouch_(event) { + if (event.touches && event.touches.length > 0) { + return { + clientX: event.touches[0].clientX, + clientY: event.touches[0].clientY + }; + } else { + return { clientX: 0, clientY: 0 }; + } + }; + #addEventListener_() { const dragElem = this.$dragElem[0]; const container = this.$container[0]; @@ -143,6 +154,66 @@ class Drag { document.onmouseup = null; }; }; + + dragElem.ontouchstart = (touchEvent) => { + touchEvent.preventDefault(); + this.$container.addClass('dragging'); + let touch = this.#getTouch_(touchEvent); + let dis, prev; + if (type === 'h') { + dis = touch.clientY; + dragElem.top = dragElem.offsetTop; + } else { + dis = touch.clientX; + dragElem.left = dragElem.offsetLeft; + } + const prevSize = this.size; + + document.ontouchmove = (moveEvent) => { + moveEvent.preventDefault(); + this.runEvent('ondragStart'); + const current = this.#getTouch_(moveEvent); + let iT, maxT, minT = parseInt(min), movement; + + if (type === 'h') { + iT = dragElem.top + (current.clientY - dis); + maxT = container.clientHeight - minT; + movement = current.clientY - dis; + } else { + iT = dragElem.left + (current.clientX - dis); + maxT = container.clientWidth - minT; + movement = current.clientX - dis; + } + + iT += 1; + if (prev === iT) return false; + prev = iT; + + if (full[0] && movement < 0 && iT < minT * 0.4) { // 向上或向左 + this.changeTo('0%'); + this.runEvent('onfull', Drag.Extend.NEGATIVE); + } else if (full[1] && movement > 0 && iT > (maxT + minT * 0.6)) { // 向下或向右 + this.changeTo('100%'); + this.runEvent('onfull', Drag.Extend.POSITIVE); + } else if (iT < maxT && iT > minT) { // 中间区域 + let shown = this.shown; + this.changeTo(iT); + if (shown !== Drag.Extend.BOTH) { + this.runEvent('exitfull', shown); + } + } + + this.runEvent('ondragEnd'); + return false; + }; + + document.ontouchend = () => { + this.$container.removeClass('dragging'); + this.prevSize = prevSize; + document.ontouchmove = null; + document.ontouchend = null; + }; + }; } changeTo(part) {