Skip to content

代码块隐藏模块

代码块隐藏模块

笔记

一个代码块的代码太多,会占据大量的篇幅,如果能选择性隐藏,页面也许更加好看。

版权声明

警告

本着开源共享、共同学习的精神:

本文是在 博主《youngkbt》文章:《本站 - 代码块隐藏模块》https:publicstaticvoidmain(String[] args) {System.out.println("Hello,World");}}

PixPin_2024-12-26_16-03-01

看到代码块右边的箭头了吗,点击即可隐藏代码块,再次点击则会展开代码块。

本内容实现并不难,只需三步:

实现内容:

前提 1

本内容重新实现的一键复制功能是基于 vuepress-plugin-one-click-copy插件(箭头左边),该插件已经内置 vuepress-theme-vdoing主题,所以无需担心,如果你曾经卸载了该插件,则需要安装回来;如果已经安装,则无需看这一步:

sh
yarnaddvuepress-plugin-one-click-copy-D

当然,如果你懂得看下面的源码,则将适配 vuepress-plugin-one-click-copy插件的代码进行修改,只需要提供其他插件的 class 名进行判断(Vue 组件的 108 - 119 行代码),并自行在 F12 调试,移动到满意的位置。

如果不知道自己是否曾卸载或存在该插件,则前往根目录下的 package.json文件查看 devDependencies是否有 vuepress-plugin-one-click-copy插件。

前提 2

本功能需要代码块需要开启 行号功能,该功能已经内置 VuePress,所以只需要开启该配置即可。

docs/.vuepress/config.ts里开启行号:

ts
exportdefaultdefineConfig4CustomTheme({theme:"vdoing",markdown:{lineNumbers:true,extractHeaders:["h2","h3","h4"],},});

1、添加箭头图标

