VuePress 使用并应用 mcommon 模板

发布于:2025-07-04 ⋅ 阅读:(15) ⋅ 点赞:(0)

VuePress 可以实现用 Markdown 编程,快速便捷开发网站

通过命令行创建项目模板 

npm init vuepress vuepress-starter

你想要创建什么类型的项目? 这个配置选择 docs

启动项目

npm run docs:dev

网站启动了,编辑 README.md 文件可以实时更新页面

这个模板是官方提供的,现在要设计自己的模板。首先需要安装一个自动注册组件的包

npm install unplugin-vue-components -D

添加配置 docs\.vuepress\config.js

import Components from 'unplugin-vue-components/vite'

  bundler: viteBundler({
    viteOptions: {
      plugins: [
        Components({
          dirs: ['components'],
          allowOverrides: true,
          directoryAsNamespace: true, // 组件命令带路径
          dts: 'components.d.ts',
        })
      ]
    },
  }),

 docs 目录下添加 components 目录,添加 vd-tag.vue 文件

<template>
    <div class="auto">
        自动注册组件测试
    </div>
</template>

 启动项目

npm run docs:dev

生成 components.d.ts

/* eslint-disable */
// @ts-nocheck
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
// biome-ignore lint: disable
export {}

/* prettier-ignore */
declare module 'vue' {
  export interface GlobalComponents {
    VdTag: typeof import('./components/vd-tag.vue')['default']
  }
}

 首页引入自动生成的全局组件 README.md 末尾追加

<VdTag />

那么怎么引入代码块呢

以前版本写法

 <<< ./docs/.vuepress/config.js

 最新版本写法

@[code](./.vuepress/config.js)

但是如果做为组件插槽的内容使用时 @[code](./.vuepress/config.js) 必须上方和下方有一空行才会生效。

<DemoBlock>

@[code](./.vuepress/config.js)

</DemoBlock>

 DemoBlock 组件从 mcommon 上借鉴的模板

<template>
  <div class="demo-block"
    :class="['demo', { 'hover': hovering }]"
    @mouseenter="hovering = true"
    @mouseleave="hovering = false">
    <div class="source">
      <slot name="source"></slot>
    </div>
    <div class="meta"
      ref="meta">
      <div class="description"
        v-if="$slots.default">
        <slot></slot>
      </div>
      <div class="highlight">
        <slot name="highlight"></slot>
      </div>
    </div>
    <div class="demo-block-control"
      ref="control"
      :class="{ 'is-fixed': fixedControl }"
      @click="isExpanded = !isExpanded">
      <transition name="arrow-slide">
        <i :class="[iconClass, { 'hovering': hovering }]"></i>
      </transition>
      <transition name="text-slide">
        <span v-show="hovering">{{ controlText }}</span>
      </transition>
    </div>
  </div>
</template>

<style lang="scss">
.demo-block {
  border: solid 1px #ebebeb;
  border-radius: 3px;
  transition: 0.2s;
  &.hover {
    box-shadow: 0 0 8px 0 rgba(232, 237, 250, 0.6),
      0 2px 4px 0 rgba(232, 237, 250, 0.5);
  }
  .demo-button {
    float: right;
  }
  .source {
    padding: 24px;
  }
  .meta {
    background-color: #fafafa;
    border-top: solid 1px #eaeefb;
    overflow: hidden;
    height: 0;
    transition: height 0.2s;
  }
  .description {
    padding: 20px;
    box-sizing: border-box;
    border: solid 1px #ebebeb;
    border-radius: 3px;
    color: #666;
    word-break: break-word;
    margin: 10px;
    background-color: #fff;
    p {
      margin: 0;
      line-height: 26px;
    }
  }
  .highlight {
    pre {
      margin: 0;
    }
    code.hljs {
      margin: 0;
      border: none;
      max-height: none;
      border-radius: 0;
      &::before {
        content: none;
      }
    }
  }
  .demo-block-control {
    border-top: solid 1px #eaeefb;
    height: 44px;
    box-sizing: border-box;
    background-color: #fff;
    border-bottom-left-radius: 4px;
    border-bottom-right-radius: 4px;
    text-align: center;
    margin-top: -1px;
    color: #d3dce6;
    cursor: pointer;
    position: relative;

    &.is-fixed {
      position: fixed;
      bottom: 0;
      width: 718px;
      z-index: 1;
    }
    i {
      font-size: 16px;
      line-height: 44px;
      transition: 0.3s;
      &.hovering {
        transform: translateX(-40px);
      }
    }
    > span {
      position: absolute;
      transform: translateX(-30px);
      font-size: 14px;
      line-height: 44px;
      transition: 0.3s;
      display: inline-block;
    }
    &:hover {
      color: #409eff;
      background-color: #f9fafc;
    }
    & .text-slide-enter,
    & .text-slide-leave-active {
      opacity: 0;
      transform: translateX(10px);
    }

    .control-button {
      line-height: 26px;
      position: absolute;
      top: 0;
      right: 0;
      font-size: 14px;
      padding-left: 5px;
      padding-right: 25px;
    }
  }
  table {
    margin: 0;
    display: table;
  }
  th,
  td,
  tr {
    border: 0;
  }
}
.el-popper {
  table {
    margin: 0;
    display: table;
  }
  th,
  td,
  tr {
    border: 0;
  }
  tr:nth-child(2n) {
    background: none;
  }
}
</style>

