全网最详细的从0到1的turbo pnpm monorepo的前端工程化项目[vitePress篇]

全网最详细的从0到1的turbo pnpm monorepo的前端工程化项目[vitePress篇]

    • 前言
    • 选型
    • 为什么选择VitePress
    • 安装VitePress
    • 运行
    • 优化默认UI
    • 使用自定义UI
      • 编辑自定义布局
      • 编写home页面组件
      • 编写page页面组件
    • 结语

前言

一个好的工程化项目,必然有一个好的文档管理,这样才算称得上一个好的工程化,也大大提高后面的工作和文档查找的效率!组件库文档可以帮我们解决

  • 不知道项目中有哪些公共组件(比如组员写的组件,但是你并不知道),导致重复开发。
  • 复用组件时需要再去翻代码,看看怎么使用,传什么参数。
  • 以前写的代码,需要修改或者重构时,无从下手

选型

组件文档库是现代前端开发的重要组成部分,它可以提高团队协作效率、减少重复工作,并为项目提供一个可靠的知识库。以下是几个最受欢迎的组件文档库工具:

  • VitePress: 是一个基于 Vite 构建工具的静态网站生成器,专为编写文档而设计。它是 Vue.js 生态系统中的一部分,旨在提供简单、快速且易于使用的文档编写和展示解决方案。

  • Storybook:Storybook 是目前最流行的组件文档库工具之一。它支持 React、Vue、Angular 等主流前端框架,可以帮助开发人员将组件独立测试和展示,并提供了一个干净、易于导航的文档网站。Storybook 还提供了许多插件和工具,可帮助你更轻松地管理组件库。

  • Styleguidist:Styleguidist 是另一个流行的组件文档库工具,它专注于样式组件库的构建和文档化。它支持 React 和 Vue,并提供了一个动态的文档网站,可用于展示样式组件和交互效果。Styleguidist 还提供了许多可定制的主题和插件,可帮助你创建专业级的样式文档。

  • Docz:Docz 是一个基于 Markdown 的组件文档库工具,旨在帮助开发人员快速构建漂亮的文档网站。它支持 React 和 Vue 组件,并提供了一个干净、可定制的文档网站模板。Docz 还提供了许多插件和工具,可帮助你更轻松地管理和展示组件库。

  • Catalog:Catalog 是一个简单而强大的组件文档库工具,它支持 React 和 Vue 等主流前端框架,并提供了一个可定制的文档网站。Catalog 还提供了一些有用的功能,如交互式代码演示、快速搜索和样式调试工具。

  • Dumi: 是一个基于 Umi 的 React 文档工具,专门用于开发 React 组件的文档网站。是一个适用于 React 组件文档开发的工具,它可以帮助开发人员快速创建漂亮、易于维护的文档网站。Dumi 具有方便的 Markdown 编写、实时预览、丰富的组件库等特点和功能,可以大大提高开发效率和文档质量。

  • Docsify: 是一个轻量级的文档网站生成工具,它可以帮助你快速创建漂亮、易于阅读和导航的文档网站。是一个简单轻便的文档网站生成工具,适用于快速创建漂亮、易于阅读和导航的文档网站。它支持 Markdown 编写、自动生成导航和侧边栏、可定制主题样式等特点,使得文档编写和展示变得简单而高效。

为什么选择VitePress

VitePress 是一个轻量级、快速且易于使用的文档生成工具,适用于编写和展示各种类型的文档。它是 Vue.js 生态系统中的一部分,与 Vue 组件开发非常契合,可以帮助开发人员快速构建漂亮的文档网站。 而且VitePress 的一些特点和功能:

  1. 快速:VitePress 构建工具使用了现代化的开发服务器和打包器 Vite,可以实现秒级的冷重载和快速的热更新,以提供流畅的开发体验。

  2. Markdown 支持:VitePress 使用 Markdown 格式编写文档,Markdown 是一种易于学习和编写的标记语言,可以方便地将文档内容转换为美观的 HTML。

  3. 主题定制:VitePress 提供了易于定制的默认主题,并支持使用 Vue 组件进行自定义主题开发。你可以根据自己的需求,轻松地创建适合项目风格的文档主题。

  4. 侧边栏和导航:VitePress 提供了一个自动生成的侧边栏和导航工具,可根据 Markdown 文件结构自动创建菜单和链接,使读者可以方便地浏览和导航文档内容。

  5. 部署简单:VitePress 生成的静态网站可以轻松部署到各种静态网站托管服务(如 Netlify、GitHub Pages 等)或自行托管,没有复杂的构建过程。

