创建vue3 UI组件库,发布到NPM仓库

前端web开发过程中,往往需要开发UI组件库,今天这篇文章就是分享一下如何开发一个UI组件库,并且发布到npm仓库,并且为UI组件库编写开发文档。

B站视频:

开发vue3 UI组件库,并且发布到NPM,并且编写指导文档_哔哩哔哩_bilibili

一、效果图

查看代码:

二、创建VUE3项目

npm create vite

 三、创建package

在src目录下创建package文件夹,作为组件库的主目录。在package文件夹下创建components文件夹,作为UI组件的主目录。 在components文件夹下创建button文件夹,并在在button文件夹下创建index.ts和index.vue文件,index.vue文件用来编写button组件,index.ts文件用来导出button组件,方便将来按需引入组件,以下是各文件分别的内容。

package/components/index.vue

<template>
  <button class="dd-button" :class="`dd-button-${size} dd-button-${type} `">
    <slot></slot>
  </button>
</template>
<script lang="ts">
import { defineComponent } from "vue";

export default defineComponent({
  name: "dd-button",
  props: {
    size: {
      type: String,
      default: "middle",
    },
    type: {
      type: String,
      default: "normal",
    },
  },
  setup() {},
});
</script>
<style lang="less" scoped>
.dd-button {
  font-size: 14px;
  min-width: 97px;
  padding: 4px;
  box-sizing: border-box;
}
.dd-button-large {
  height: 40px;
}

.dd-button-middle {
  height: 36px;
}

.dd-button-small {
  height: 32px;
}

.dd-button-primary {
  background-color: #4033da;
  color: #ffffff;
  border: 1px solid #4033da;
}

.dd-button-normal {
  background-color: #ffffff;
  color: #333333;
  border: 1px solid #eee9e9;
}

.dd-button-error {
  background-color: #570a20;
  color: #ffffff;
}
</style>

package/components/index.ts

import { App } from 'vue';
import ddButton from './index.vue';
ddButton.install = (app: App) => {
    app.component(ddButton.name, ddButton);
    return app;
}

export default ddButton;

接下来在package下创建一个index.ts文件,用来导出所有的组件。

package/index.ts

import { App } from "vue";
import ddButton from "./components/button";
const components = [ddButton];
const install = (app: App) => {
    for (const item of components){
        app.component(item.name, item);
    }
    return app;
}
export default { install };

然后在package下创建package.json文件,用来编写组件库的配置。

package/package.json

{
    "name": "@wdddev/dd-ui",
    "version": "0.0.1",
    "description": "dd 组件库",
    "author": {
        "name": "wdddev"
    },
    "private": false,
    "publishConfig": {
        "access": "public",
        "registry": "https://registry.npmjs.org/"
    },
    "dependencies": {}
}

到这里基本的组件库就已经写好了,可以发布了。

四、发布到NPM仓库

发布之前需要创建一个npm账号。可以访问npm | Sign Up进行注册。然后打开cmd, 执行npm adduser,然后根据提示登陆用户。登录成功之后,就可以在package目录下执行 npm publish 进行发布。

发布之后就可以执行  npm install @wdddev/dd-ui进行安装,并且在main.ts中引入使用。

五、编写组件文档

编写组件文档,主要做到两个功能,第一个是需要展示demo组件的内容和demo中的编写代码。另外一个就是表格文档。用来展示属性、插槽、方法、事件等。所以需要写两个组件,一个是代码的预览组件,一个是表格文档组件。

document.vue 表格文档组件

<template>
  <h3>{{ title }}</h3>
  <table class="document-table">
    <thead>
      <tr>
        <th v-for="(item, indnx) in tableheaders" :key="indnx">{{ item }}</th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="(itemRow, indexRow) in body" :key="indexRow">
        <td v-for="(itemCol, indexCol) in itemRow" :key="indexCol">
          {{ itemCol }}
        </td>
      </tr>
    </tbody>
  </table>
</template>
<script setup lang="ts">
import { computed } from "vue";

const props = defineProps({
  title: {
    type: String,
    default: "",
  },

  type: {
    type: String,
    default: "prop",
    values: ["prop", "event", "slot", "methods"],
  },

  body: {
    type: Array,
    default: [],
  },

  headers: {
    type: Array,
    default: [],
  },
});
const headerByType: any = {
  prop: ["属性", "说明", "数据类型", "可选值", "默认值"],
  slot: ["插槽名", "说明"],
  event: ["事件名", "说明", "回调参数"],
  methods: ["方法名", "说明", "入参"],
};

const tableheaders = computed(() => {
  if (props.headers.length === 0) {
    const type = props.type as string;
    return headerByType[type];
  }
  return props.headers;
});
</script>

<style lang="less" scoped>
.document-table {
  width: 100%;
  margin: 20px 0;

  th, td {
    padding: 0.5rem 1rem;
    border: 1px solid #777474;
    white-space: normal;
    text-align: left;
  }
}
</style>

priview.vue 用来预览和展示代码的组件

<template>
    <div class="priview-button-contain">
        <dd-button type="error" @click="hideCode" v-if="codeVisibel" >隐藏代码</dd-button>
        <dd-button type="primary" @click="showCode" v-else >查看代码</dd-button>
    </div>

    <div class="priview-component-contain">
        <component :is="component" />
    </div>

    <div v-if="codeVisibel" class="priview-code-contain">
        <pre v-html="codeHtml"></pre>
    </div>
