Vue3 造轮子: 官网装修文档页

166 阅读4分钟

创建更多路由

在views里面创建Intro(介绍),GetStarted(开始使用),Install(安装)组件

在router.ts里面创建路径,引入上面的组件

在Doc.vue里面添加路由链接<router-link to="。。。"><router-link>

image.png

image.png

高亮当前路由

设置选中路由的

在CSS中添加下面的代码

.router-link-active {
  text-decoration: underline;  //选中的路由下方有下划线 
}

image.png

如果想要选中的整个区域变化,那router-link-active就没办法实现,会出现下图的效果

image.png

为什么会这样?因为这里是a标签,我们实际选中的区域是<li>,代码结构实际上是<li>

image.png

image.png

做法:不可能通过a标签控制<li>的样式,那么就让a标签充满<li>

> ol {
    > li {
      > a {
        display: block;
        padding: 4px 16px;
        text-decoration: none;
      }
      .router-link-active {
        background: white;
      }
    }
  }

image.png

引入GitHub的Markdown样式

github-markdown-css

将文档的内容写好

运行yarn add github-markdown-css

这时,会出现报错,但是加上对应的版本号就可以了

yarn add github-markdown-css@4.0.0

运行成功。在每个<article>标签内加上markdown-body,即

<article class="markdown-body">
。。。
</article>

支持 import markdown 文件

自制vite插件

搜索 Vue3 vite plugin

创建一个plugin/md.ts的插件

md.ts

// @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: [
      // 用于开发
      async ({ app }) => {
        app.use(async (ctx, next) => {
          // koa 是个web框架
          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,所以要安装marked

命令如下:

yarn add --dev marked

或者

npm i -D marked

再创建vite.config.ts文件

vite.config.ts

// @ts-nocheck

import { md } from "./plugins/md";

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

然后就可以创建markdown/intro.mdmarkdown/get-started.mdmarkdown/install.md,将内容转到.md文件内,即可用marked的语法

vite在开发的时候用的是浏览器的原生能力,部署的时候用的是rollup,md.ts是否支持rollup?(答案是支持的)

运行yarn build,得到三个文件(js文件,css文件,html文件)

再运行yarn global add http-server

安装后使用http-server dist/ -c-1

消灭重复

将重复的代码消灭,创建Markdown.vue组件,将重复的代码给提取到Markdown.vue

接受一个参数,props在初始化的时候执行,import ... from ......是在引入的时候执行

import md from props.path只能写在文件外面,不能写在setup里面,如果写在文件里面是会自动的移到文件外面去,可以用动态import(props.path)

动态import

import(props.path)

动态import 同之前的 import ... from .... 的区别是:动态import 是异步去加载

在开发者工具里面,可以看到Markdown.vue有去请求Intro.vue里面的文件

image.png

然后不写动态import的话,就不会有该请求

那我们知道了动态import是异步的请求,异步返回内容(可以用await,但是会出现bug,因为setup是不支持async的,如果外面没有写async,里面是不能用await的),我们可以声明一个容器(content)来容纳一个值

setup(props) {
    const content = ref<string>(null); //声明一个容器
    import(props.path).then((result) => {
      content.value = result.default;
    });
    //等加载成功之后,在成功回调里面得到result
  },

为什么写default?

因为result里面有一个default属性

结论:动态import得到的东西,有一个默认的default属性,通过default才能得到它的默认导出

content的值从原来的null,文件加载成功之后,就变成了md

  • 如何证明是异步的?

使用

setTimeout(() => {
  content.value = result.default
}, 10000)

在main.ts里面添加组件Markdown

image.png

在router.ts添加路由路径,引入Markdown.vue

image.png

展示源代码

方便用户拷贝

需要使用vue-loader的custom的blocks功能

创建Switch1Demo.vue和Switch2Demo.vue

<demo>
常规用法
</demo>

<template>
  <Switch v-model:value="bool" />
</template>

<script>
import { ref } from "vue";
import Switch from "../lib/Switch.vue";

export default {
  components: { Switch },
  setup() {
    const bool = ref(false);
    return { bool };
  },
};
</script>

如何将代码显示到页面:使用<demo></demo>,将SwitchDemo.vue的内容插入到页面;在SwitchDemo.vue里面的想要显示的代码内容用<pre>{{ Switch1Demo.__sourceCode }}</pre>包裹

插件<Switch1Demo/>等价于 <component :is="Switch1Demo" />

<template>
  <div>
    <h1>Switch 组件示例</h1>
    <div class="demo">
      <h2>常规用法</h2>
      <div class="demo-component">
        <component :is="Switch1Demo" />
      </div>
      <div class="demo-actions">
        <Button>查看代码</Button>
      </div>
      <div class="demo-code">
        <pre>{{ Switch1Demo.__sourceCode }}</pre>
      </div>
    </div>
    <div class="demo">
      <h2>支持 disabled</h2>
      <div class="demo-component">
        <component :is="Switch2Demo" />
      </div>
      <div class="demo-actions">
        <Button>查看代码</Button>
      </div>
      <div class="demo-code">
        <pre>{{ Switch2Demo.__sourceCode }}</pre>
      </div>
    </div>
  </div>
</template>

<script lang="ts">
import { ref } from "vue";
import Switch from "../lib/Switch.vue";
import Button from "../lib/Button.vue";
import Switch1Demo from "./Switch1.demo.vue";
import Switch2Demo from "./Switch2.demo.vue";
export default {
  components: { Button },
  setup() {
    const bool = ref(false);
    return { bool, Switch1Demo, Switch2Demo };
  },
};
</script>

如何高亮源代码

使用prismjsv-html

prismjs

运行

yarn add prismjs

引入prismjsprismjs/themes/prism-okaidia.css

import "prismjs";
import "prismjs/themes/prism-okaidia.css";
const Prism = (window as any).Prism;
<div class="demo-code">
  <pre
    class="language-html"
    v-html="Prism.highlight(Switch2Demo.__sourceCode, Prism.languages.html, 'html')" />
</div>

Demo组件

<Demo component="x" />

新建一个Demo.vue的文件

想在任何一个地方展示Demo,只需要引入这个组件,然后return这个组件,然后组件放到<Demo :component="组件名" />

Demo.vue

<template>
  <div class="demo">
    <h2>{{ component.__sourceCodeTitle }}</h2>
    <div class="demo-component">
      <component :is="component" />
    </div>
    <div class="demo-actions">
      <Button @click="toggleCode">查看代码</Button>
    </div>
    <div class="demo-code" v-if="codeVisible">
      <pre class="language-html" v-html="html" />
    </div>
  </div>
</template>
<script lang="ts">
import "prismjs";
import "prismjs/themes/prism-okaidia.css";
import Button from "../lib/Button.vue";
import { computed, ref } from "vue";
const Prism = (window as any).Prism;
export default {
  components: {
    Button,
  },
  props: {
    component: Object,
  },
  setup(props) {
    const html = computed(() => {
      return Prism.highlight(
        props.component.__sourceCode,
        Prism.languages.html,
        "html"
      );
    }); //html是component计算出来的属性
    const toggleCode = () => (codeVisible.value = !codeVisible.value);
    const codeVisible = ref(false);
    return { Prism, html, codeVisible, toggleCode };
  },
};
</script>

然后在需要引入的文件里面使用<Demo :component="组件名">

image.png

image.png

image.png

image.png

完善代码

点击开始的后跳转到介绍里面

将跳转路径改为redirect: "/doc/intro"

image.png