基于vite从0-1创建一个vue3组件库(二)

1,141 阅读3分钟

组件文档和预览效果

首先我列举一下目前比较主流的几个文档展示框架

  • story-book
  • vue-press
  • dumi
    这些文档展示框架都可以用于展示组件,但是他们都有一套自己的规则,也存在额外的学习成本。所以我选择不采用这些,而是通过上一节通过vite创建的项目本身来构建一个文档预览应用。

构建文档预览应用

我们当前启动项目只能看到如下的结果

image.png 对比主流的组件库应用,我们最起码需要达成下面几个条件:

  1. 一个关于组件的导航菜单
  2. 组件的预览效果
  3. 组件的实例代码
  4. 组件的简介(配置项,事件,额外说明等)

1.添加组件的导航菜单

这里我们引用vue-router,这里选择了v4版本。 并且引用了ant-design-vue作为ui库

yarn add vue-router@4 -D
yarn add ant-design-vue@next -D

src目录下面增加一下文件夹

- router // 用于路由配置
- page  // 用于编写预览页面

在page页面添加一个HelloPage

import { defineComponent } from 'vue';
import { Hello } from 'mis-design';

const HelloPage = defineComponent({
  setup() {
    return () => (<Hello title="123"></Hello>);
  },
});

export default HelloPage;

配置路由

import { createRouter, createWebHistory } from 'vue-router';

import Hello from '../page/Hello'

const routes = [{
    path: '/',
    component: Hello
}]

const router = createRouter({
    history:createWebHistory(),
    routes
})

export default  router;

修改main.ts

import { createApp } from 'vue'
import App from './App.vue'
import MyUI from '../packages/components'
import Routes from './router'
import 'ant-design-vue/dist/antd.css'

createApp(App).use(Routes).use(MyUI).mount('#app')

修改一下app.vue,更改页面布局,增加菜单栏等。 首先在page文件夹中新建一个Menus.tsx

import { defineComponent, watch, reactive } from 'vue';
import { Menu } from 'ant-design-vue';
import { RouterLink, useRoute } from 'vue-router';

interface IMenuItem {
  name: string;
  zh?: string;
  path: string;
}

const menuMap: IMenuItem[] = [
  {
    name: 'Hello',
    path: '/',
    zh: '欢迎页',
  },
];
const menus = defineComponent({
  setup() {
    const route = useRoute();
    const state = reactive({
      currentKey: [] as string[],
    });
    watch(route, (value) => {
      const keys = value.path;
      state.currentKey = [keys];
      console.log(state.currentKey);
    });
    return () => (
      <Menu mode="inline" selectedKeys={state.currentKey}>
        {menuMap.map((item) => (
          <Menu.Item key={item.path}>
            <RouterLink to={item.path}>
              {item.name}
              &nbsp;{item.zh}
            </RouterLink>
          </Menu.Item>
        ))}
      </Menu>
    );
  },
});

export default menus;

app.vue

<script setup lang="ts">
import { Layout } from 'ant-design-vue'
import Menus from './page/Menus'
import { RouterView } from 'vue-router'
const { Header, Sider, Content } = Layout;
import './style/index.css'
// import { Button } from './components/index'
// This starter template is using Vue 3 <script setup> SFCs
// Check out https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup
</script>

<template>
  <Layout style="height:100%">
    <Header style="text-align:left;">
      <h1 style="color:#fff;display: flex;align-items: center;">
        MY-UI
      </h1>
    </Header>
    <Layout>
      <Sider>
        <Menus />
      </Sider>
      <Content>
        <RouterView />
      </Content>
    </Layout>
  </Layout>
</template>

2.组件预览+说明文档md

上面的HelloPage现在我们可以预览到Hello组件的展示效果,但是这才是最基础的,接下来我们要编写组件说明文档

// packages/components/Hello/readme.md
# Hello

# 配置项

| 参数  | 说明 | 类型   | 默认值 | 版本 |
| ----- | ---- | ------ | ------ | ---- |
| title | ---  | string | -      | -    |

接下来让md在页面展示,这里有一个很好用的库vite-plugin-md,更改vite.config.ts