安装VitePress

接上篇文章,在apps下新建 docs 文件夹, 在docs下初始化并生成package.json,安装vitepress 和 vue, 官网安装向导

$ cd apps && mkdir docs && cd docs
$ pnpm init
$ pnpm add -D vitepress vue // 或者在根目录下 pnpm add -D vitepress vue --filter="docs"
$ pnpm vitepress init // apps/docs下

pnpm vitepress init 运行时,按照提示一步一步跟自己的需要来进行配置,最终生成这样的的

docs
├─ .vitepress
│  ├─ cache
│  └─ config.ts
├─ api-examples.md
├─ index.md
├─ markdown-examples.md
└─ package.json

这个全在官网上的,没啥好说的, 唯一的我这边吧命令稍微改下,吧 docs:dev,docs:build,docs:preview 全部改成dev,build,preview 这样在turbo 任务的时候好处理,并且在根目录下加入指令 “dev”: “turbo run dev”,

运行

直接在跟目录下 或者在apps/docs下运行都可以

$ pnpm run dev // 或者在根目录下 pnpm run dev --filter="docs"

在这里插入图片描述

在这里插入图片描述

运行的效果

在这里插入图片描述

优化默认UI

  • 基础配置

修改 apps/docs/.vitepress/config.ts文件,加入全局搜索

export default defineConfig({
  title: "Robin Design",
  description: "为业余而生",
  themeConfig: {
    search: {
      provider: 'local'
    },
    // https://vitepress.dev/reference/default-theme-config
    nav: [
      { text: '首页', link: '/' },
      { text: '组件', link: '/markdown-examples' }
    ],

    sidebar: [
      {
        text: 'Examples',
        items: [
          { text: 'Markdown Examples', link: '/markdown-examples' },
          { text: 'Runtime API Examples', link: '/api-examples' }
        ]
      }
    ],

    socialLinks: [
      { icon: 'github', link: 'https://github.com/vuejs/vitepress' }
    ]
  }
})
  • 新建css, 在.vitepress/theme下新建 common.css和index.ts

common.css

