官网装修 - 文档页

[toc]


创建更多路由

分别创建介绍、安装和开始使用导航对应的组件 router.ts

  • 路由路径一般小写,横杠链接
  • 组件一般大写
 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
import ButtonDemo from '@/components/ButtonDemo.vue';
import DialogDemo from '@/components/DialogDemo.vue';
import DocsDemo from '@/components/DocsDemo.vue';
import SwitchDemo from '@/components/SwitchDemo.vue';
import TabsDemo from '@/components/TabsDemo.vue';
import Docs from '@/views/Docs.vue';
import GetStarted from '@/views/GetStarted.vue';
import Home from '@/views/Home.vue';
import Install from '@/views/Install.vue';
import Intro from '@/views/Intro.vue';
import {createRouter, createWebHashHistory} from 'vue-router';

const history = createWebHashHistory();
export const router = createRouter({
  history,
  routes: [
    {path: '/', component: Home},
    {
      path: '/docs', component: Docs,
      children: [
        {path: '', component: DocsDemo},
        {path: 'intro', component: Intro},
        {path: 'get-started', component: GetStarted},
        {path: 'install', component: Install},
        {path: 'switch', component: SwitchDemo},
        {path: 'button', component: ButtonDemo},
        {path: 'dialog', component: DialogDemo},
        {path: 'tabs', component: TabsDemo},
      ]
    },
  ]
});

高亮当前路由 router active class

  • 高亮当前路由(模糊匹配)
  • 使用vue-router 选中任意路由时自动添加的router-link-active类可以精确匹配
    • router-link-active标记当前选中的类
    • router-link-exact-active链接精准激活时,匹配选中项的类
  • 选择给router-link-exact-active类添加样式
  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
<template>
  <div class="layout">
    <top-nav class="nav" menuBtnVisible></top-nav>
    <div class="content">
      <transition name="aside">
        <aside v-if="asideVisible">
          <header>
            <h2>
              <router-link class="alink" to="/docs">文档</router-link>
            </h2>
          </header>
          <ol>
            <li>
              <h3>
                <router-link class="router-link" to="/docs/intro">介绍</router-link>
              </h3>
            </li>
            <li>
              <h3>
                <router-link class="router-link" to="/docs/install">安装</router-link>
              </h3>
            </li>
            <li>
              <h3>
                <router-link class="router-link" to="/docs/get-started">开始使用</router-link>
              </h3>
            </li>
          </ol>
          <header>
            <h2>
              组件列表
            </h2>
          </header>
          <ol>
            <li>
              <h3>
                <router-link to="/docs/switch"
                             class="router-link">
                  Switch 组件
                </router-link>
              </h3>
            </li>
            <li>
              <h3>
                <router-link to="/docs/button"
                             class="router-link">
                  Button 组件
                </router-link>
              </h3>
            </li>
            <li>
              <h3>
                <router-link to="/docs/dialog"
                             class="router-link">
                  Dialog 组件
                </router-link>
              </h3>
            </li>
            <li>
              <h3>
                <router-link to="/docs/tabs"
                             class="router-link">
                  Tabs 组件
                </router-link>
              </h3>
            </li>
          </ol>
        </aside>
      </transition>
      <main>
        <router-view></router-view>
      </main>
    </div>
  </div>
</template>

<script setup lang="ts">
import {inject, Ref} from 'vue';

let asideVisible = inject<Ref<boolean>>('asideVisible');
</script>

<script lang="ts">
import TopNav from '@/components/TopNav.vue';

export default {
  name: 'Docs',
  components: {TopNav}
};
</script>

