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

news2024/10/4 0:29:57

全网最详细的从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.coloradmin.cn/o/1457478.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Go-Zero】goctl生成model层后报错Unresolved reference ‘ErrNotFound‘解决方案

【Go-Zero】goctl生成model层后报错Unresolved reference ErrNotFound’解决方案 大家好 我是寸铁&#x1f44a; 总结了一篇goctl生成model层后报错Unresolved reference ErrNotFound’报错解决方案的文章✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 问题背景 大家好&#xff…

Sora 的工作原理

原文&#xff1a;How Sora Works (And What It Means) 作者&#xff1a; DAN SHIPPER OpenAI 的新型文本到视频模型为电影制作开启了新篇章 DALL-E 提供的插图。 让我们先明确一点&#xff0c;我们不会急急忙忙慌乱。我们不会预测乌托邦或预言灾难。我们要保持冷静并... 你…

java面试多线程篇

文章说明 在文章中对所有的面试题都进行了难易程度和出现频率的等级说明 星数越多代表权重越大&#xff0c;最多五颗星&#xff08;☆☆☆☆☆&#xff09; 最少一颗星&#xff08;☆&#xff09; 1.线程的基础知识 1.1 线程和进程的区别&#xff1f; 难易程度&#xff1a;☆☆…

Filterajax

1.Filter概念 概念:表示过滤器,是JavaWeb三大组件(Servlet,Filter,Listener)之一;过滤器可以把对资源的请求拦截下来,从而实现一些特殊的功能.过滤器可以完成一些通用操作比如:登录添加购物车,视频广告,敏感字符处理等等... 2.Filter快速入门 3.Listener 4.Ajax学习 1.使用场…

移动通信相关知识学习笔记

一、移动通信架构简图 移动无线的接入网是专指各种基站设备。核心网就是各种交换机。 二、无线信号基本原理 无线网络中&#xff0c;使用AP设备和天线来实现有线和无线信号互相转换。如上图所示&#xff0c;有线网络侧的数据从AP设备的有线接口进入AP后&#xff0c;经AP处理为…

一.重新回炉Spring Framework: 理解Spring IoC

1. 写在前面的话 说实话&#xff0c;从事java开发工作时间也不短了&#xff0c;对于Spring Framework&#xff0c;也是天天用&#xff0c;这期间也碰到了很多问题&#xff0c;也解决了很多问题。可是&#xff0c;总感觉对Spring Framework还是一知半解&#xff0c;不能有个更加…

PCIe学习笔记(2)错误处理和AER/DPC功能

文章目录 PCIe ErrorAER (Advanced Error Reporting)DPC (Downstream Port Containment) 处理器上错误通常可分为detected和undetected error。Undetected errors可能变得良性(benign)&#xff0c;也可能导致系统故障如silent data corruptions (SDC)。Detected errors则又可分…

2024024期传足14场胜负前瞻

2024024期赛事由亚冠5场&#xff0c;欧冠4场、英超1场、英冠4场组成。售止时间为2月20日&#xff08;周二&#xff09;17点30分&#xff0c;敬请留意&#xff1a; 本期中深盘中等&#xff0c;1.5以下赔率5场&#xff0c;1.5-2.0赔率5场&#xff0c;其他场次是平半盘、平盘。本期…

Django后端开发——ORM

文章目录 参考资料ORM-基础字段及选项字段类型练习——添加模型类应用bookstore下的models.py数据库迁移——同步至mysqlmysql中查看效果 字段选项Meta类定义示例&#xff1a;改表名应用bookstore下的models.py终端效果 练习——改表名字段选项修改应用bookstore下的models.py终…

DVWA 靶场之 Brute Force-LowMedium(前期配置铺垫与渗透方法及源码分析)

首先登录 DVWA 靶场 DVWA 默认的用户有5个&#xff0c;用户名及密码如下&#xff1a; admin/passwordgordonb/abc1231337/charleypablo/letmeinsmithy/password 难度等级设置为 low &#xff0c;我们先从最简单的开始 来到 Brute Force&#xff08;暴力破解&#xff09; 我们可…

手写myscrapy(二)

我们看一下scrapy的系统架构设计方法和思路&#xff1a; 模块化设计&#xff1a; Scrapy采用模块化设计&#xff0c;将整个系统划分为多个独立的模块&#xff0c;包括引擎&#xff08;Engine&#xff09;、调度器&#xff08;Scheduler&#xff09;、下载器&#xff08;Downl…

目录IO 2月19日学习笔记

1. lseek off_t lseek(int fd, off_t offset, int whence); 功能: 重新设定文件描述符的偏移量 参数: fd:文件描述符 offset:偏移量 whence: SEEK_SET 文件开头 SEE…

C++ 浮点数二分 数的三次方根

给定一个浮点数 n &#xff0c;求它的三次方根。 输入格式 共一行&#xff0c;包含一个浮点数 n 。 输出格式 共一行&#xff0c;包含一个浮点数&#xff0c;表示问题的解。 注意&#xff0c;结果保留 6 位小数。 数据范围 −10000≤n≤10000 输入样例&#xff1a; 1000.00…

面试题:链表相交

链表相交 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 思路 这个题目有2个思路&#xff0c;我先说容易想到的思路 对齐链表…

极速提升测试效率:揭秘Web自动化三大等待技巧!

三种等待方式 简介 在实际工作中等待机制可以保证代码的稳定性&#xff0c;保证代码不会受网速、电脑性能等条件的约束。 等待就是当运行代码时&#xff0c;如果页面的渲染速度跟不上代码的运行速度&#xff0c;就需要人为的去限制代码执行的速度。 在做 Web 自动化时&…

Jetpack 之Glance+Compose实现一个小组件

Glance&#xff0c;官方对其解释是使用 Jetpack Compose 样式的 API 构建远程 Surface 的布局&#xff0c;通俗的讲就是使用Compose风格的API来搭建小插件布局&#xff0c;其最新版本是2022年2月23日更新的1.0.0-alpha03。众所周知&#xff0c;Compose样式的API与原生差别不小&…

测试开发【Mock平台】13基础:拦截器服务实现(四) 简单规则匹配逻辑

【Mock平台】为系列测试开发教程&#xff0c;从0到1编码带你一步步使用Spring Boot 和 Antd React框架完成搭建一个测试工具平台&#xff0c;希望作为一个实战项目对各位的测试开发学习之路有帮助&#xff0c;关注公众号发送“mock”获取github项目源码地址&#xff0c;大奇一个…

力扣算法Algorithm竞赛模板库(codeforces-go):含了算法竞赛中常用的数据结构和算法实现,助力开发者更高效地解决问题

1.算法Algorithm竞赛模板库&#xff08;codeforces-go&#xff09; 算法竞赛模板库&#xff0c;为算法竞赛爱好者提供了一系列精心设计的算法模板。这个库包含了算法竞赛中常用的数据结构和算法实现&#xff0c;助力开发者更高效地解决问题 一个算法模板应当涵盖以下几点&…

【C++】【类和对象】初始化列表

1.形式和必用场景 初始化列表&#xff1a;以一个冒号开始&#xff0c;接着是一个以逗号分隔的数据成员列表&#xff0c;每个"成员变量"后面跟一个放在括号中的初始值或表达式。 #include<iostream> using namespace std; class Date { public:Date(int year,…