feat: 树状菜单聚焦当前打开文章

1. 树状菜单聚焦当前打开文章
2. 优化树状菜单样式
This commit is contained in:
xiaozzzi 2024-04-07 02:43:52 +08:00
parent 2f8eaff819
commit 61ed63732a
4 changed files with 64 additions and 48 deletions

View File

@ -6,22 +6,25 @@
</div> </div>
<!-- --> <!-- -->
<div class="doc-tree-operator"> <div class="doc-tree-operator">
<el-tooltip effect="light" popper-class="is-small" placement="top" :offset="4" :hide-after="0" content="显示排序"> <el-tooltip effect="light" popper-class="is-small" placement="top" :hide-after="0" content="显示排序">
<div class="iconbl bl-a-leftdirection-line" @click="handleShowSort"></div> <div class="iconbl bl-a-leftdirection-line" @click="handleShowSort"></div>
</el-tooltip> </el-tooltip>
<el-tooltip effect="light" popper-class="is-small" placement="top" :offset="4" :hide-after="0" content="根目录下新建文章"> <el-tooltip effect="light" popper-class="is-small" placement="top" :hide-after="0" content="根目录下新建文章">
<div class="iconbl bl-fileadd-line" @click="addArticleToRoot()"></div> <div class="iconbl bl-fileadd-line" @click="addArticleToRoot()"></div>
</el-tooltip> </el-tooltip>
<el-tooltip effect="light" popper-class="is-small" placement="top" :offset="4" :hide-after="0" content="根目录下新建文件夹"> <el-tooltip effect="light" popper-class="is-small" placement="top" :hide-after="0" content="根目录下新建文件夹">
<div class="iconbl bl-folderadd-line" @click="addFolderToRoot()"></div> <div class="iconbl bl-folderadd-line" @click="addFolderToRoot()"></div>
</el-tooltip> </el-tooltip>
<el-tooltip effect="light" popper-class="is-small" placement="top" :offset="4" :hide-after="0" :show-after="1000" content="搜索"> <el-tooltip effect="light" popper-class="is-small" placement="top" :hide-after="0" :show-after="1000" content="搜索">
<div class="iconbl bl-search-line" @click="showTreeFilter()"></div> <div class="iconbl bl-search-item" @click="showTreeFilter()"></div>
</el-tooltip> </el-tooltip>
<el-tooltip effect="light" popper-class="is-small" placement="top" :offset="4" :hide-after="0" :show-after="1000" content="刷新"> <el-tooltip effect="light" popper-class="is-small" placement="top" :hide-after="0" :show-after="1000" content="刷新">
<div class="iconbl bl-refresh-line" @click="refreshDocTree()"></div> <div class="iconbl bl-refresh-line" @click="refreshDocTree()"></div>
</el-tooltip> </el-tooltip>
<el-tooltip effect="light" popper-class="is-small" placement="top" :offset="4" :hide-after="0" :show-after="1000" content="折叠所有文件夹"> <el-tooltip effect="light" popper-class="is-small" placement="top" :hide-after="0" :show-after="1000" content="选中当前文章">
<div class="iconbl bl-collimation" @click="collimationCurrentArticle"></div>
</el-tooltip>
<el-tooltip effect="light" popper-class="is-small" placement="top" :hide-after="0" :show-after="1000" content="折叠所有文件夹">
<div class="iconbl bl-collapse" @click="collapseAll"></div> <div class="iconbl bl-collapse" @click="collapseAll"></div>
</el-tooltip> </el-tooltip>
<div class="doc-tree-search" ref="DocTreeSearch" v-show="isShowTreeFilter"> <div class="doc-tree-search" ref="DocTreeSearch" v-show="isShowTreeFilter">
@ -63,7 +66,7 @@
@nodeCollapse="handleNodeCollapse" @nodeCollapse="handleNodeCollapse"
@nodeDrop="handleDrop"> @nodeDrop="handleDrop">
<template #default="{ node, data }"> <template #default="{ node, data }">
<div class="menu-item-wrapper" @click.right="handleClickRightMenu($event, data)"> <div class="menu-item-wrapper" :id="'article-doc-wrapper-' + data.i" @click.right="handleClickRightMenu($event, data)">
<div :class="[viewStyle.isShowSubjectStyle ? (data.t?.includes('subject') ? 'subject-title' : 'doc-title') : 'doc-title']"> <div :class="[viewStyle.isShowSubjectStyle ? (data.t?.includes('subject') ? 'subject-title' : 'doc-title') : 'doc-title']">
<div v-if="isShowSort" class="sort-tag" :style="{ backgroundColor: getColor(node) }">{{ data.s }}</div> <div v-if="isShowSort" class="sort-tag" :style="{ backgroundColor: getColor(node) }">{{ data.s }}</div>
<div class="doc-name"> <div class="doc-name">
@ -97,9 +100,9 @@
</el-tree> </el-tree>
<bl-row v-else class="doc-trees-placeholder" just="center"> <bl-row v-else class="doc-trees-placeholder" just="center">
无文档点击 无文档点击
<div class="iconbl bl-a-texteditorhighlightcolor-line" @click="addArticleToRoot()"></div> <div class="iconbl bl-fileadd-line" @click="addArticleToRoot()"></div>
/ /
<div class="iconbl bl-a-folderon-line" @click="addFolderToRoot()"></div> <div class="iconbl bl-folderadd-line" @click="addFolderToRoot()"></div>
添加 添加
</bl-row> </bl-row>
</div> </div>
@ -120,18 +123,10 @@
<span class="iconbl bl-a-rightsmallline-line"></span> <span class="iconbl bl-a-rightsmallline-line"></span>
<span class="iconbl bl-apps-line"></span>更多 <span class="iconbl bl-apps-line"></span>更多
<div class="tree-menu-level2" :style="rMenuLevel2"> <div class="tree-menu-level2" :style="rMenuLevel2">
<div v-if="curDoc.o === 0" @click="open(1)"> <div v-if="curDoc.o === 0" @click="open(1)"><span class="iconbl bl-a-cloudupload-line"></span>公开{{ curDocType }}</div>
<span class="iconbl bl-a-cloudupload-line"></span>公开{{ curDoc.ty === 3 ? '文章' : '文件夹' }} <div v-if="curDoc.o === 1" @click="open(0)"><span class="iconbl bl-a-clouddownload-line"></span>取消{{ curDocType }}公开</div>
</div> <div v-if="curDoc.star === 0" @click="star(1)"><span class="iconbl bl-star-fill"></span>收藏{{ curDocType }}</div>
<div v-if="curDoc.o === 1" @click="open(0)"> <div v-if="curDoc.star === 1" @click="star(0)"><span class="iconbl bl-star-line"></span>取消收藏{{ curDocType }}</div>
<span class="iconbl bl-a-clouddownload-line"></span>取消{{ curDoc.ty === 3 ? '文章' : '文件夹' }}公开
</div>
<div v-if="curDoc.star === 0" @click="star(1)">
<span class="iconbl bl-star-fill"></span>收藏{{ curDoc.ty === 3 ? '文章' : '文件夹' }}
</div>
<div v-if="curDoc.star === 1" @click="star(0)">
<span class="iconbl bl-star-line"></span>取消收藏{{ curDoc.ty === 3 ? '文章' : '文件夹' }}
</div>
<div v-if="curDoc.ty === 3 && !curDoc.t.includes('toc')" @click="addArticleTag('toc')"> <div v-if="curDoc.ty === 3 && !curDoc.t.includes('toc')" @click="addArticleTag('toc')">
<span class="iconbl bl-list-ordered"></span>设为专题目录 <span class="iconbl bl-list-ordered"></span>设为专题目录
</div> </div>
@ -177,7 +172,7 @@
<div v-if="curDoc.ty === 3 && curDoc.o === 1" @click="createUrl('open')"><span class="iconbl bl-planet-line"></span>博客中查看</div> <div v-if="curDoc.ty === 3 && curDoc.o === 1" @click="createUrl('open')"><span class="iconbl bl-planet-line"></span>博客中查看</div>
<div v-if="curDoc.ty === 3 && curDoc.o === 1" @click="handleArticleQrCodeDialog"><span class="iconbl bl-qr-code-line"></span>博客二维码</div> <div v-if="curDoc.ty === 3 && curDoc.o === 1" @click="handleArticleQrCodeDialog"><span class="iconbl bl-qr-code-line"></span>博客二维码</div>
<div class="menu-item-divider"></div> <div class="menu-item-divider"></div>
<div @click="delDoc()"><span class="iconbl bl-a-fileprohibit-line"></span>删除{{ curDocType }}</div> <div @click="delDoc()"><span class="iconbl bl-delete-line"></span>删除{{ curDocType }}</div>
</div> </div>
</div> </div>
</Teleport> </Teleport>
@ -257,6 +252,7 @@
width: 700px; width: 700px;
word-break: break-all; word-break: break-all;
"> ">
<div>{{ articleCurrnetId }}</div>
<div>当前选中{{ docTreeCurrentId }}</div> <div>当前选中{{ docTreeCurrentId }}</div>
<div>所有展开{{ Array.from(docTreeCurrentExpandId) + '' }}</div> <div>所有展开{{ Array.from(docTreeCurrentExpandId) + '' }}</div>
</div> </div>
@ -354,6 +350,25 @@ const getRouteQueryParams = () => {
docTreeCurrentId.value = articleId docTreeCurrentId.value = articleId
const parentNode = DocTreeRef.value.getNode(articleId) const parentNode = DocTreeRef.value.getNode(articleId)
setCurrentKey({ i: articleId, p: parentNode.data.p, ty: 3 }) setCurrentKey({ i: articleId, p: parentNode.data.p, ty: 3 })
const ele = document.getElementById('article-doc-wrapper-' + articleId)
if (ele) {
;(DocTreeContainer.value as Element).scrollTop = ele.offsetTop
}
})
}
}
/**
* 聚焦当前打开的文章
*/
const collimationCurrentArticle = () => {
if (!isEmpty(docTreeData.value) && isNotBlank(articleCurrnetId.value)) {
DocTreeRef.value.setCurrentKey(articleCurrnetId.value)
nextTick(() => {
const ele = document.getElementById('article-doc-wrapper-' + articleCurrnetId.value)
if (ele) {
;(DocTreeContainer.value as Element).scrollTop = ele.offsetTop
}
}) })
} }
} }
@ -429,7 +444,7 @@ const endLoading = () => {
//#endregion //#endregion
//#region ----------------------------------------< >-------------------------------------- //#region ----------------------------------------< >--------------------------------------
const articleCurrnetId = ref('')
// , // ,
const docTreeCurrentId = ref('') const docTreeCurrentId = ref('')
// //
@ -465,6 +480,7 @@ const setCurrentKey = (tree: { i: string; p: string; ty: DocType }, node?: Node,
} else if (tree.ty === 3) { } else if (tree.ty === 3) {
docTreeCurrentId.value = tree.i docTreeCurrentId.value = tree.i
docTreeCurrentExpandId.value.add(tree.p) docTreeCurrentExpandId.value.add(tree.p)
articleCurrnetId.value = tree.i
} }
DocTreeRef.value.setCurrentKey(tree.i) DocTreeRef.value.setCurrentKey(tree.i)
} }
@ -563,9 +579,9 @@ const handleNodeExpand = (tree: DocTree, _node: Node) => {
} }
/** /**
* 处理节点缩起, 同时清除所有子节点的展开状态 * 处理节点折叠, 同时清除所有子节点的展开状态
*/ */
const handleNodeCollapse = (tree: DocTree, node: Node) => { const handleNodeCollapse = async (tree: DocTree, node: Node) => {
docTreeCurrentExpandId.value.delete(tree.i) docTreeCurrentExpandId.value.delete(tree.i)
collapseChilds(node) collapseChilds(node)
} }
@ -573,7 +589,7 @@ const handleNodeCollapse = (tree: DocTree, node: Node) => {
/** /**
* 递归缩起所有子节点 * 递归缩起所有子节点
*/ */
const collapseChilds = (node: Node) => { const collapseChilds = async (node: Node) => {
for (let i = 0; i < node.childNodes.length; i++) { for (let i = 0; i < node.childNodes.length; i++) {
const child = node.childNodes[i] const child = node.childNodes[i]
if (child.isLeaf) { if (child.isLeaf) {

View File

@ -4,37 +4,37 @@
// 操作树状菜单的工具栏 // 操作树状菜单的工具栏
.doc-tree-operator { .doc-tree-operator {
@include box(100%, 28px); @include box(100%, 30px);
@include flex(row, center, center); @include flex(row, center, center);
@include themeColor(#909399, #969696); @include themeColor(#909399, #969696);
position: relative; position: relative;
.iconbl { .iconbl {
font-size: 18px; font-size: 18px;
margin: 0 3px; padding: 3px;
transition: background-color 0.2s;
cursor: pointer; cursor: pointer;
&:hover { &:hover {
color: var(--el-color-primary); @include themeBg(#efefef, #393939);
border-radius: 4px;
} }
} }
.bl-a-leftdirection-line { .bl-a-leftdirection-line {
font-size: 20px; margin-bottom: 1px;
margin: 0 1px;
} }
.bl-a-folderon-line { .bl-folderadd-line {
margin: 0 5px;
}
.bl-refresh-line {
font-size: 16px;
margin: 0 2px; margin: 0 2px;
&:active {
color: var(--el-color-primary-light-3);
} }
.bl-search-item {
margin: 0 2px;
}
.bl-collapse {
font-size: 16px;
} }
.doc-tree-search { .doc-tree-search {
@ -73,7 +73,7 @@
} }
.doc-trees-container { .doc-trees-container {
@include box(100%, calc(100% - 78px)); @include box(100%, calc(100% - 80px));
overflow-y: scroll; overflow-y: scroll;
overflow-x: hidden; overflow-x: hidden;

View File

@ -69,7 +69,7 @@ export const handleTreeDrop = (
}) })
} }
console.log(`same: ${isSame}, dropType: ${dropType}, drag: ${dragSourceSort}, enter: ${enterSourceSort}`) // console.log(`same: ${isSame}, dropType: ${dropType}, drag: ${dragSourceSort}, enter: ${enterSourceSort}`)
if (isSame) { if (isSame) {
// drag 在 enter 前 // drag 在 enter 前
if (dropType === 'before') { if (dropType === 'before') {
@ -221,8 +221,8 @@ export const handleTreeDrop = (
if (needUpd.length > 0) { if (needUpd.length > 0) {
updateFn(needUpd) updateFn(needUpd)
} }
console.log(needUpd) // console.log(needUpd)
console.log('==========================================') // console.log('==========================================')
} }
/** /**

View File

@ -8,10 +8,10 @@
<div class="iconbl bl-a-leftdirection-line" @click="handleShowSort"></div> <div class="iconbl bl-a-leftdirection-line" @click="handleShowSort"></div>
</el-tooltip> </el-tooltip>
<el-tooltip effect="light" popper-class="is-small" placement="top" :offset="4" :hide-after="0" content="根目录下新建图片文件夹"> <el-tooltip effect="light" popper-class="is-small" placement="top" :offset="4" :hide-after="0" content="根目录下新建图片文件夹">
<div class="iconbl bl-a-folderon-line" @click="addFolderToRoot()"></div> <div class="iconbl bl-folderadd-line" @click="addFolderToRoot()"></div>
</el-tooltip> </el-tooltip>
<el-tooltip effect="light" popper-class="is-small" placement="top" :offset="4" :hide-after="0" :show-after="1000" content="搜索"> <el-tooltip effect="light" popper-class="is-small" placement="top" :offset="4" :hide-after="0" :show-after="1000" content="搜索">
<div class="iconbl bl-search-line" @click="showTreeFilter()"></div> <div class="iconbl bl-search-item" @click="showTreeFilter()"></div>
</el-tooltip> </el-tooltip>
<el-tooltip effect="light" popper-class="is-small" placement="top" :offset="4" :hide-after="0" :show-after="1000" content="刷新"> <el-tooltip effect="light" popper-class="is-small" placement="top" :offset="4" :hide-after="0" :show-after="1000" content="刷新">
<div class="iconbl bl-refresh-line" @click="refreshDocTree()"></div> <div class="iconbl bl-refresh-line" @click="refreshDocTree()"></div>
@ -97,7 +97,7 @@
<span class="iconbl bl-a-fileedit-line"></span>编辑详情 <span class="iconbl bl-a-fileedit-line"></span>编辑详情
</div> </div>
<div :class="['menu-item', Number(curDoc.i) <= 0 ? 'disabled' : '']" @click="addFolderToDoc()"> <div :class="['menu-item', Number(curDoc.i) <= 0 ? 'disabled' : '']" @click="addFolderToDoc()">
<span class="iconbl bl-a-fileadd-line"></span>新增文件夹 <span class="iconbl bl-folderadd-line"></span>新增文件夹
</div> </div>
<div class="menu-item-divider"></div> <div class="menu-item-divider"></div>
<div :class="['menu-item', Number(curDoc.i) <= 0 ? 'disabled' : '']" @click="delDoc()"> <div :class="['menu-item', Number(curDoc.i) <= 0 ? 'disabled' : '']" @click="delDoc()">