<style lang="scss" scoped>
.layout {
  display: flex;
  flex-direction: column;
  height: 100vh;

  > .nav {
    flex-shrink: 0;
    height: 5vh;
  }

  > .content {
    height: 95vh;
    display: flex;
    flex-grow: 1;
    padding-top: 60px;
    padding-left: 156px;
    @media screen and(max-width: 768px) {
      padding-left: 0;
    }

    > aside {
      flex-shrink: 0;
      position: fixed;
      top: 0;
      left: 0;
      background: linear-gradient(
          145deg,
          rgba(183, 233, 230, 50) 100%,
          rgba(227, 255, 253, 1) 0%);
      width: 150px;
      padding: 60px 0 16px;
      height: 100vh;
      color: black;
      z-index: 1;

      > header {
        > h2 {
          margin-bottom: 4px;
          line-height: 50px;
          padding: 0 16px;
          user-select: none;
        }
      }

      > ol {
        display: flex;
        flex-direction: column;

        > li {
          > h3 {
            display: block;
            line-height: 25px;
            transition: .25s;
            padding-left: -16px;

            &:hover {
              transform: translate3D(4px, 0, 0);
            }

            .router-link {
              display: block;
              height: 100%;
              width: 100%;
              padding: 4px 16px;
            }

            .router-link-active {
              background-color: white;
              padding-left: -4px;
            }


          }

        }
      }

    }

    > main {
      flex-grow: 1;
      padding: 16px;
      background: white;
      overflow: auto;
    }

    .aside-enter-active,
    .aside-leave-active {
      transition: all 0.25s ease;
    }

    .aside-enter-from,
    .aside-leave-to {
      opacity: 0;
      transform: translate3D(-100%, 0, 0);
    }
  }

}

</style>

引入 Github 的 Markdown 样式

填充文档内容

Intro.vue

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<template>
  <article class="markdown-body">
    <h1>介绍</h1>
    <p>King UI 是一款基于 Vue 3 和 TypeScript 的 UI 组件库。</p>
    <p>这款组件库其实是我为了总结自己这几年的技术经验而写的,全程亲手编写,尽量不采用第三方库,包括你现在看到的这个官网也几乎都是我自己写的。</p>
    <p>所以如果强烈不建议你将此 UI 库用于生产环境。但如果你是抱着看源代码的目的来的,那么这个库还是值得一看的。源代码放在了
      github.com/frankfang/xxxxxxx,历史提交信息非常规范,你可以按提交的顺序逐个查看;你也可以直接查看每个组件的源代码和示例,运行方法见 README.md。</p>
    下一节:<a href="#/doc/install">安装</a>
  </article>
</template>

Install.vue

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<template class="markdown-body">
  <article>
    <h1>安装</h1>
    <p>打开终端运行下列命令:</p>
    <pre><code>npm install king-ui</code></pre>
    <p></p>
    <pre><code>yarn add king-ui</code></pre>

    <p>
      下一节:<a href="#/doc/get-started">开始使用</a>
    </p>
  </article>
</template>

GetStarted.vue

 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
<template>
  <article class="markdown-body">
    <h1>
      开始使用
    </h1>

    <p>请先<a href="#/doc/install">安装</a>本组件库。</p>
    <p>然后在你的代码中写入下面的代码</p>
    <pre><code>import {Button, Tabs, Switch, Dialog} from "king-ui"</code></pre>
    就可以使用我提供的组件了。

    <h2>Vue 单文件组件</h2>
    <p>代码示例:</p>
    <pre>
      <code>
        &lt;template&gt;
        &nbsp;&nbsp;&lt;div&gt;&lt;Button&gt;按钮&lt;/Button&gt;&lt;/div&gt;
        &lt;/template&gt;
        &lt;script&gt;
        &nbsp;&nbsp;import {Button, Tabs, Switch, Dialog} from "king-ui"
        &nbsp;&nbsp;export default {
        &nbsp;&nbsp;&nbsp;components: {Button}
        &nbsp;&nbsp;}
        &lt;/script&gt;
      </code>
    </pre>

  </article>
</template>