图标库来自阿里云:https:<script>exportdefault{mounted() {setTimeout(() =>{this.addExpand(40);},1000);},watch:{$route(to,from) {if(to.path !=from.path ||this.$route.hash =="") {setTimeout(() =>{this.addExpand(40);},1000);}},},methods:{addExpand(hiddenHeight=40) {letmodes =document.getElementsByClassName("line-numbers-mode");Array.from(modes).forEach((item) =>{letexpand =item.getElementsByClassName("expand")[0];if(!expand) {letmodeHeight =item.offsetHeight;if(modeHeight ==0&&item.parentNode.className !="cardImgListContainer") {modeHeight =this.getHiddenElementHight(item);}modeHeight -=12;item.style.height =modeHeight +"px";letpre =item.getElementsByTagName("pre")[0];letwrapper =item.getElementsByClassName("line-numbers-wrapper")[0];constdiv=document.createElement("div");div.className ="expand icon-xiangxiajiantou iconfont";div.onclick=() =>{if(parseInt(item.style.height) ==hiddenHeight) {div.className ="expand icon-xiangxiajiantou iconfont";item.style.height =modeHeight +"px";setTimeout(() =>{pre.style.display ="block";wrapper.style.display ="block";},80);} else{div.className ="expand icon-xiangxiajiantou iconfont closed";item.style.height =hiddenHeight +"px";setTimeout(() =>{pre.style.display ="none";wrapper.style.display ="none";},300);}};item.append(div);item.append(this.addCircle());}this.getLanguage(item);letflag =false;letinterval =setInterval(() =>{flag =this.moveCopyBlock(item);if(flag) {clearInterval(interval);}},1000);});},getHiddenElementHight(hiddenElement) {letmodeHeight;if(hiddenElement.parentNode.style.display =="none"||hiddenElement.parentNode.className !="theme-code-block theme-code-block__active") {hiddenElement.parentNode.style.display ="block";modeHeight =hiddenElement.offsetHeight;hiddenElement.parentNode.style.display ="none";if(hiddenElement.parentNode.className =="theme-code-block"||hiddenElement.parentNode.className =="cardListContainer") {hiddenElement.parentNode.style.display ="";}}returnmodeHeight;},addCircle() {letdiv =document.createElement("div");div.className ="circle";returndiv;},moveCopyBlock(element) {letcopyElement =element.getElementsByClassName("code-copy")[0];if(copyElement &&copyElement.parentNode !=element) {copyElement.parentNode.parentNode.insertBefore(copyElement,copyElement.parentNode);returntrue;} else{returnfalse;}},getLanguage(element) {letcontent =getComputedStyle(element,":before").getPropertyValue("content");if(content.length==2||content ==""||content =="none") {letlanguage =element.className.substring("language".length+1,element.className.indexOf(""));element.setAttribute("data-language",language);}},},};</script><style>.line-numbers-mode{overflow:hidden;transition:height 0.3s;margin-top:0.85rem;}.line-numbers-mode::before{content:attr(data-language);}.expand{width:16px;height:16px;cursor:pointer;position:absolute;z-index:3;top:0.8em;right:0.5em;color:rgba(238,255,255,0.8);font-weight:900;transition:transform 0.3s;}div[class*="language-"].line-numbers-modepre{margin:30px00.85rem0;}div[class*="language-"].line-numbers-mode.line-numbers-wrapper,.highlight-lines{margin-top:30px;}.closed{transform:rotate(90deg) translateY(-3px);transition:all0.3s;}li.closed{transform:rotate(90deg) translate(5px,-8px);}div[class*="language-"]::before{position:absolute;z-index:3;top:0.3em;left:4.7rem;font-size:1.15em;color:rgba(238,255,255,0.8);text-transform:uppercase;font-weight:bold;width:fit-content;}lidiv[class*="language-"]::before,li.expand{margin-top:-4px;}div[class*="language-"].line-numbers-mode::after{margin-top:35px;}.circle{position:absolute;top:0.8em;left:0.9rem;width:12px;height:12px;border-radius:50%;background:#fc625d;-webkit-box-shadow:20px0#fdbc40,40px0#35cd4b;box-shadow:20px0#fdbc40,40px0#35cd4b;}.code-copy{position:absolute;top:0.8rem;right:2rem;fill:rgba(238,255,255,0.8);opacity:1;}.code-copysvg{margin:0;}</style>

第 7 行和第 14 行的参数 40 是隐藏代码块后,保留的代码块高度,40 是默认值。

注意

  • 如果浅色模式的代码块背景色是浅灰色,则取消 226 - 234 的注释使代码生效(模板已经取消注释)
  • 如果是黑色,则注释 226 - 234 的代码(我自己的注释了,因为我的代码块是黑色背景)
  • 如果不喜欢代码块的语言变成大写,则注释 188 行的 text-transform:uppercase;

如果你想要你的代码块和我一样是 黑色,则打开 docs/.vuepress/styles/palette.styl文件,替换掉原来的浅色模式:

stylus
.theme-mode-light--bodyBg:#f4f4f4--mainBg:rgba(255,255,255,1)--sidebarBg:rgba(255,255,255,.8)--blurBg:rgba(255,255,255,.9)--customBlockBg:rgba(255,255,255,.9)--textColor:#00323c--textLightenColor:#0085AD--borderColor:rgba(0,0,0,.15)--codeBg:#282C34--codeColor:#D4D4D4codeThemeDark()div[class*="language-"].highlight-lines.highlightedbackground-colorrgba(0,0,0,.66)&.line-numbers-mode.highlight-lines.highlighted&:beforebackground-colorrgba(0,0,0,.66)div[class*="language-"].line-numbers-mode::afterborder-right1pxsolidrgba(0,0,0,0.66)

如果你喜欢加粗的 绿色、`` 包裹的 英文高亮 abcd包裹的 文字高亮、深色模式的颜色(点击右下角的衣服图标,切换深色模式)等等,那么可以参考我的自定义样式模块,左侧的关于本站目录下就能找到。


自己本次代码:(设置了黑色背景)

vue
<template></template><script>exportdefault{mounted() {setTimeout(() =>{this.addExpand(40);},1000);},watch:{$route(to,from) {if(to.path !=from.path ||this.$route.hash =="") {setTimeout(() =>{this.addExpand(40);},1000);}},},methods:{addExpand(hiddenHeight=40) {letmodes =document.getElementsByClassName("line-numbers-mode");Array.from(modes).forEach((item) =>{letexpand =item.getElementsByClassName("expand")[0];if(!expand) {letmodeHeight =item.offsetHeight;if(modeHeight ==0&&item.parentNode.className !="cardImgListContainer") {modeHeight =this.getHiddenElementHight(item);}modeHeight -=12;item.style.height =modeHeight +"px";letpre =item.getElementsByTagName("pre")[0];letwrapper =item.getElementsByClassName("line-numbers-wrapper")[0];constdiv=document.createElement("div");div.className ="expand icon-xiangxiajiantou iconfont";div.onclick=() =>{if(parseInt(item.style.height) ==hiddenHeight) {div.className ="expand icon-xiangxiajiantou iconfont";item.style.height =modeHeight +"px";setTimeout(() =>{pre.style.display ="block";wrapper.style.display ="block";},80);} else{div.className ="expand icon-xiangxiajiantou iconfont closed";item.style.height =hiddenHeight +"px";setTimeout(() =>{pre.style.display ="none";wrapper.style.display ="none";},300);}};item.append(div);item.append(this.addCircle());}this.getLanguage(item);letflag =false;letinterval =setInterval(() =>{flag =this.moveCopyBlock(item);if(flag) {clearInterval(interval);}},1000);});},getHiddenElementHight(hiddenElement) {letmodeHeight;if(hiddenElement.parentNode.style.display =="none"||hiddenElement.parentNode.className !="theme-code-block theme-code-block__active") {hiddenElement.parentNode.style.display ="block";modeHeight =hiddenElement.offsetHeight;hiddenElement.parentNode.style.display ="none";if(hiddenElement.parentNode.className =="theme-code-block"||hiddenElement.parentNode.className =="cardListContainer") {hiddenElement.parentNode.style.display ="";}}returnmodeHeight;},addCircle() {letdiv =document.createElement("div");div.className ="circle";returndiv;},moveCopyBlock(element) {letcopyElement =element.getElementsByClassName("code-copy")[0];if(copyElement &&copyElement.parentNode !=element) {copyElement.parentNode.parentNode.insertBefore(copyElement,copyElement.parentNode);returntrue;} else{returnfalse;}},getLanguage(element) {letcontent =getComputedStyle(element,":before").getPropertyValue("content");if(content.length==2||content ==""||content =="none") {letlanguage =element.className.substring("language".length+1,element.className.indexOf(""));element.setAttribute("data-language",language);}},},};</script><style>.line-numbers-mode{overflow:hidden;transition:height 0.3s;margin-top:0.85rem;}.line-numbers-mode::before{content:attr(data-language);}.expand{width:16px;height:16px;cursor:pointer;position:absolute;z-index:3;top:0.8em;right:0.5em;color:rgba(238,255,255,0.8);font-weight:900;transition:transform 0.3s;}div[class*="language-"].line-numbers-modepre{margin:30px00.85rem0;}div[class*="language-"].line-numbers-mode.line-numbers-wrapper,.highlight-lines{margin-top:30px;}.closed{transform:rotate(90deg) translateY(-3px);transition:all0.3s;}li.closed{transform:rotate(90deg) translate(5px,-8px);}div[class*="language-"]::before{position:absolute;z-index:3;top:0.3em;left:4.7rem;font-size:1.15em;color:rgba(238,255,255,0.8);text-transform:uppercase;font-weight:bold;width:fit-content;}lidiv[class*="language-"]::before,li.expand{margin-top:-4px;}div[class*="language-"].line-numbers-mode::after{margin-top:35px;}.circle{position:absolute;top:0.8em;left:0.9rem;width:12px;height:12px;border-radius:50%;background:#fc625d;-webkit-box-shadow:20px0#fdbc40,40px0#35cd4b;box-shadow:20px0#fdbc40,40px0#35cd4b;}.code-copy{position:absolute;top:0.8rem;right:2rem;fill:rgba(238,255,255,0.8);opacity:1;}.code-copysvg{margin:0;}.theme-mode-light.expand{color:#666;}.theme-mode-lightdiv[class*="language-"]::before{color:#666;}.theme-mode-light.code-copy{fill:#666;}</style>

3、注册Vue组件

在 docs/.vuepress/config.js(新版是 config.ts)的 plugins 中添加插件配置。

添加如下内容:

js

js
module.exports={plugins:[{name:'custom-plugins',globalUIComponents:["BlockToggle"] }],}

ts

bash
import{UserPlugins}from'vuepress/config'plugins:<UserPlugins>[[{name:'custom-plugins',globalUIComponents:["BlockToggle"] 
}]]

效果

ok 了,nice😜

image-20241226161845406

注意

  • vuepress-plugin-one-click-copy插件在移动端(手机端)失效,因为其自带的隐藏效果原因,这并不是本模块引起,而是本身插件的设计问题,所以如果觉得移动端也想要支持一键复制,请更换其他插件,并自行修改源码进行适配
  • 低分辨率的电脑,会导致代码的行数与代码不对应(代码行数溢出),这并非本模块原因,而是 VuePress 代码块本身的原因,可能新版本会修复

结束语

如果你正在热编译 markdown 的代码块,它不会立马生效,你只需要刷新下就能看到效果,而打包后,效果是会生效,无需担心。

如果你还有疑惑,可以去我的 GitHub 仓库或者 Gitee 仓库查看源码。

如果你有更好的方式,评论区留言告诉我,或者加入 Vdoing 主题的 QQ 群:694387113。谢谢!

最近更新