import Markdown from 'vite-plugin-md'
export default defineConfig({
  plugins: [
    vue({ include: [/\.vue$/, /\.md$/] }),
    vueJsx(),
    Markdown()
  ],
}

我们在封装一个Preview.tsx用于显示我们的组件+源码+md 为了源码的高亮,我们需要prismjs

yarn add prismjs -D
// Preview.tsx
import { defineComponent, onMounted } from 'vue';
import { Collapse } from 'ant-design-vue';
import Prism from 'prismjs';
import 'prismjs/themes/prism-coy.css';

const Preview = defineComponent({
  props: ['sourceCode', 'language', 'md'],
  setup(props, { slots }) {
    onMounted(() => {
      Prism.highlightAll();
    });

    return () => (
      <div>
        <Collapse>
          <Collapse.Panel
            style={{
              textAlign: 'left',
            }}
            header={
              <div
                style={{
                  background: '#fff',
                  padding: '16px',
                }}
                onClick={(e) => e.stopPropagation()}
              >
                {slots.default && slots.default()}
              </div>
            }
          >
            <pre class="language-html">
              <code class={props.language || 'language-javascript'}>
                {props.sourceCode}
              </code>
            </pre>
          </Collapse.Panel>
        </Collapse>

        {props.md}
      </div>
    );
  },
});

export default Preview;

最后,我们修改一下原来的Page/Hello.tsx

import { defineComponent } from 'vue';
import { Hello } from '../../packages/components';
import MD from '../../packages/components/Hello/readme.md';

import Preview from './Preview';

const HelloPage = defineComponent({
  setup() {
    return () => (
      <div>
        
            <Preview sourceCode={`<Hello title="123"></Hello>`} md={<MD />}>
              <Hello title="123"></Hello>
            </Preview>

      </div>
    );
  },
});

export default HelloPage;

Hello.tsx引用Hello组件的路径有点难看,我们把他改成

import { Hello } from 'my-ui';
import MD from 'my-ui/Hello/readme.md';

这里需要给vite.config.ts配置resolve.alias,并且对应修改tsconfig.json增加paths

// vite.config.ts
resolve: {
    alias: {
      'my-ui': '/packages/components'
    }
  }
{
  "compilerOptions": {
    "baseUrl": "./",
    "paths": {
      "my-ui": ["packages/components"],
      "my-ui/*": ["packages/components/*"]
    },
  }
 }

最后优化一下markdown的展示效果,增加一个样式文件style/index.css

.markdown-body {
  padding: 16px;
}
.markdown-body h1 {
  text-align: left;
}
.markdown-body table {
    width: 100%;
    min-width: 720px;
    margin: 2em 0;
    font-size: 13px;
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier,
      monospace;
    line-height: 1.5;
    border: 1px solid #e8e8e8;
  }
  .markdown-body table th,
  .markdown-body table td {
    padding: 12px;
    border-color: #e8e8e8;
    border-width: 1px 0;
  }
  .markdown-body table th {
    padding-top: 14px;
    border-width: 0 0 2px 0;
    background-color: #e8e8e8;
  }
  .markdown-body table tbody tr {
    -webkit-transition: all 0.3s;
    transition: all 0.3s;
  }
  .markdown-body table tbody tr:hover {
    background: rgba(60, 90, 100, 0.04);
  }
  .markdown-body table td:first-child {
    width: 20%;
    color: #595959;
    font-weight: 600;
  }
  .markdown-body table td:nth-child(3) {
    width: 22%;
    color: #c41d7f;
    font-size: 13px;
    word-break: break-all;
  }
  .markdown-body table td:nth-child(4) {
    width: 16%;
    font-size: 13px;
  }
  .markdown-body hr {
    margin: 12px 0;
  }
  

最终效果达成!

可能相对来说不太好看,关于样式和预览页面可以自己优化调整 image.png

后续

关于组件库后面还有一些东西可以做,这里先记录一下,后续更新再发~

  • 国际化
  • 组件创建脚手架
  • 实现组件的实时修改预览等