使用github-markdown-css为代码添加样式

  • 安装yarn add github-markdown-css
  • main.ts中引入import 'github-markdown-css';
    • 黑暗模式github-markdown-css/github-markdown-dark.css
    • 明亮模式github-markdown-css/github-markdown-light.css
  • 在容器的标签上添加类class="markdown-body"

这样写比较麻烦,考虑直接使用*.md文件,转化为HTML标签,插入js文件中


添加支持 import markdown 文件

直接引入 Markdown 文件需要 ** Vite 插件 **

自制Vite 插件

  • Vite在开发项目时没有使用任何打包工具,使用浏览器自带的能力
  • 浏览器不支持引入*.md文件,但支持引入*.js文件
  • *.md文件转译为*.js文件,然后引入浏览器

新建目录与文件plugins/md.ts

 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
// @ts-nocheck
import path from 'path';
import fs from 'fs';
import marked from 'marked';

const mdToJs = str => {
  const content = JSON.stringify(marked(str));
  return `export default ${content}`;
};

export function md() {
  return {
    configureServer: [ // 用于开发 KOA
      async ({app}) => {
        app.use(async (ctx, next) => { // koa
        // 处理 以*.md结尾的文件,使用mdToJs方法编译为js文件
          if (ctx.path.endsWith('.md')) {
            ctx.type = 'js';
            const filePath = path.join(process.cwd(), ctx.path);
            ctx.body = mdToJs(fs.readFileSync(filePath).toString());
          } else {
            await next();
          }
        });
      },
    ],
    transforms: [{  // 用于 rollup // 插件
      test: context => context.path.endsWith('.md'),
      transform: ({code}) => mdToJs(code)
    }]
  };
}

  • 由于md.ts引用了marked,需要安装yarn add --dev marked

vite.config.ts中调用md.ts

1
2
3
4
5
6
// @ts-nocheck
import { md } from "./plugins/md";

export default {
  plugins: [md()]
};

正式版vite已经不支持此种写法了,所以可以使用官方推荐的插件vite-plugin-md

使用vite-plugin-md

解释一下 md.ts

  • 用于开发 KOA
    • 添加加载*.md文件为*.js文件的功能
    • 导出一个字符串export default "<h1>..."
  • 用于 rollup 插件
    • 对 .md文件进行编译
    • 使用mdToJs()方法将*.md 转译为js代码

事不过三,消除重复

Don’t Repeat Yourself

 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
// Install.vue
<script lang="ts" setup>
import InstallMD from '@/markdown/install.md';
</script>

<template>
  <InstallMD class="markdown-body"></InstallMD>
</template>

<script lang="ts">
export default {
  name: 'Install'
};
</script>


// GetStarted.vue
<script lang="ts" setup>
import GetStartedMD from '@/markdown/getStarted.md';
</script>

<template>
  <GetStartedMD class="markdown-body"></GetStartedMD>
</template>

<script lang="ts">
export default {
  name: 'GetStarted'
};
</script>

// Intro.vue
<script setup lang="ts">
import IntroMD from '@/markdown/intro.md';
</script>

<template>
  <IntroMD class="markdown-body"></IntroMD>
</template>

<script lang="ts">
export default {
  name: 'Intro',
};
</script>

三个组件的结构一致,可以用一个组件来代替

  • 新建组件src/view/Markdown.vue
  • 将导入语句的路径作为参数,参数数据由外界传入
    • props: {path: {type: String, required: true}}
  • setup() {}中动态异步地引入import(props.path),异步请求文件
    • 使用 顶层 await
    • await 的表达式会自动编译成在 await 之后保留当前组件实例上下文的格式。

``


你的代码有什么缺点

  • 不支持SSR

展示源代码

优化demo展示

SwitchDemo.vue

 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
