Jamey's Jamey's
首页
导航站
  • 学习专栏

    • 《HTML》笔记
    • 《CSS》笔记
    • 《JavaScript》笔记
    • 《Vue》笔记
    • 《Git》笔记
    • 《规范》笔记
    • 《软技能》笔记
    • 《面试》笔记
    • 《持续集成&交付&部署》笔记
  • 踩坑专栏

    • 《Element-UI 实践系列》笔记
    • 《移动端 实践系列》笔记
    • 《综合》笔记
  • 配置专栏

    • 《环境系列》笔记
  • 极空间

    • Docker
  • 影视

    • movie
  • 编辑器笔记

    • 开发编辑器
  • 浏览器笔记

    • Chrome
  • Mac笔记

    • Mac
  • 跨界学习

    • 运营
  • 破解合集

    • 破解
  • 本站

    • 分类
    • 标签
    • 归档
  • 我的

    • 收藏
    • 书单
    • 关于

Jamey

首页
导航站
  • 学习专栏

    • 《HTML》笔记
    • 《CSS》笔记
    • 《JavaScript》笔记
    • 《Vue》笔记
    • 《Git》笔记
    • 《规范》笔记
    • 《软技能》笔记
    • 《面试》笔记
    • 《持续集成&交付&部署》笔记
  • 踩坑专栏

    • 《Element-UI 实践系列》笔记
    • 《移动端 实践系列》笔记
    • 《综合》笔记
  • 配置专栏

    • 《环境系列》笔记
  • 极空间

    • Docker
  • 影视

    • movie
  • 编辑器笔记

    • 开发编辑器
  • 浏览器笔记

    • Chrome
  • Mac笔记

    • Mac
  • 跨界学习

    • 运营
  • 破解合集

    • 破解
  • 本站

    • 分类
    • 标签
    • 归档
  • 我的

    • 收藏
    • 书单
    • 关于
  • 关于 - 自我

  • 关于 - 本站

    • 本站 - 介绍
    • 本站 - 导航站模块
    • 本站 - 代码块隐藏模块
      • 一. 前言
      • 二. 前提
      • 三. 添加箭头图标
      • 四. 添加Vue组件
      • 五. 注意
      • 六. 注册Vue组件
  • 关于 - 技巧

  • 关于
  • 关于 - 本站
Jamey
2022-03-12
目录

本站 - 代码块隐藏模块

# 本站 - 代码块隐藏模块

笔记

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

2022-03-12 @Jamey

# 一. 前言

目前适用版本是 Vdoing v1.x。

代码块可以隐藏,也可以展开,这和 ::: details 类似,下面是简单的代码块 Demo:

public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello,World");
    }
}
1
2
3
4
5

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

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

  • 添加箭头图标
  • 编写代码块模块的 Vue 组件
  • 全局注册 Vue 组件

实现内容:

  • 代码块的隐藏和显示

  • 美化代码块的 UI,趋向于 Mac

  • 优化代码块语言的显示,因为默认主题的一些语言如 stylus 是不会显示出来。本内容的优化无论代码块语言是什么(如 abc),都会显示出来,如图

    我的语言不是 Java、PHP、JS、SH,而是 abdedfg
    
    1

