mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-05 15:36:49 +08:00
实现文件浏览器的拖动分隔条功能
This commit is contained in:
@@ -136,6 +136,12 @@ const sort = ref('name')
|
|||||||
// 是否显示目录树
|
// 是否显示目录树
|
||||||
const showDirTree = ref(false)
|
const showDirTree = ref(false)
|
||||||
|
|
||||||
|
// 拖动分隔条相关
|
||||||
|
const navigatorWidth = ref(280) // 初始宽度
|
||||||
|
const isDragging = ref(false)
|
||||||
|
const dragStartX = ref(0)
|
||||||
|
const dragStartWidth = ref(0)
|
||||||
|
|
||||||
// 计算属性
|
// 计算属性
|
||||||
const storagesArray = computed(() => {
|
const storagesArray = computed(() => {
|
||||||
return props.storages?.map(item => ({
|
return props.storages?.map(item => ({
|
||||||
@@ -181,6 +187,58 @@ function fileListUpdated(items: FileItem[]) {
|
|||||||
fileListItems.value = items
|
fileListItems.value = items
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 阻止选择事件
|
||||||
|
function preventSelect(event: Event) {
|
||||||
|
event.preventDefault()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拖动分隔条相关方法
|
||||||
|
function startDrag(event: MouseEvent) {
|
||||||
|
event.preventDefault() // 阻止默认行为
|
||||||
|
event.stopPropagation() // 阻止事件冒泡
|
||||||
|
|
||||||
|
isDragging.value = true
|
||||||
|
dragStartX.value = event.clientX
|
||||||
|
dragStartWidth.value = navigatorWidth.value
|
||||||
|
|
||||||
|
document.addEventListener('mousemove', handleDrag, { passive: false })
|
||||||
|
document.addEventListener('mouseup', stopDrag, { passive: false })
|
||||||
|
document.addEventListener('selectstart', preventSelect) // 阻止选择开始
|
||||||
|
|
||||||
|
document.body.style.cursor = 'col-resize'
|
||||||
|
document.body.style.userSelect = 'none'
|
||||||
|
;(document.body.style as any).webkitUserSelect = 'none' // Safari兼容
|
||||||
|
;(document.body.style as any).mozUserSelect = 'none' // Firefox兼容
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDrag(event: MouseEvent) {
|
||||||
|
if (!isDragging.value) return
|
||||||
|
|
||||||
|
event.preventDefault() // 阻止默认行为
|
||||||
|
|
||||||
|
const deltaX = event.clientX - dragStartX.value
|
||||||
|
const newWidth = dragStartWidth.value + deltaX
|
||||||
|
|
||||||
|
// 设置最小和最大宽度限制
|
||||||
|
const minWidth = 200
|
||||||
|
const maxWidth = window.innerWidth * 0.6
|
||||||
|
|
||||||
|
navigatorWidth.value = Math.max(minWidth, Math.min(maxWidth, newWidth))
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopDrag() {
|
||||||
|
isDragging.value = false
|
||||||
|
document.removeEventListener('mousemove', handleDrag)
|
||||||
|
document.removeEventListener('mouseup', stopDrag)
|
||||||
|
document.removeEventListener('selectstart', preventSelect)
|
||||||
|
|
||||||
|
document.body.style.cursor = ''
|
||||||
|
document.body.style.userSelect = ''
|
||||||
|
;(document.body.style as any).webkitUserSelect = ''
|
||||||
|
;(document.body.style as any).mozUserSelect = ''
|
||||||
|
}
|
||||||
|
|
||||||
// 外层DIV大小控制
|
// 外层DIV大小控制
|
||||||
const scrollStyle = computed(() => {
|
const scrollStyle = computed(() => {
|
||||||
return appMode
|
return appMode
|
||||||
@@ -219,8 +277,14 @@ const fileListStyle = computed(() => {
|
|||||||
:items="fileListItems"
|
:items="fileListItems"
|
||||||
:endpoints="endpoints"
|
:endpoints="endpoints"
|
||||||
:axios="axios"
|
:axios="axios"
|
||||||
|
:style="{ width: `${navigatorWidth}px`, minWidth: `${navigatorWidth}px` }"
|
||||||
@navigate="pathChanged"
|
@navigate="pathChanged"
|
||||||
/>
|
/>
|
||||||
|
<!-- 拖动分隔条 -->
|
||||||
|
<div v-if="showDirTree" class="divider" :class="{ 'divider-dragging': isDragging }" @mousedown="startDrag">
|
||||||
|
<div class="divider-line"></div>
|
||||||
|
<VIcon class="divider-icon" size="small">mdi-drag-vertical</VIcon>
|
||||||
|
</div>
|
||||||
<FileList
|
<FileList
|
||||||
:item="item"
|
:item="item"
|
||||||
:storage="activeStorage"
|
:storage="activeStorage"
|
||||||
@@ -231,6 +295,7 @@ const fileListStyle = computed(() => {
|
|||||||
:sort="sort"
|
:sort="sort"
|
||||||
:listStyle="fileListStyle"
|
:listStyle="fileListStyle"
|
||||||
:showTree="showDirTree"
|
:showTree="showDirTree"
|
||||||
|
:style="{ flex: 1 }"
|
||||||
@pathchanged="pathChanged"
|
@pathchanged="pathChanged"
|
||||||
@loading="loadingChanged"
|
@loading="loadingChanged"
|
||||||
@refreshed="refreshPending = false"
|
@refreshed="refreshPending = false"
|
||||||
@@ -243,3 +308,64 @@ const fileListStyle = computed(() => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.divider {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: transparent;
|
||||||
|
cursor: col-resize;
|
||||||
|
inline-size: 4px;
|
||||||
|
transition: background-color 0.2s ease;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider:hover {
|
||||||
|
background-color: rgba(var(--v-theme-on-surface), 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider-dragging {
|
||||||
|
background-color: rgba(var(--v-theme-primary), 0.12) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider-line {
|
||||||
|
background-color: rgba(var(--v-theme-outline), 0.3);
|
||||||
|
block-size: 100%;
|
||||||
|
inline-size: 1px;
|
||||||
|
transition: background-color 0.2s ease;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider-dragging .divider-line {
|
||||||
|
background-color: rgb(var(--v-theme-primary)) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider:hover .divider-line {
|
||||||
|
background-color: rgba(var(--v-theme-primary), 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider-icon {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
padding: 2px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background-color: rgba(var(--v-theme-surface), 0.9);
|
||||||
|
color: rgba(var(--v-theme-on-surface-variant), 0.6);
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider-dragging .divider-icon {
|
||||||
|
background-color: rgba(var(--v-theme-surface), 0.95);
|
||||||
|
color: rgb(var(--v-theme-primary));
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider:hover .divider-icon {
|
||||||
|
color: rgba(var(--v-theme-primary), 0.9);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user