<template>
  <div>
    <h1>Switch 组件示例 </h1>
    <div class="demo">
      <h2>常规用法</h2>
      <div class="demo-component">
        <VueSwitch v-model:toggleValue="bool1"/>
      </div>
      <div class="demo-actions">
        <VueButton>查看代码</VueButton>
      </div>
      <div class="demo-code">
        <pre>&lt;Switch v-model:value="bool" /&gt;</pre>
      </div>
    </div>
    <div class="demo">
      <h2>支持 disabled </h2>
      <div class="demo-component">
        <VueSwitch v-model:toggleValue="bool2" disabled/>
      </div>
      <div class="demo-actions">
        <VueButton>查看代码</VueButton>
      </div>
      <div class="demo-code">
        <pre>&lt;Switch v-model:value="bool" disabled /&gt;</pre>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import VueSwitch from '@/lib/Switch.vue';
import VueButton from '@/lib/Button.vue';
import {ref} from 'vue';

const bool1 = ref(false);
const bool2 = ref(false);
const bool3 = ref(false);
</script>

<script lang="ts">
export default {
  name: 'SwitchDemo'
};
</script>

<style lang="scss" scoped>
$border-color: #d9d9d9;
.demo {
  border: 1px solid $border-color;
  margin: 16px 0 32px;

  > h2 {
    font-size: 20px;
    padding: 8px 16px;
    border-bottom: 1px solid $border-color;
  }

  &-component {
    padding: 16px;
  }

  &-actions {
    padding: 8px 16px;
    border-top: 1px dashed $border-color;
  }

  &-code {
    padding: 8px 16px;
    border-top: 1px dashed $border-color;

    > pre {
      line-height: 1.1;
      font-family: Consolas, 'Courier New', Courier, monospace;
      margin: 0;
    }
  }
}
</style>

  • demo分为四个部分
    • 标题 h2
    • 展示的组件 <VueSwitch />
    • 切换按钮 <VueButton />
    • 组件的源码 <div class="demo-code"><pre>...

展示抽离的源代码,方便拷贝

 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
<template>
  <div>
    <h1>Switch 组件示例 </h1>
    <div class="demo">
      <h2>常规用法</h2>
      <div class="demo-component">
        <Switch1demo/>
      </div>
      <div class="demo-actions">
        <VueButton>查看代码</VueButton>
      </div>
      <div class="demo-code">
        <pre>&lt;Switch v-model:value="bool" /&gt;</pre>
      </div>
    </div>
    <div class="demo">
      <h2>支持 disabled </h2>
      <div class="demo-component">
        <Switch2demo/>
      </div>
      <div class="demo-actions">
        <VueButton>查看代码</VueButton>
      </div>
      <div class="demo-code">
        <pre>&lt;Switch v-model:value="bool" disabled /&gt;</pre>
      </div>
    </div>
    <div class="demo">
      <h2>支持 文字 </h2>
      <div class="demo-component">
        <Switch3demo/>
      </div>
      <div class="demo-actions">
        <VueButton>查看代码</VueButton>
      </div>
      <div class="demo-code">
        <pre>&lt;Switch v-model:value="bool" disabled /&gt;</pre>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import Switch1demo from '@/components/switch/switch1demo.vue';
import Switch2demo from '@/components/switch/switch2demo.vue';
import Switch3demo from '@/components/switch/switch3demo.vue';
import VueButton from '@/lib/Button.vue';

</script>
...

使用vue-loaderCustom Blocks功能处理自定义标签

switch1demo.vue为例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<demo>常规用法</demo>
<script setup lang="ts">
import VueSwitch from '@/lib/Switch.vue';
import {ref} from 'vue';

const bool = ref(false);
</script>

<template>
  <VueSwitch v-model:toggleValue="bool"/>
</template>