:root {
  --vp-home-hero-name-color: transparent;
  --vp-home-hero-name-background: -webkit-linear-gradient(120deg, #bd34fe 30%, #41d1ff);
  --vp-home-hero-image-background-image: linear-gradient(-45deg, #bd34fe 50%, #47caff 50%);
  --vp-home-hero-image-filter: blur(44px);
}
.VPNavBarTitle>.title>span{    height: var(--vp-nav-height);
  font-size: 24px;
  font-weight: 700;
  color: var(--vp-c-text-1);
  line-height: calc(var(--vp-nav-height) - 4px);
  background: #005de0 -webkit-linear-gradient(left,#005de0,#febaf7 50%,#bd34fe 90%,#561214) no-repeat 0 0;
  background-size: 20% 100%;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  text-decoration: underline;
  -webkit-animation: slideShine 2s linear infinite;
  animation: slideShine 2s linear infinite;
}

.clip{
  background: var(--vp-home-hero-name-background);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: var(--vp-home-hero-name-color);
}


@-webkit-keyframes slideShine {
  0% {
      background-position: 0 0
  }

  to {
      background-position: 100% 100%
  }
}

@keyframes slideShine {
  0% {
      background-position: 0 0
  }

  to {
      background-position: 100% 100%
  }
}

index.ts

import DefaultTheme from 'vitepress/theme'
import './common.css'

export default DefaultTheme
  • 优化首页,这个首页没有做很多处理,首页弄成跟官网一样,这个后期有更好的在做处理,这个文件在apps/docs/index.md
---
layout: home

hero:
  name: "Robin Design"
  text: "为了业余而生 "
  tagline: Robin更表现出我当下的心境
  actions:
    - theme: brand
      text: 快速开始
      link: /markdown-examples
    - theme: alt
      text: GitHub
      link: /api-examples

features:
  - title: 蓝色知更鸟
    details: 蓝色知更鸟的身体主要是蓝色的,头部有白色斑点,翅膀上有黑色条纹
  - title: 红胸知更鸟
    details: 红胸知更鸟的胸部是橙红色的,头部和背部是深灰色的,腹部是白色的
  - title: 紫翅知更鸟
    details: 紫翅知更鸟的羽毛呈现出紫色的光泽,具有黑色的头部和背部
  - title: 黄腹知更鸟
    details: 黄腹知更鸟的身体是鲜黄色的,头部有一些淡绿色的斑块
  - title: 绿头鸭
    details: 绿头鸭的雄性具有独特的羽毛颜色,头部呈现出绿色,身体大部分是灰褐色的

效果图
在这里插入图片描述

使用自定义UI

我这边不太喜欢默认的,修改的需要自己查好多文档来进行处理,很耗时。这里我使用自定义的方式来实现,

编辑自定义布局

修改theme/index.ts 文件

import './common.css'
import Layout from './Layout.vue'

export default {
  Layout: Layout
}

新增 theme/Layout.vue

<script setup>
import { useData } from 'vitepress'
import NotFound from './NotFound.vue'
import Home from './Home.vue'
import Page from './page/index.vue'

const { page, frontmatter } = useData()
</script>

<template>
  <Home v-if="frontmatter.layout === 'home'" />
  <NotFound v-else-if="page.isNotFound" />
  <Page v-else />
</template>

新增 theme/NotFound.vue 404页面, Home和Page组件请看下面

编写home页面组件

新增 theme/Home.vue

<template>
  <div class="warp">
    <div class="warp-banner">
      <div class="card-box">
        <div class="card-box-left">
          <div class="title">{{ frontmatter.hero.name }}</div>
          <div class="desc">{{ frontmatter.hero.text }}</div>
          <div class="tagline">{{ frontmatter.hero.tagline }}</div>
          <div class="button-warp">
            <a>快速开始</a>
            <a>GitHub</a>
          </div>
        </div>
        <div class="card-box-right">
          <img src="/public/dev.png" />
        </div>
      </div>
      <div class="big-title">知更鸟</div>
      <div class="card-box">
        <div class="card-box-left title-bg">
          <div class="title"></div>
        </div>
        <ul class="card-box-right feat-warp">
          <li class="feat-item" v-for="(item,inx) in frontmatter.features" :key="inx">
            <svg class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="200" height="200">
              <path d="M83.5 517.7a428.7 432.5 0 1 0 857.4 0 428.7 432.5 0 1 0-857.4 0Z" :fill="item.color"></path>
              <path d="M517.2 711.1c-22-6.7-44.5-11.5-65.2-22.1-76.3-38.9-115.2-116.6-97.9-203.5 8.5-42.7-28.5-84.6-71.6-75.4-23.5 5-47.8 6.1-71.7 9.3-5 0.7-9.7 2.5-13-4.2 20.2-4.9 40.3-9.5 60.4-14.6 19.2-4.8 32.6-15.9 41.3-34.4 23.9-50.4 80.1-57.7 116.4-15.1 21.8 25.5 36.7 55.8 55.4 83.5 4 5.9 8.3 11.5 12.4 17.2 6.2 14.5 16.5 17.4 30.6 11.5 26.1-10.9 52.4-21.4 78.7-32 71.3-28.2 142.7-56.4 214.1-84.6 0.4 1.5 1.2 2.7 0.9 3.3-35.6 60.3-76.1 116.9-128.7 163.9-29.8 26.7-61.9 49.7-104.6 49.4-8.4 0-7.9 5.6-8.5 11.1-4.2 39.7 8.4 73.9 36.2 101.9 36.1 36.4 57.7 79.7 65.6 130 1.1 6.8 3.1 14 0 20.9-0.1 0.2-0.8 0.4-1.2 0.3-0.5-0.2-0.9-0.6-1.4-0.9-4.9-19.2-18-33.5-30.5-47.6-31.6-35.3-69.9-60.1-117.7-67.9z" fill="#FFFFFF"></path>
              <path d="M593 431.4c-26.2 10.6-52.6 21.1-78.7 32-14.1 5.9-24.4 3-30.6-11.5 65.9-51.3 131.8-102.5 197.6-153.8 1.1 1 2.2 2.1 3.3 3.1-14.5 20-29.1 39.9-43.3 60.1-16.2 23.3-34.2 45.3-48.3 70.1zM517.2 711.1c47.8 7.8 86.1 32.6 117.7 68.1 12.5 14 25.6 28.3 30.5 47.6-19.5-13-39-25.9-62.8-29.6-4.2-0.6-7.1-2.8-8.7-6.5-15.3-36.5-43.4-60.6-76.7-79.6z" fill="#C5FFDF"></path>
            </svg>
            <div class="item-info">
              <div class="title">{{item.title}}</div>
              <div class="desc">{{item.details}}</div>
            </div>
          </li>
        </ul>
      </div>
    </div>
    <h1>我是首页</h1>
    <Content />
  </div>
</template>

<script setup>
import { useData } from 'vitepress'

const { frontmatter } = useData()
</script>

<style scoped>
  .....
.item-info .desc{
  line-height: 24px;
  font-size: 13px;
  color: #3c3c43;
  opacity: 0.6;
}
</style>

效果图如下

在这里插入图片描述

编写page页面组件

新增 theme/page文件夹,在page文件夹新增footer.vue,header.vue, sidebar.vue, index.vue

编写footer.vue

<template>
  <div class="page-footer">
    <span>{{ theme.footer.copyright }}</span>
  </div>
</template>

<script setup>
import { useData } from 'vitepress'

const { theme } = useData()
</script>

<style scoped>
.page-footer {
  position: relative;
  background-color: #f3f3f3;
  height: 26px;
  font-size: 12px;
  text-align: center;
  color: #666;
  flex: 0 0 auto
}
.page-footer>span {
  opacity: .4;
  line-height: 26px
}
</style>

编写header.vue

<template>
  <div class="page-header">
    <div class="left">
      <span class="slide-title">{{ site.title }}</span>
    </div>
    <div class="right">
      <ul class="ul-nav">
        <li v-for="nav in theme.nav" :key="nav.link">
          <a :href="nav.link">{{ nav.text }}</a>
        </li>
      </ul>
      <div class="user">
        <svg viewBox="0 0 1024 1024" width="30" height="30" class="icon"><path data-v-074131e3="" d="M530.324211 630.74807l27.486315 46.708772 37.367018 63.41614a3.413333 3.413333 0 0 1 0 5.030176q-31.079298 30.181053-61.799298 60.901053c-1.796491 1.796491-2.694737 1.97614-4.670878 0l-62.158596-61.080702c-1.437193-1.437193-1.97614-2.515088 0-4.491228q31.977544-53.894737 63.775439-107.789474l1.437193-2.155789z" p-id="7910"></path><path data-v-074131e3="" d="M842.374737 826.385965a9.162105 9.162105 0 0 1-8.982456-8.802807c-2.874386-87.848421-57.487719-196.53614-156.115088-234.442105a9.341754 9.341754 0 0 1-5.569123-6.28772 8.802807 8.802807 0 0 1 2.15579-8.08421c42.037895-45.630877 60.721404-89.824561 60.541754-140.665263a181.804912 181.804912 0 0 0-72.757895-143.719299 9.162105 9.162105 0 0 1-2.694737-12.575438 8.982456 8.982456 0 0 1 12.39579-2.515088 197.614035 197.614035 0 0 1 81.021754 159.528421 211.806316 211.806316 0 0 1-56.769122 143.719298c98.447719 44.373333 152.701754 155.396491 155.755789 245.580351a8.982456 8.982456 0 0 1-8.623158 9.341755z m-566.613333 0a8.802807 8.802807 0 0 1-8.443509-9.521404 258.515088 258.515088 0 0 1 206.596491-239.112982A158.091228 158.091228 0 0 1 415.169123 538.947368a8.982456 8.982456 0 0 1 13.114386-12.395789 141.38386 141.38386 0 0 0 211.267368-8.26386 8.982456 8.982456 0 1 1 13.832983 11.317895 157.73193 157.73193 0 0 1-70.242807 49.403509 259.054035 259.054035 0 0 1 200.488421 237.136842 8.982456 8.982456 0 0 1-8.623158 9.521403 8.802807 8.802807 0 0 1-9.341755-8.443508 240.909474 240.909474 0 0 0-480.920701 0 8.982456 8.982456 0 0 1-8.982456 9.162105z m360.735438-495.292632a9.162105 9.162105 0 0 1-6.467368-2.694737 141.204211 141.204211 0 0 0-197.614035-1.257543 9.162105 9.162105 0 0 1-12.755088 0 8.982456 8.982456 0 0 1 0-12.755088 159.169123 159.169123 0 0 1 223.663158 1.616842 8.982456 8.982456 0 0 1-6.28772 15.270175z" p-id="7911"></path><path data-v-074131e3="" d="M591.584561 512a84.794386 84.794386 0 0 1-61.978947-26.947368 85.153684 85.153684 0 1 1 0-116.77193 85.153684 85.153684 0 1 1 61.978947 143.719298z m0-123.778246a38.804211 38.804211 0 1 0 38.624562 38.624562 38.624561 38.624561 0 0 0-38.624562-38.624562z m-123.778245 0a38.804211 38.804211 0 1 0 38.624561 38.624562A38.804211 38.804211 0 0 0 467.087719 388.221754z"></path></svg>
        <span>Robin</span>
      </div>
    </div>
  </div>
</template>

<script setup>
import { useData } from 'vitepress'

const { site, theme } = useData()
</script>

<style scoped>
.page-header {
  position: relative;
  height: 44px;
  padding-right: 20px;
  background-color: #222833;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
}
.page-header .left{
  position: relative;
  font-size: 20px;
  padding: 0 10px;
  border-right: 2px solid rgba(255,255,255,0.1);
}
.page-header .right{
  position: relative;
  display: flex;
  align-items: center;
  flex: 1;
  text-align: left;
  height: 100%;
  padding-left: 10px;
}
.slide-title{
  font-size: 20px;
  background: #005de0 -webkit-linear-gradient(left,#005de0,#febaf7 50%,#ff0 90%,#bd34fe) no-repeat 0 0;
  background-size: 20% 100%;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  text-decoration: underline;
  -webkit-animation: slideShine 3s linear infinite;
  animation: slideShine 3s linear infinite;
}
.ul-nav{
  flex: 1;
  border-right: 2px solid rgba(255,255,255,0.1);
  margin: 0 10px;
  font-size: 14px;
}
.ul-nav>li {
  position: relative;
  display: inline-block;
  height: 100%;
  padding: 12px 15px;
  cursor: pointer;
  z-index: 2
}
.ul-nav>li a {
  color: #fff;
  opacity: .7
}
.ul-nav>li.active:before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  opacity: .1;
  background: #fff;
  display: inline-block;
  height: 100%;
  width: 100%
}
.ul-nav>li.active:after {
  content: "";
  position: absolute;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  border-bottom: 4px solid #378cff;
  border-right: 18px solid transparent;
  border-left: 18px solid transparent
}
.ul-nav>li.active a {
  opacity: 1;
}
.user{
  position: relative;
  z-index: 2;
  background: hsla(0,0%,100%,.2);
  display: inline-block;
  height: 35px;
  border-radius: 20px;
  padding: 0 15px;
  cursor: pointer;
  margin-left: 15px;
}
.user>svg{
  vertical-align: middle;
  fill: #fff;
}
.user>span{
  vertical-align: sub;
}
</style>

编写sidebar.vue

<template>
  <nav class="nav-warp">
    <h2 class="nav-title active">
      <svg class="svg-icon nav" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" >
        <path d="M444.188444 84.423111V917.048889H967.111111z" fill="#00F4FC"></path>
        <path d="M444.302222 510.407111v406.755556H967.111111L711.793778 510.407111H444.302222z" fill="#02BEFF"></path>
        <path d="M444.188444 510.407111H56.888889v406.755556h387.299555z" fill="#005FE0"></path>
      </svg>
      <span>入门</span>
    </h2>
    <ul class="nav-items">
      <li class="nav-item">
        <a class="nav-group">
          <span>规范</span>
          <span class="icon-chevron-down">
            <svg width="1em" height="1em" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
              <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
                <path d="M12.1464466,6.85355339 L8.35355339,10.6464466 C8.15829124,10.8417088 7.84170876,10.8417088 7.64644661,10.6464466 L3.85355339,6.85355339 C3.65829124,6.65829124 3.65829124,6.34170876 3.85355339,6.14644661 C3.94732158,6.05267842 4.07449854,6 4.20710678,6 L11.7928932,6 C12.0690356,6 12.2928932,6.22385763 12.2928932,6.5 C12.2928932,6.63260824 12.2402148,6.7597852 12.1464466,6.85355339 Z" fill-rule="nonzero" class="ng-tns-c41-5"></path>
              </g>
            </svg>
          </span>
        </a>
      </li>
    </ul>
  </nav>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { useData } from 'vitepress'

const { theme } = useData()
const navInx = ref(0)
const groupInx = ref(0)

</script>

<style scoped>
.svg-icon {
    width: 1.2em;
    height: 1.2em;
    vertical-align: -0.2em;
    overflow: hidden;
}
.sidebar{
  position: relative;
  display: inline-block;
  border-right: 1px solid #ebeff2;
  color: #3F536E;
  width: 190px;
  height: 100%;
  background: #fff;
  transition: all .3s;
}
.happy-scroll{
  width: 190px;
  height: 100%;
}
.nav-child-item{
  position: relative;
}
.btn-svg{
  display: inline-block;
  position: fixed;
  left: 162px;
  z-index: 2;
  top: 50%;
  transform: translateY(-50%);
  cursor: pointer;
  transition: all .3s;
}
.btn-svg svg{
  transform: rotate(-90deg);
}
.nav-warp{
  font-size: 14px;
  width: 190px;
  padding-bottom: 15px;
}
.nav-title{
  position: relative;
  padding: 0 0 5px 20px;
  color: #657085;
  font-size: 16px;
  letter-spacing: 0;
  text-transform: uppercase;
  font-weight: 600;
  margin-top: 15px;
}
.nav-title .nav{
  position: absolute;
  top: 1px;
  left: 2px;
  display: none;
  font-size: 13px;
}
.nav-title.active .nav{
  display: inline-block;
}
.nav-group{
  display: block;
  position: relative;
  padding: 6px 0 6px 20px;
  color: #575d6c;
  font-weight: 600;
  z-index: 2;
}
.nav-group:hover{
  color: #1a6fe3;
}
.nav-group i{
  position: absolute;
  top: 50%;
  right: 16px;
  margin-top: -7px;
  color: #A8C6DF;
  font-size: 14px;
  transition: all .3s;
}
.nav-items{
  font-size: 14px;
  font-weight: normal;
  line-height: 1.8;
}
.nav-item{
  position: relative;
}
.nav-child-items{
  display: none;
}
.active .nav-child-items{
  display: block;
}
.nav-page{
  display: block;
  position: relative;
  padding: 5px 0 5px 20px;
  color: #333;
  font-weight: normal;
  line-height: 1.5;
  cursor: pointer;
  font-weight: 600;
}
.nav-page:hover {
  color: #005FE0;
  background-color: rgba(236, 242, 252, 0.25);
}
.nav-page.active,
.nav-page.router-link-active{
  color: #005FE0;
  background-color: rgba(236,242,252,0.2);
}
.nav-page.active:after,
.nav-page.router-link-active:after{
  display: inline-block;
}
.nav-page.active:hover,
.nav-page.router-link-active:hover{
  color: #3F536E;
}
.nav-component{
  display: block;
  position: relative;
  padding: 3px 0px 3px 27px;
  font-size: 12px;
  color: #575d6c;
  font-family: "Comic Sans MS";
  z-index: 2;
}
.nav-component:hover{
  color: #005FE0;
  background-color: rgba(236, 242, 252, 0.25);
}
.nav-component.active,
.nav-component.router-link-active{
  color: #005FE0;
  background-color: rgba(236, 242, 252, 0.25);
}
.nav-component.router-link-active .svg-promotion{
  display: inline-block;
}
.nav-component span{
  padding-left: 6px;
  font-size: 13px;
}
.nav-item.active .icon-chevron-down{
  transform: rotate(180deg);
  transform-origin: center;
}
.icon-chevron-down{
  display: inline-block;
  text-indent: 0;
  pointer-events: none;
  position: absolute;
  right: 10px;
  top: 12px;
  width: 16px;
  height: 16px;
  line-height: 16px;
  transition: transform .3s cubic-bezier(.645,.045,.355,1);
}
.icon-chevron-down svg{
  width: 16px;
  height: 16px;
}
.icon-chevron-down svg path{
  fill: #575d6c;
}
.svg-promotion{
  display: inline-block;
  height: 1em;
  width: 1em;
  line-height: normal;
  fill: #1a6fe3;
  position: absolute;
  top: 9px;
  left: 10px;
  display: none;
}
</style>

编写index.vue

<template>
  <div class="page">
    <PageHeader class="page-header"></PageHeader>
    <div class="page-content">
      <div class="sidebar">
        <pageSidebar></pageSidebar>
      </div>
      <div class="md-warp">
        <Content />
      </div>
    </div>
    <pageFooter class="page-footer"></pageFooter>
  </div>
</template>

<script setup lang="ts">
import PageHeader from './header.vue'
import pageFooter from './footer.vue'
import pageSidebar from './sidebar.vue'
</script>

<style scoped>
.page{
  width: 100%;
  height: 100%;
  overflow: hidden
}
.page-content {
  position: relative;
  display: flex;
  background: #ebeff2;
  height: calc(100% - 70px)
}
.page-content>.sidebar {
  position: relative;
  display: inline-block;
  border-right: 1px solid #ebeff2;
  color: #3f536e;
  width: 190px;
  flex-shrink: 0;
  height: 100%;
  background: #fff;
  transition: all .3s;
}
.page-content>.md-warp{
  position: relative;
  padding: 15px;
  flex: 1;
  padding: 0;
  background: #ebeff2;
  z-index: 1;
  overflow: auto;
}
.md-warp>div{
  position: relative;
  padding: 15px;
}

</style>

整体效果如下
在这里插入图片描述

结语

本文从实战出发,在前篇一个为 turbo的基础项目工程项目基础下,搭建vitePress,本文我估计,是全网唯一一个手把手第一次真正从0到一的完整的教程,纯属个人见解,因为我没有看到像我这么全的!,本文旨意在搭建一个vue3的组件库,后面还有更多的文章信息,我也不知道后面文章什么时候更新,本人很赖!希望大家鼓励鼓励我!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/395409.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【复现】Panalog大数据日志审计系统 RCE漏洞_51

目录 一.概述 二 .漏洞影响 三.漏洞复现 1. 漏洞一&#xff1a; 四.修复建议&#xff1a; 五. 搜索语法&#xff1a; 六.免责声明 一.概述 Panalog大数据日志审计系统定位于将大数据产品应用于高校、 公安、 政企、 医疗、 金融、 能源等行业之中&#xff0c;针对网络流…

秒级到毫秒级的跨越—一次慢SQL优化历险

一次慢 SQL 优化过程 一、背景 对于公司内部的一个发票管理系统&#xff0c;财务人员经常需要对发票的开票交易进行查询&#xff0c;这里涉及到两张表&#xff1a;发票订单表和发票信息表&#xff0c;我们需要查询订单 ID、开票 APP、开票主体、订单类型、支付渠道、支付总额…

Linux系统安全:安全技术和防火墙

目录 一、安全技术和防火墙 1.安全技术 2.防火墙的分类 二、防火墙 1.iptables四表五链 2.黑白名单 3.iptables基本语法 4.iptables选项 5.控制类型 6.隐藏扩展模块 7.显示扩展模块 8.iptables规则保存 9.自定义链使用 一、安全技术和防火墙 1.安全技术 入侵检测系…

AMD FPGA设计优化宝典笔记(5)低频全局复位与高扇出

亚军老师的这本书《AMD FPGA设计优化宝典》&#xff0c;他主要讲了两个东西&#xff1a; 第一个东西是代码的良好风格&#xff1b; 第二个是设计收敛等的本质。 这个书的结构是一个总论&#xff0c;加上另外的9个优化&#xff0c;包含的有&#xff1a;时钟网络、组合逻辑、触发…

在ubuntu20.04 上配置 qemu/kvm linux kernel调试环境

一&#xff1a;安装qemu/kvm 和 virsh qemu/kvm 是虚拟机软件&#xff0c;virsh是管理虚拟机的命令行工具&#xff0c;可以使用virsh创建&#xff0c;编辑&#xff0c;启动&#xff0c;停止&#xff0c;删除虚拟机。 &#xff08;1&#xff09;&#xff1a;安装之前&#xff0c…

Matlab|基于支持向量机的电力短期负荷预测【最小二乘、标准粒子群、改进粒子群】

目录 主要内容 部分代码 结果一览 下载链接 主要内容 该程序主要是对电力短期负荷进行预测&#xff0c;采用三种方法&#xff0c;分别是最小二乘支持向量机&#xff08;LSSVM&#xff09;、标准粒子群算法支持向量机和改进粒子群算法支持向量机三种方法对负荷进行…

Shiro-05-shiro 基础知识补充密码学+哈希散列

密码学 密码术是隐藏或混淆数据的过程&#xff0c;因此窥探眼睛无法理解它。 Shiro的加密目标是简化JDK的加密支持并使之可用。 需要特别注意的是&#xff0c;密码通常不是特定于主题的&#xff0c;因此Shiro API的其中一个领域不是特定于主题的。 即使未使用“主题”&…

Android 架构组件全示例

Android 架构组件全示例 Android架构组件属于Jetpack的组成部分&#xff0c;彻底改变了开发人员构建健壮且易于维护的Android应用程序的方式。通过Room、Lifecycle-aware组件、ViewModels、LiveData、Paging、Navigation、ViewBinding和WorkManager等组件&#xff0c;开发人员…

K8s进阶之路-命名空间级-服务发现 :

服务发现&#xff1a; Service&#xff08;东西流量&#xff09;&#xff1a;集群内网络通信、负载均衡&#xff08;四层负载&#xff09;内部跨节点&#xff0c;节点与节点之间的通信&#xff0c;以及pod与pod之间的通信&#xff0c;用Service暴露端口即可实现 Ingress&#…

python绘制k线图均线图

AAPL.csv 数据文件 Date,Close,Volume,Open,High,Low 06/23/2023,$186.68,53117000,$185.55,$187.56,$185.01 06/22/2023,$187.00,51245330,$183.74,$187.045,$183.67 06/21/2023,$183.96,49515700,$184.90,$185.41,$182.5901 06/20/2023,$185.01,49799090,$184.41,$1…

unity学习(15)——服务器组装(1)

1.新建好的c#项目如下&#xff1a; 文件夹中内容如下&#xff1a; 此时已经可以通过vs2022打开.sln文件&#xff0c;就可以打开项目了。 2.我们把逆向后&#xff08;主程序&#xff09;的内容的代码粘贴过去。有些逆向功底&#xff0c;很快可以定位到&#xff0c;服务器的入口…

uniapp项目准备工作

1.封装请求 export const baseUrl function getHeaders () {let token uni.getStorageSync(token)let header {"access-token":token,// X-Requested-With: XMLHttpRequest,Content-Type: application/json; charsetUTF-8}return header } function reLogin(){/…

Leetcoder Day14|二叉树part03

语言&#xff1a;Java/C 104.二叉树的最大深度​​​​​​​ 给定一个二叉树&#xff0c;找出其最大深度。 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。 说明: 叶子节点是指没有子节点的节点。 示例&#xff1a; 给定二叉树 [3,9,20,null,null,15,7]&#xf…

如何配置OSS中的文件是预览还是下载

如何决定文件是预览还是下载 1. 首先需要绑定自己的二级域名&#xff0c;下载时使用自己的二级域名下载 链接&#xff1a;关于绑定域名的官方文档 2. 文件需要配置正确的请求头 链接&#xff1a; 关于设置文件Content-Type的官方文档 2.1 设置或修改文件请求头包含多种方式…

【C++】C++11中

C11中 1.lambda表达式2.可变参数模板3.包装器 1.lambda表达式 在前面我们学习过仿函数。仿函数的作用到底是干什么的呢&#xff1f; 它为了抛弃函数指针&#xff01; 主要是因为函数指针太难学了 就比如下面这个&#xff0c;看着也挺难受的。 它的参数是一个函数指针&#x…

IO线程-day2

1> 使用fread和fwrite完成两个文件的拷贝 程序&#xff1a; #define MAXSIZE 1024 #include<myhead.h>int main(int argc, char const *argv[]) {FILE *srcfpNULL;FILE *destfpNULL;if(!(srcfpfopen("pm.bmp","r")))PRINT_ERR("");if…

【漏洞复现-通达OA】通达OA video_file.php 任意文件下载漏洞

一、漏洞简介 通达OA video_file.php文件存在任意文件下载漏洞&#xff0c;攻击者通过漏洞可以读取服务器敏感文件。 二、影响版本 ● 通达OA2011 三、资产测绘 ● hunterapp.name"通达 OA" ● 特征 四、漏洞复现 GET /general/mytable/intel_view/video_file.…

比特浏览器bit_selenium3bit_selenium4使用

bit_selenium3 from selenium import webdriver from selenium.common.exceptions import TimeoutException from selenium.webdriver.common.keys import Keys from selenium.webdriver.chrome.options import Options from bit_api import *# /browser/open 接口会返回 selen…

【C/C++】实现Reactor高并发服务器 完整版

代码结构 文件介绍 InetAddress.h InetAddress类 ip和端口设置 Socket.h Socket类 设置fd Epoll.h epollfd 管理类 Channel.h Channel类 管理epoll以及对应回调函数实现 EventLoop.h EventLoop事件循环类 TcpServer.h 服务器类 tcpepoll.cpp 主函数 InetAddress.h #if…

腾讯云OSS文件上传功能

腾讯云COS介绍 腾讯云COS&#xff08;Cloud Object Storage&#xff09;是一种基于对象的存储服务&#xff0c;用于存储和管理海量的非结构化数据&#xff0c;如图片、音视频文件、备份数据等。它具有以下特点和优势&#xff1a; 高可靠性&#xff1a;采用分布式存储架构&…
最新文章