feat(LivePreviewEditor): 为目录侧边栏添加宽度拖拽调整功能
添加目录侧边栏的宽度拖拽调整支持,提升用户自定义布局的灵活性。 - 新增拖拽手柄组件,用户可调整侧边栏宽度(150px-600px范围) - 拖拽时提供视觉反馈(光标变化、手柄高亮) - 移除侧边栏固定宽度样式,改为JS动态控制 - 拖拽期间禁用过渡动画以避免视觉延迟
This commit is contained in:
parent
e1c97dd8f0
commit
2c6b978d8c
|
|
@ -4,8 +4,12 @@
|
|||
|
||||
<div class="editor-main">
|
||||
<!-- 目录大纲侧边栏 -->
|
||||
<div class="toc-sidebar" :class="{ collapsed: !showToc }">
|
||||
<div class="toc-content">
|
||||
<div
|
||||
class="toc-sidebar"
|
||||
:class="{ collapsed: !showToc, resizing: isResizing }"
|
||||
:style="{ width: showToc ? `${tocWidth}px` : '0px' }"
|
||||
>
|
||||
<div class="toc-content" :style="{ width: `${tocWidth}px` }">
|
||||
<div v-if="toc.length === 0" class="toc-empty">暂无大纲</div>
|
||||
<div
|
||||
v-for="(item, index) in toc"
|
||||
|
|
@ -20,6 +24,13 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 拖拽手柄 -->
|
||||
<div
|
||||
v-if="showToc"
|
||||
class="toc-resizer"
|
||||
@mousedown.prevent="startResize"
|
||||
></div>
|
||||
|
||||
<codemirror
|
||||
v-model="code"
|
||||
placeholder="请输入 Markdown 内容..."
|
||||
|
|
@ -84,6 +95,36 @@ const { applyHeading, wrapSelection, prefixLines, insertLink } = useMarkdownActi
|
|||
// 目录相关
|
||||
const showToc = ref(true);
|
||||
const toc = shallowRef([]);
|
||||
const tocWidth = ref(220);
|
||||
const isResizing = ref(false);
|
||||
let startX = 0;
|
||||
let startWidth = 0;
|
||||
|
||||
const startResize = (e) => {
|
||||
isResizing.value = true;
|
||||
startX = e.clientX;
|
||||
startWidth = tocWidth.value;
|
||||
|
||||
document.addEventListener('mousemove', handleResize);
|
||||
document.addEventListener('mouseup', stopResize);
|
||||
document.body.style.cursor = 'col-resize';
|
||||
document.body.style.userSelect = 'none';
|
||||
};
|
||||
|
||||
const handleResize = (e) => {
|
||||
if (!isResizing.value) return;
|
||||
const diff = e.clientX - startX;
|
||||
const newWidth = Math.max(150, Math.min(600, startWidth + diff));
|
||||
tocWidth.value = newWidth;
|
||||
};
|
||||
|
||||
const stopResize = () => {
|
||||
isResizing.value = false;
|
||||
document.removeEventListener('mousemove', handleResize);
|
||||
document.removeEventListener('mouseup', stopResize);
|
||||
document.body.style.cursor = '';
|
||||
document.body.style.userSelect = '';
|
||||
};
|
||||
|
||||
const debounce = (fn, delay) => {
|
||||
let timer = null;
|
||||
|
|
@ -480,16 +521,20 @@ onUnmounted(() => {
|
|||
}
|
||||
|
||||
.toc-sidebar {
|
||||
width: 220px;
|
||||
/* width: 220px; 由 JS 控制 */
|
||||
flex-shrink: 0;
|
||||
border-right: 1px solid var(--border-color);
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
background-color: var(--card-background);
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition: width 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.toc-sidebar.resizing {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.toc-sidebar.collapsed {
|
||||
width: 0;
|
||||
opacity: 0;
|
||||
|
|
@ -497,10 +542,25 @@ onUnmounted(() => {
|
|||
}
|
||||
|
||||
.toc-content {
|
||||
width: 220px; /* 固定宽度,防止内容挤压 */
|
||||
/* width: 220px; 由 JS 控制 */
|
||||
padding: 12px 0;
|
||||
}
|
||||
|
||||
.toc-resizer {
|
||||
width: 4px;
|
||||
cursor: col-resize;
|
||||
background-color: transparent;
|
||||
transition: background-color 0.2s;
|
||||
flex-shrink: 0;
|
||||
margin-left: -1px; /* 重叠边框 */
|
||||
z-index: 10;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.toc-resizer:hover, .toc-sidebar.resizing + .toc-resizer {
|
||||
background-color: var(--primary-color);
|
||||
}
|
||||
|
||||
.toc-empty {
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
|
|
|
|||
Loading…
Reference in New Issue