写一个vite2.0插件 vueCompAddSourceCodeTitleFromCustomBlock.ts

  • 处理自定义标签<demo></demo>
  • vite 1.x 迁移 自定义块转换
  • transform(code, id)中的id其实所解析到的文件的 url
  • 使用正则匹配/vue&type=demo/.test(id)
  • 去除多余的查询参数得到该文件路径
    • const path = id.replace(`?vue&type=demo&index=0&lang.demo`,'');
  • 按路径读取文件内容const fileString = fs.readFileSync(path).toString();
  • 找出<demo></demo>标签节点,并且得到文本
    • const parsed = baseParse(fileString).children.find(n => n.tag === 'demo');
    • const title = parsed.children[0].content;
  • 得到代码主体const main = fileString.split(parsed.loc.source).join('').trim();
  • 给组件附加属性
    • Component.__sourceCode = ${JSON.stringify(main)}
    • Component.__sourceCodeTitle = ${JSON.stringify(title)}
  • 在模板字符串中返回 方法
    • return `export default function (Component) { Component.__sourceCode = ${JSON.stringify(main)} Component.__sourceCodeTitle = ${JSON.stringify(title)} }`.trim();
 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
import {baseParse} from '@vue/compiler-core';
import fs from 'fs';

// 自定义块转换
// 可以告诉 vite 在遇到 vue 文件的时候如何处理自定义块 <example>
// 获取组件源码 Component.__sourceCode
// 获取组件标题 Component.__sourceCodeTitle
export function vueCompAddSourceCodeTitleFromCustomBlock(customBlockName: string) {
  const regexp = new RegExp(`vue&type=${customBlockName}`);
  return {
    name: 'vueCustomBlockTransforms',
    transform: (code: string, id: string) => {
      if (!regexp.test(id)) {
        return;
      }
      const path = id
        .replace(`?vue&type=${customBlockName}&index=0&lang.${customBlockName}`,
          '');
      const fileString = fs.readFileSync(path).toString();
      // @ts-ignore
      const parsed = baseParse(fileString).children.find(n => n.tag === 'demo');
      // demo 标题
      // @ts-ignore
      const title = parsed.children[0].content;
      // 代码主体
      // @ts-ignore
      const main = fileString.split(parsed.loc.source).join('').trim();

      return `export default function (Component) {
        Component.__sourceCode = ${JSON.stringify(main)}
        Component.__sourceCodeTitle = ${JSON.stringify(title)}
      }`.trim();
    },
  };
}

配置vite.config.ts

 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
import vue from '@vitejs/plugin-vue';
import {defineConfig/*, PluginOption, UserConfig*/} from 'vite';
import Markdown from 'vite-plugin-md';
import ViteComponents/*, {Options}*/ from 'vite-plugin-components';
// const path = require('path'); path.resolve(...)
// https://vitejs.dev/config/
const {resolve} = require('path');
// vueCustomBlockTransforms
import {vueCompAddSourceCodeTitleFromCustomBlock} from './plugins/vueCompAddSourceCodeTitleFromCustomBlock';

export default defineConfig({
  plugins: [
    vue({
      include: [/\.vue$/, /\.md$/],
    }),
    Markdown(),
    ViteComponents({
      dirs: ['src/markdown'],
      // allow auto load markdown components under `./src/components/`
      extensions: ['vue', 'md'],

      // allow auto import and register components used in markdown
      customLoaderMatcher: (path: string) => path.endsWith('.md'),
    }),
    vueCompAddSourceCodeTitleFromCustomBlock('demo')
  ],
  resolve: {
    alias: [
      {
        find: '@',
        replacement: resolve('./src')
      },
      {find: /^~@/, replacement: resolve(__dirname, 'src')}
    ]
  }

});

参考


小优化:使用 <component :is=""/>

五彩斑斓的源代码

使用pismjs为显示的源代码加样式

  • 安装yarn add pismjs
  • 安装yarn add @types/prismjs -D
  • 在需要显示源代码的组件中引入
    • import * as Prism from 'prismjs';,使用全局下的window.Prism
      • 不能使用import 'pismjs'
      • 不能使用import default from 'pismjs'
    • 样式import 'prismjs/themes/prism-okaidia.css';
  • env.d.ts中声明模块类型declare module 'prismjs';
  • pismjs将每行代码字符串外都包裹一层span,加上相应的样式
  • 加背景色<pre class="language-html" v-html="Prism.highlight(Switch1demo.__sourceCode, Prism.languages.html, 'html')"></pre>