<script type="text/babel">
export default {
  name: 'DemoBlock',
  data () {
    return {
      codepen: {
        script: '',
        html: '',
        style: ''
      },
      hovering: false,
      isExpanded: false,
      fixedControl: false,
      scrollParent: null
    }
  },
  methods: {
    scrollHandler () {
      const { top, bottom, left } = this.$refs.meta.getBoundingClientRect()
      this.fixedControl = bottom > document.documentElement.clientHeight &&
          top + 44 <= document.documentElement.clientHeight
    },
    removeScrollHandler () {
      this.scrollParent && this.scrollParent.removeEventListener('scroll', this.scrollHandler)
    }
  },
  computed: {
    iconClass () {
      return this.isExpanded ? 'el-icon-caret-top' : 'el-icon-caret-bottom'
    },
    controlText () {
      return this.isExpanded ? '隐藏代码':'显示代码'
    },
    codeArea () {
      return this.$el.getElementsByClassName('meta')[0]
    },
    codeAreaHeight () {
      if (this.$el.getElementsByClassName('description').length > 0) {
        return this.$el.getElementsByClassName('description')[0].clientHeight +
            this.$el.getElementsByClassName('highlight')[0].clientHeight + 20
      }
      return this.$el.getElementsByClassName('highlight')[0].clientHeight
    }
  },
  watch: {
    isExpanded (val) {
      this.codeArea.style.height = val ? `${this.codeAreaHeight + 1}px` : '0'
      if (!val) {
        this.fixedControl = false
        this.removeScrollHandler()
        return
      }
      setTimeout(() => {
        this.scrollParent = window
        this.scrollParent && this.scrollParent.addEventListener('scroll', this.scrollHandler)
        this.scrollHandler()
      }, 200)
    }
  },
  created () {
    const highlight = this.$slots.highlight
    if (highlight && highlight[0]) {
      let code = ''
      let cur = highlight[0]
      if (cur.tag === 'pre' && (cur.children && cur.children[0])) {
        cur = cur.children[0]
        if (cur.tag === 'code') {
          code = cur.children[0].text
        }
      }
    }
  },
  mounted () {
    this.$nextTick(() => {
      let highlight = this.$el.getElementsByClassName('highlight')[0]
      if (this.$el.getElementsByClassName('description').length === 0) {
        highlight.style.width = '100%'
        highlight.borderRight = 'none'
      }
    })
  },
  beforeDestroy () {
    this.removeScrollHandler()
  }
}
</script>

demo.vue

<template>
  <ul class="demo-select">
    <li class="li">
      <label>基本用法</label>
      <select v-model="value" ></select>
    </li>
    <li class="li">
      <label>异步获取数据</label>
      <select v-model="value"></select>
    </li>
  </ul>
</template>
<script>
export default {
  data() {
    return {
      value: null
    };
  },
  methods: {
  }
};
</script>
<style lang="scss">
</style>

README.md

<DemoBlock>
<template #source>
  <Demo />
</template>

@[code](./.vuepress/config.js)

</DemoBlock>

 

vuepress 模板推荐

瀑布流容器 | Plume 主题

https://theme-hope.vuejs.press/zh/demo/portfolio-home.html

友情链接 | Plume 主题