mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-06-28 02:51:56 +08:00
实现文件浏览器的拖动分隔条功能
This commit is contained in:
@@ -136,6 +136,12 @@ const sort = ref('name')
|
||||
// 是否显示目录树
|
||||
const showDirTree = ref(false)
|
||||
|
||||
// 拖动分隔条相关
|
||||
const navigatorWidth = ref(280) // 初始宽度
|
||||
const isDragging = ref(false)
|
||||
const dragStartX = ref(0)
|
||||
const dragStartWidth = ref(0)
|
||||
|
||||
// 计算属性
|
||||
const storagesArray = computed(() => {
|
||||
return props.storages?.map(item => ({
|
||||
@@ -181,6 +187,58 @@ function fileListUpdated(items: FileItem[]) {
|
||||
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大小控制
|
||||
const scrollStyle = computed(() => {
|
||||
return appMode
|
||||
@@ -219,8 +277,14 @@ const fileListStyle = computed(() => {
|
||||
:items="fileListItems"
|
||||
:endpoints="endpoints"
|
||||
:axios="axios"
|
||||
:style="{ width: `${navigatorWidth}px`, minWidth: `${navigatorWidth}px` }"
|
||||
@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
|
||||
:item="item"
|
||||
:storage="activeStorage"
|
||||
@@ -231,6 +295,7 @@ const fileListStyle = computed(() => {
|
||||
:sort="sort"
|
||||
:listStyle="fileListStyle"
|
||||
:showTree="showDirTree"
|
||||
:style="{ flex: 1 }"
|
||||
@pathchanged="pathChanged"
|
||||
@loading="loadingChanged"
|
||||
@refreshed="refreshPending = false"
|
||||
@@ -243,3 +308,64 @@ const fileListStyle = computed(() => {
|
||||
</div>
|
||||
</div>
|
||||
</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