神奇的封装:Demo 组件

事不过三 封装<Demo component="x"/>组件 简化代码

 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
<script setup lang="ts">
import Prism from 'prismjs';
import 'prismjs/themes/prism-okaidia.css';
import 'prismjs/plugins/line-numbers/prism-line-numbers.css';
import 'prismjs/plugins/line-numbers/prism-line-numbers.min.js';
import VueButton from '@/lib/button.vue';
import {computed, ref} from 'vue';

const codeVisible = ref(false);
const props = defineProps({
  component: Object
});
const toggle = () => {
  codeVisible.value = !codeVisible.value;
};
const html = computed(() => {
  return Prism.highlight(props.component?.__sourceCode, Prism.languages.html, 'html');
});

</script>

<template>
  <div class="vue-demo">
    <h2>{{ component.__sourceCodeTitle }}</h2>
    <div class="vue-demo-component">
      <keep-alive>
        <component :is="component"></component>
      </keep-alive>
    </div>
    <div class="vue-demo-actions">
      <VueButton @click="toggle">查看代码</VueButton>
    </div>
    <div class="vue-demo-code" v-show="codeVisible">
      <pre class="language-html">
        <code class="language-html" v-html="html"></code>
      </pre>
    </div>
  </div>
</template>

<script lang="ts">
export default {
  name: 'Demo'
};
</script>

<style lang="scss">
@import 'prismjs/plugins/line-numbers/prism-line-numbers.css';
</style>

<style lang="scss" scoped>
$border-color: #d9d9d9;

.vue-demo {
  border: 1px solid $border-color;
  margin: 16px 0 32px;

  > h2 {
    font-size: 20px;
    padding: 8px 16px;
    border-bottom: 1px solid $border-color;
  }

  &-component {
    padding: 16px;
  }

  &-actions {
    padding: 8px 16px;
    border-top: 1px dashed $border-color;
  }

  &-code {
    padding: 8px 16px;
    border-top: 1px dashed $border-color;

    > pre {
      line-height: 1.1;
      font-family: Consolas, 'Courier New', Courier, monospace;
      margin: 0;
      padding-left: 70px;

      @media(max-width: 500px) {
        padding-left: 5px;
      }

      > code {
        &:first-child {
          margin-left: -70px;
        }
      }
    }
  }
}
</style>


使用mitt

main.ts

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import App from '@/App.vue';
import '@/assets/icon/svg.js';
import '@/lib/var.scss';
import {router} from '@/router';
import '@/styles/index.scss';
import 'github-markdown-css/github-markdown-light.css';
import {createApp} from 'vue';
import mitt from 'mitt';

const app = createApp(App);
app.use(router);
app.config.globalProperties.$evbus = mitt;

app.mount('#app');

App.vue

 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
<script setup lang="ts">
import mitt from 'mitt';
import {provide, reactive, ref} from 'vue';
import {router} from '@/router';

const width = document.documentElement.clientWidth;
const asideVisible = ref(width > 500);
provide('asideVisible', asideVisible);
const emmiter = reactive(mitt());
provide('evBus', emmiter);

router.afterEach(() => {
  // 判断屏幕尺寸是否为移动端,决定侧边栏是否可见
  if (width <= 768) {
    emmiter.emit('evBus');
    asideVisible.value = false;
  } else {
    // 屏幕宽度大于500px 显示代码行数 prismjs line-numbers
    document.querySelector('body')?.classList.add('line-numbers');
  }

});

</script>

<script lang="ts">
export default {
  name: 'App'
};
</script>

<template>
  <router-view></router-view>
</template>