</template>

<script setup lang="ts">
import { computed, onMounted, ref } from 'vue';
import 'prismjs';
import 'prismjs/themes/prism.css';
const Prism = (window as any).Prism;
const props = defineProps({
    component: Object,
    componentName: String,
    demoName: String
})
const codeVisibel = ref(false);
function hideCode() {
    codeVisibel.value = false;
}

function showCode() {
    codeVisibel.value = true;
}

const codeResourc = ref('');
const isDev = import.meta.env.MODE;
const getCode = async () => {
    if (isDev === 'development') {
        codeResourc.value = (await import(/* @vite-ignore */ `../views/document/${props.componentName}/${props.demoName}.vue?raw`)).default;
    } else {
        codeResourc.value = await fetch(`src/views/document/${props.componentName}/${props.demoName}.vue`).then((res) => res.text())
    }
}

onMounted(() => {
    getCode();
})

const codeHtml = computed(() => {
    return Prism.highlight(codeResourc.value, Prism.languages.html, 'html')
})
</script>

<style lang="less" scoped>
.priview-button-contain {
    width: 300px;
    height: 40px;
    margin: 20px 0 ;
}

.priview-component-contain {
    width: 100%;
    border: 1px solid #c3bcbc;
    margin-bottom: 20px;
    padding: 10px;
    box-sizing: border-box;
}

.priview-code-contain {
    width: 100%;
    border: 1px solid #c3bcbc;
    margin-bottom: 20px;
    padding: 10px;
    box-sizing: border-box;
    font-size: 16px;
}
</style>

接下来写一个文档的主页面,分别是左侧菜单和右边的内容区域。在src下创建views文件夹,并且创建doc.vue文件,作为主页面。

src/views/doc.vue

<template>
  <div class="doc-contain">
    <div class="doc-contain-menu">
      <div
        v-for="menu in menuList"
        :key="menu.path"
        @click="changeView(menu.path)"
        class="doc-contain-menu-item"
        :class="{ 'doc-contain-menu-item-active': $route.path == menu.path }"
      >
        {{ menu.title }}
      </div>
    </div>
    <router-view class="doc-contain-content" />
  </div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import MenuList from "./menu";
import { useRouter } from "vue-router";
export default defineComponent({
  setup() {
    return {
      menuList: MenuList,
      router: useRouter(),
    };
  },
  methods: {
    changeView(path: any) {
      this.router.push(path);
    },
  },
});
</script>
<style lang="less" scoped>
.doc-contain {
  width: calc(100vw - 40px);
  height: calc(100vw - 40px);
  display: flex;
  .doc-contain-menu {
    height: 100%;
    width: 220px;
    overflow-y: auto;
    padding: 20px 10px;
    box-sizing: border-box;
    border: 1px solid #e6e0e0;
    .doc-contain-menu-item {
      width: 100%;
      height: 40px;
      padding: 2px 4px;
      box-sizing: border-box;
      border: 1px solid #eae4e4;
      display: flex;
      align-items: center;
    }

    .doc-contain-menu-item-active {
      border: 1px solid #3c09a3;
    }
  }

  .doc-contain-content {
    width: calc(100% - 240px);
    height: 100%;
    overflow-y: auto;
    margin-left: 20px;
  }
}
</style>

接下来在views下创建document文件夹,然后创建button文件夹,作为按钮组件demo的主目录。然后创建index.vue文件和demo.vue文件。index.vue文件用来作为文档的主要页面,demo.vue用来示范如何使用button组件。

src/views/document/index.vue

<template>
  <div class="document-contain">
    <h1>dd-button</h1>
    <h3>按钮</h3>
    <div class="priview-contain">
        <priview :component="buttonPriview" componentName="button" demoName="demo"></priview>
        <document title="属性" type="prop" :body="propBody"></document>
    </div>
  </div>
</template>
<script lang="ts">
import { defineComponent, reactive } from 'vue'
import priview from '../../../components/priview.vue';
import document from '../../../components/document.vue';
import buttonDemo from './demo.vue'
export default defineComponent({
    components: {
        priview,
        document
    },
    setup() {
       return {
        buttonPriview: buttonDemo,
        propBody: reactive([
            ['size', "尺寸", 'String', 'samll large middle', 'middle'],
            ['type', "类型", 'String', 'primary error normal', 'normal'],
        ])
       }
    },
})
</script>

<style lang="less" scoped>
.document-contain {
  width: 100%;
  .priview-contain {
    width: 100%;
  }
}
</style>

src/views/document/demo.vue

<template>
  <div class="btn-demo">
    <dd-button class="button-position" type="primary">主要按钮</dd-button>
    <dd-button class="button-position">普通按钮</dd-button>
    <dd-button class="button-position" type="error">错误类型</dd-button>
  </div>

  <div class="btn-demo">
    <dd-button class="button-position"  size="large">大尺寸</dd-button>
    <dd-button class="button-position"  size="middle">中等尺寸</dd-button>
    <dd-button class="button-position"  size="small">小尺寸</dd-button>
  </div>
</template>
<style lang="less" scoped>
.btn-demo {
  display: flex;
  align-items: center;
  margin-top: 20px;
  .button-position {
    margin-right: 20px;
  }
}
</style>

最后就是配置路由,通过页面跳转就可以了。就可以看到界面内容了。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云梦山老人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值