专业的编程技术博客社区

网站首页 > 博客文章 正文

Vue3.3 + TS4 ,自主打造媲美 ElementPlus 的组件库(超清完结)

baijin 2025-01-04 16:57:44 博客文章 15 ℃ 0 评论

xia仔ke:quangneng.com/3674/

使用 Vue 3.3 和 TypeScript 4 自主打造媲美 ElementPlus 的组件库

在现代前端开发中,组件库是构建高效、可维护应用的关键工具。ElementPlus 是一个流行的 Vue 3 组件库,但如果你想定制自己的 UI 组件库来满足特定需求,或者希望提升对组件库内部工作原理的理解,可以尝试自主打造一个。本文将带你通过使用 Vue 3.3 和 TypeScript 4 创建一个高质量的组件库。

1. 项目概述

我们将创建一个组件库,包含以下功能:

  • 支持 Vue 3 的新特性,如 Composition API 和 Teleport。
  • 使用 TypeScript 提供类型安全和开发支持。
  • 提供基本的 UI 组件,例如 Button、Input 和 Modal。

2. 项目设置

2.1 初始化项目

首先,我们需要初始化一个新的 Vue 3 项目,并安装相关依赖:

bashmkdir my-component-library
cd my-component-library
npm init -y
npm install vue@next typescript ts-node @types/node @vue/compiler-sfc --save
npm install --save-dev vite @vitejs/plugin-vue @types/vite

创建 TypeScript 配置文件 tsconfig.json:

json{
  "compilerOptions": {
    "target": "es6",
    "module": "esnext",
    "moduleResolution": "node",
    "strict": true,
    "jsx": "preserve",
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "baseUrl": "./src",
    "paths": {
      "@/*": ["*"]
    }
  },
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
  "exclude": ["node_modules"]
}

2.2 配置 Vite

在项目根目录创建 vite.config.ts 文件:

typescriptimport { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';

export default defineConfig({
  plugins: [vue()],
  build: {
    lib: {
      entry: 'src/index.ts',
      name: 'MyComponentLibrary',
      fileName: (format) => `my-component-library.${format}.js`,
    },
    rollupOptions: {
      external: ['vue'],
      output: {
        globals: {
          vue: 'Vue',
        },
      },
    },
  },
});

3. 开发组件库

3.1 组织目录结构

项目目录结构如下:

my-component-library/
├── src/
│   ├── components/
│   │   ├── Button.vue
│   │   ├── Input.vue
│   │   ├── Modal.vue
│   ├── index.ts
├── package.json
├── tsconfig.json
├── vite.config.ts

3.2 编写组件

Button 组件

src/components/Button.vue:

<template>
  <button :class="['btn', typeClass]" :disabled="disabled">
    <slot></slot>
  </button>
</template>

<script lang="ts" setup>
import { defineProps } from 'vue';

const props = defineProps<{
  type?: 'primary' | 'secondary';
  disabled?: boolean;
}>();

const typeClass = computed(() => {
  return props.type === 'primary' ? 'btn-primary' : 'btn-secondary';
});
</script>

<style scoped>
.btn {
  padding: 8px 16px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}
.btn-primary {
  background-color: #007bff;
  color: white;
}
.btn-secondary {
  background-color: #6c757d;
  color: white;
}
</style>

Input 组件

src/components/Input.vue:

<template>
  <input :class="['input', sizeClass]" :type="type" :placeholder="placeholder" />
</template>

<script lang="ts" setup>
import { defineProps } from 'vue';

const props = defineProps<{
  type?: 'text' | 'password';
  placeholder?: string;
  size?: 'small' | 'medium' | 'large';
}>();

const sizeClass = computed(() => {
  return props.size === 'large' ? 'input-large' : props.size === 'small' ? 'input-small' : '';
});
</script>

<style scoped>
.input {
  padding: 8px;
  border: 1px solid #ced4da;
  border-radius: 4px;
}
.input-large {
  font-size: 1.25rem;
}
.input-small {
  font-size: 0.875rem;
}
</style>

Modal 组件

src/components/Modal.vue:

<template>
  <div v-if="visible" class="modal-overlay">
    <div class="modal-content">
      <button class="close" @click="close">X</button>
      <slot></slot>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { defineProps, defineEmits } from 'vue';

const props = defineProps<{
  visible: boolean;
}>();

const emit = defineEmits<{ (event: 'update:visible', value: boolean): void }>();

const close = () => {
  emit('update:visible', false);
};
</script>

<style scoped>
.modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;
}
.modal-content {
  background: white;
  padding: 16px;
  border-radius: 4px;
  position: relative;
}
.close {
  position: absolute;
  top: 8px;
  right: 8px;
  border: none;
  background: transparent;
  cursor: pointer;
}
</style>

3.3 导出组件

在 src/index.ts 中导出组件:

typescriptimport Button from './components/Button.vue';
import Input from './components/Input.vue';
import Modal from './components/Modal.vue';

export { Button, Input, Modal };

4. 组件库测试

4.1 本地测试

在本地进行组件测试,你可以使用 Vite 的开发服务器:

bashnpm run dev

4.2 发布到 npm

在发布之前,确保在 package.json 中配置了合适的入口文件和包名:

json{
  "name": "my-component-library",
  "version": "1.0.0",
  "main": "dist/my-component-library.umd.js",
  "module": "dist/my-component-library.es.js",
  "types": "dist/my-component-library.d.ts",
  "files": [
    "dist"
  ],
  "scripts": {
    "build": "vite build"
  }
}

然后构建项目并发布到 npm:

bashnpm run build
npm publish

5. 使用组件库

在 Vue 3 项目中安装并使用组件库:

bashnpm install my-component-library

在项目中导入并使用组件:

typescriptimport { createApp } from 'vue';
import App from './App.vue';
import { Button, Input, Modal } from 'my-component-library';

const app = createApp(App);
app.component('Button', Button);
app.component('Input', Input);
app.component('Modal', Modal);
app.mount('#app');

示例组件使用

<template>
  <div>
    <Button type="primary">Primary Button</Button>
    <Input size="large" placeholder="Enter text" />
    <Modal :visible="modalVisible" @update:visible="modalVisible = $event">
      <p>This is a modal</p>
    </Modal>
  </div>
</template>

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

const modalVisible = ref(false);
</script>

6. 总结

通过本文,你已经学会了如何使用 Vue 3.3 和 TypeScript 4 自主打造一个媲美 ElementPlus 的高质量组件库。我们从初始化项目、开发组件到发布和使用,详细介绍了整个过程。这个组件库的创建不仅能提升你的前端开发技能,也能帮助你更好地理解 Vue 和 TypeScript 的应用。希望这能为你的前端开发之旅提供有力的支持。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表