# 二. 前提

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

    npm add vuepress-plugin-one-click-copy -D
    
    1
    yarn add vuepress-plugin-one-click-copy -D
    
    1
    // Make sure to add code blocks to your code group

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

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

    # 三. 添加箭头图标

    图标库来自阿里云:https://www.iconfont.cn/ (opens new window)。

    如果你没有账号,或者觉得添加比较麻烦,就使用我的图标库地址,当你发现图标失效了,就请来这里获取新的地址,如果还没有更新,请在评论区留言。

    当然,建议你使用自己的图标库,比较稳定。就像注册一个购物账户,然后添加到购物车即可。

    在 docs/.vuepress/config.js 的 head 模块里添加如下内容:

    ['link', { rel: 'stylesheet', href: '//at.alicdn.com/t/font_3114978_qe0b39no76.css' }],['link', { rel: 'stylesheet', href: '//at.alicdn.com/t/font_3114978_qe0b39no76.css' }],
    
    1

    # 四. 添加Vue组件

    在 docs/.vuepress/components 目录下创建 Vue 组件:BlockToggle.vue。如果不存在 components 目录,则请创建。

    添加如下内容:

    <template></template>
    
    <script>
    export default {
      mounted() {
        setTimeout(() => {
          this.addExpand(40);
        }, 1000);
      },
      watch: {
        $route(to, from) {
          console.log("11");
          setTimeout(() => {
            this.addExpand(40);
          }, 1000);
        },
      },
      methods: {
        // 隐藏代码块后,保留 40 的代码块高度
        addExpand(hiddenHeight = 40) {
          let modes = document.getElementsByClassName("line-numbers-mode");
          // 遍历出每一个代码块
          Array.from(modes).forEach((item) => {
            // 首先获取 expand 元素
            let expand = item.getElementsByClassName("expand")[0];
            // expand 元素不存在,则进入 if 创建
            if (!expand) {
              // 获取代码块原来的高度,进行备份
              let modeHeight = item.offsetHeight;
              // display:none 的代码块需要额外处理
              if (modeHeight == 0) {
                modeHeight = this.getHiddenElementHight(item);
              }
              // modeHeight 比主题多 12,所以减掉,并显示赋值,触发动画过渡效果
              modeHeight -= 12;
              item.style.height = modeHeight + "px";
              // 获取代码块的各个元素
              let pre = item.getElementsByTagName("pre")[0];
              let wrapper = item.getElementsByClassName("line-numbers-wrapper")[0];
              // 创建箭头元素
              const div = document.createElement("div");
              div.className = "expand icon-xiangxiajiantou iconfont";
              // 箭头点击事件
              div.onclick = () => {
                // 代码块已经被隐藏,则进入 if 循环,如果没有被隐藏,则进入 else 循环
                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);
            // 移动一键复制图标到正确的位置
            let flag = false;
            let interval = setInterval(() => {
              flag = this.moveCopyBlock(item);
              if (flag) {
                clearInterval(interval);
              }
            }, 1000);
          });
        },
        getHiddenElementHight(hiddenElement) {
          let modeHeight;
          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";
            // 清除 vuepress 自带的 deetails 多选代码块
            if (
              hiddenElement.parentNode.className == "theme-code-block" ||
              hiddenElement.parentNode.className == "cardListContainer"
            ) {
              hiddenElement.parentNode.style.display = "";
            }
          }
          return modeHeight;
        },
        // 添加三个圆圈
        addCircle() {
          let div = document.createElement("div");
          div.className = "circle";
          return div;
        },
        // 移动一键复制图标
        moveCopyBlock(element) {
          let copyElement = element.getElementsByClassName("code-copy")[0];
          if (copyElement && copyElement.parentNode != element) {
            copyElement.parentNode.parentNode.insertBefore(
              copyElement,
              copyElement.parentNode
            );
            return true;
          } else {
            return false;
          }
        },
        // 解决某些代码块的语言不显示在页面上
        getLanguage(element) {
          // 动态获取 before 的 content 属性
          let content = getComputedStyle(element, ":before").getPropertyValue(
            "content"
          );
          // "" 的长度是 2,不是 0,"x" 的长度是 3
          if (content.length == 2 || content == "" || content == "none") {
            let language = 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-mode pre {
      margin: 30px 0 0.85rem 0;
    }
    /* 代码块的行数 */
    div[class*="language-"].line-numbers-mode .line-numbers-wrapper {
      margin-top: 30px;
    }
    /* 箭头关闭后旋转 -90 度 */
    .closed {
      transform: rotate(90deg) translateY(-3px);
      transition: all 0.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;
    }
    /* li 下的代码块的语言和 li 下的箭头 */
    li div[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: 20px 0 #fdbc40, 40px 0 #35cd4b;
      box-shadow: 20px 0 #fdbc40, 40px 0 #35cd4b;
    }
    /* 代码块一键复制图标 */
    .code-copy {
      position: absolute;
      top: 0.8rem;
      right: 2rem;
      fill: rgba(238, 255, 255, 0.8);
      opacity: 1;
    }
    .code-copy svg {
      margin: 0;
    }
    
    /* 如果你浅色模式的代码块背景色是浅灰色,则取消下面的注释使代码生效,如果是黑色,则注释下面的三段代码(我注释了,因为是黑色背景) */
    .theme-mode-light .expand {
      color: #666;
    }
    .theme-mode-light div[class*="language-"]::before {
      color: #666;
    }
    .theme-mode-light .code-copy {
      fill: #666;
    }
    </style>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230

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

    注意

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

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

    .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: #f6f8fa
      //--codeColor: #24292e
      //codeThemeLight()
      // 行高亮颜色,和代码块浅色主题一起使用,一起注释
      //div[class*="language-"]
      //  .highlight-lines
      //    .highlighted
      //      background-color rgba(200,200,200,.4)
      //  &.line-numbers-mode
      //    .highlight-lines .highlighted
      //      &:before
      //        background-color rgba(200,200,200,.4)
      // 代码块深色主题
      --codeBg: #282C34
      --codeColor: #D4D4D4
      codeThemeDark()
      // 行高亮颜色,和代码块深色主题一起使用,一起注释
      div[class*="language-"]
        .highlight-lines
          .highlighted
            background-color rgba(0,0,0,.66)
        &.line-numbers-mode
          .highlight-lines .highlighted
            &:before
              background-color rgba(0,0,0,.66)
      div[class*="language-"].line-numbers-mode::after  // 代码块的行数和内容分割线颜色
        border-right 1px solid rgba(0, 0, 0, 0.66)
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37

    # 五. 注意

    vuepress-plugin-one-click-copy 插件在移动端(手机端)失效,因为其自带的隐藏效果原因,这并不是本模块引起,而是本身插件的设计问题。

    所以如果觉得移动端也想要支持一键复制,请更换其他插件,并自行修改源码进行适配。

    # 六. 注册Vue组件

    在 docs/.vuepress/config.js的 plugins 中添加插件配置。

    添加如下内容:

      module.exports = {
        plugins: [
          {
            name: 'custom-plugins',
            globalUIComponents: ["BlockToggle"] // 2.x 版本 globalUIComponents 改名为 clientAppRootComponentFiles
          }
        ],
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      import { UserPlugins } from 'vuepress/config'
      plugins: <UserPlugins>[
        [
          {
            name: 'custom-plugins',
            globalUIComponents: ["BlockToggle"] // 2.x 版本 globalUIComponents 改名为 clientAppRootComponentFiles
          }
        ]
      ]
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      上次更新: 2022/04/23, 03:06:55
      本站 - 导航站模块
      技巧 - 笔记

      ← 本站 - 导航站模块 技巧 - 笔记→

      Theme by Vdoing | Copyright © 2017-2023 Jamey | blog 闽ICP备19022664号
      • 跟随系统
      • 浅色模式
      • 深色模式
      • 阅读模式