mirror of
https://github.com/siyuan-note/siyuan.git
synced 2025-12-16 22:50:13 +01:00
This commit is contained in:
parent
00dda414db
commit
b6345a8cbc
2 changed files with 49 additions and 77 deletions
|
|
@ -1,3 +1,5 @@
|
|||
import {Constants} from "../../constants";
|
||||
|
||||
export const cancelDrag = () => {
|
||||
const ghostElement = document.getElementById("dragGhost");
|
||||
if (ghostElement) {
|
||||
|
|
@ -18,7 +20,49 @@ export const cancelDrag = () => {
|
|||
}
|
||||
ghostElement.remove();
|
||||
document.onmousemove = null;
|
||||
// 通知取消拖拽,供相关模块停止滚动动画等
|
||||
window.dispatchEvent(new CustomEvent("drag-cancel"));
|
||||
stopScrollAnimation();
|
||||
}
|
||||
};
|
||||
|
||||
const dragoverScroll: {
|
||||
animationId?: number,
|
||||
element?: Element,
|
||||
space?: number // -1 向上;1 向下
|
||||
lastTime?: number
|
||||
} = {};
|
||||
export const stopScrollAnimation = () => {
|
||||
if (dragoverScroll.animationId) {
|
||||
cancelAnimationFrame(dragoverScroll.animationId);
|
||||
dragoverScroll.animationId = null;
|
||||
dragoverScroll.element = null;
|
||||
dragoverScroll.space = null;
|
||||
dragoverScroll.lastTime = null;
|
||||
}
|
||||
};
|
||||
const scrollAnimation = (timestamp: number) => {
|
||||
if (!dragoverScroll.lastTime) {
|
||||
dragoverScroll.lastTime = timestamp - 8;
|
||||
}
|
||||
dragoverScroll.element.scroll({
|
||||
top: dragoverScroll.element.scrollTop + (timestamp - dragoverScroll.lastTime) * dragoverScroll.space / 64
|
||||
});
|
||||
// 使用 requestAnimationFrame 继续动画
|
||||
dragoverScroll.animationId = requestAnimationFrame(scrollAnimation);
|
||||
dragoverScroll.lastTime = timestamp;
|
||||
};
|
||||
|
||||
export const dragOverScroll = (moveEvent: MouseEvent, contentRect: DOMRect, element: Element) => {
|
||||
const dragToUp = moveEvent.clientY < contentRect.top + Constants.SIZE_SCROLL_TB;
|
||||
if (dragToUp ||
|
||||
moveEvent.clientY > contentRect.bottom - Constants.SIZE_SCROLL_TB) {
|
||||
dragoverScroll.space = dragToUp ? moveEvent.clientY - contentRect.top - Constants.SIZE_SCROLL_TB :
|
||||
moveEvent.clientY - contentRect.bottom + Constants.SIZE_SCROLL_TB;
|
||||
if (!dragoverScroll.animationId) {
|
||||
dragoverScroll.element = element;
|
||||
dragoverScroll.animationId = requestAnimationFrame(scrollAnimation);
|
||||
}
|
||||
} else {
|
||||
// 离开滚动区域时停止滚动
|
||||
stopScrollAnimation();
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import {Editor} from "../../editor";
|
|||
import {mathRender} from "../../protyle/render/mathRender";
|
||||
import {genEmptyElement} from "../../block/util";
|
||||
import {focusBlock, focusByWbr} from "../../protyle/util/selection";
|
||||
import {dragOverScroll, stopScrollAnimation} from "../../boot/globalEvent/dragover";
|
||||
|
||||
export class Outline extends Model {
|
||||
public tree: Tree;
|
||||
|
|
@ -36,9 +37,6 @@ export class Outline extends Model {
|
|||
public blockId: string;
|
||||
public isPreview: boolean;
|
||||
private preFilterExpandIds: string[] | null = null;
|
||||
private scrollAnimationId: number | null = null;
|
||||
private scrollLastFrameTime: number = 0;
|
||||
private scrollCurrentFPS: number = 60;
|
||||
|
||||
constructor(options: {
|
||||
app: App,
|
||||
|
|
@ -334,21 +332,6 @@ export class Outline extends Model {
|
|||
}, response => {
|
||||
this.update(response);
|
||||
});
|
||||
|
||||
window.addEventListener("drag-cancel", () => {
|
||||
this.stopScrollAnimation();
|
||||
});
|
||||
}
|
||||
|
||||
private stopScrollAnimation() {
|
||||
if (this.scrollAnimationId) {
|
||||
if (typeof cancelAnimationFrame !== "undefined") {
|
||||
cancelAnimationFrame(this.scrollAnimationId);
|
||||
} else {
|
||||
clearTimeout(this.scrollAnimationId);
|
||||
}
|
||||
this.scrollAnimationId = null;
|
||||
}
|
||||
}
|
||||
|
||||
private bindSort() {
|
||||
|
|
@ -386,62 +369,7 @@ export class Outline extends Model {
|
|||
}
|
||||
ghostElement.style.top = moveEvent.clientY + "px";
|
||||
ghostElement.style.left = moveEvent.clientX + "px";
|
||||
// 检查是否在滚动边界区域
|
||||
if (moveEvent.clientY < contentRect.top + Constants.SIZE_SCROLL_TB || moveEvent.clientY > contentRect.bottom - Constants.SIZE_SCROLL_TB) {
|
||||
// 如果还没有开始滚动,则开始持续滚动
|
||||
if (!this.scrollAnimationId) {
|
||||
const scrollDirection = moveEvent.clientY < contentRect.top + Constants.SIZE_SCROLL_TB ? -1 : 1;
|
||||
this.scrollLastFrameTime = performance.now();
|
||||
let scrollFrameCount = 0;
|
||||
|
||||
const scrollAnimation = (currentTime: number) => {
|
||||
if (!this.scrollAnimationId) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 每隔 20 帧重新计算一次帧率
|
||||
if (scrollFrameCount % 20 === 0) {
|
||||
const deltaTime = currentTime - this.scrollLastFrameTime;
|
||||
this.scrollLastFrameTime = currentTime;
|
||||
// 计算过去 20 帧的平均帧率
|
||||
this.scrollCurrentFPS = deltaTime > 0 ? (20 * 1000) / deltaTime : 60;
|
||||
}
|
||||
scrollFrameCount++;
|
||||
|
||||
// 基于当前帧率计算滚动步长,确保等效于 60fps 时的 16px/帧
|
||||
const baseScrollStep = 16;
|
||||
const targetFPS = 60;
|
||||
const scrollStep = baseScrollStep * (targetFPS / this.scrollCurrentFPS);
|
||||
|
||||
this.element.scroll({
|
||||
top: this.element.scrollTop + scrollStep * scrollDirection
|
||||
});
|
||||
|
||||
// 使用 requestAnimationFrame 继续动画
|
||||
this.scrollAnimationId = requestAnimationFrame(scrollAnimation);
|
||||
};
|
||||
|
||||
// 检查浏览器是否支持 requestAnimationFrame
|
||||
if (typeof requestAnimationFrame !== "undefined") {
|
||||
this.scrollAnimationId = requestAnimationFrame(scrollAnimation);
|
||||
} else {
|
||||
// 回退到 setTimeout 方法
|
||||
const scrollInterval = 16; // 约 60fps
|
||||
const scrollStep = 16; // 每次滚动的距离
|
||||
|
||||
const scrollAnimationFallback = () => {
|
||||
this.element.scroll({
|
||||
top: this.element.scrollTop + scrollStep * scrollDirection
|
||||
});
|
||||
this.scrollAnimationId = window.setTimeout(scrollAnimationFallback, scrollInterval);
|
||||
};
|
||||
this.scrollAnimationId = window.setTimeout(scrollAnimationFallback, scrollInterval);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 离开滚动区域时停止滚动
|
||||
this.stopScrollAnimation();
|
||||
}
|
||||
dragOverScroll(moveEvent, contentRect, this.element);
|
||||
if (!this.element.contains(moveEvent.target as Element)) {
|
||||
this.element.querySelectorAll(".dragover__top, .dragover__bottom, .dragover, .dragover__current").forEach(item => {
|
||||
item.classList.remove("dragover__top", "dragover__bottom", "dragover", "dragover__current");
|
||||
|
|
@ -479,7 +407,7 @@ export class Outline extends Model {
|
|||
ghostElement?.remove();
|
||||
item.style.opacity = "";
|
||||
// 清理滚动动画
|
||||
this.stopScrollAnimation();
|
||||
stopScrollAnimation();
|
||||
if (!selectItem) {
|
||||
selectItem = this.element.querySelector(".dragover__top, .dragover__bottom, .dragover");
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue