├── .vscode
└── extensions.json
├── public
└── favicon.ico
├── src
├── assets
│ └── logo.png
├── components
│ ├── base
│ │ ├── menu
│ │ │ ├── src
│ │ │ │ ├── menu.scss
│ │ │ │ ├── types.ts
│ │ │ │ ├── index.vue
│ │ │ │ └── menu.tsx
│ │ │ └── index.ts
│ │ ├── table
│ │ │ ├── README.md
│ │ │ ├── index.ts
│ │ │ └── src
│ │ │ │ ├── types.ts
│ │ │ │ └── index.vue
│ │ ├── list
│ │ │ ├── index.ts
│ │ │ └── src
│ │ │ │ ├── types.ts
│ │ │ │ └── index.vue
│ │ ├── form
│ │ │ ├── index.ts
│ │ │ ├── README.md
│ │ │ └── src
│ │ │ │ ├── types
│ │ │ │ ├── types.ts
│ │ │ │ └── rules.ts
│ │ │ │ └── index.vue
│ │ ├── trend
│ │ │ ├── index.ts
│ │ │ └── src
│ │ │ │ └── index.vue
│ │ ├── progress
│ │ │ ├── index.ts
│ │ │ └── src
│ │ │ │ └── index.vue
│ │ ├── calendar
│ │ │ ├── index.ts
│ │ │ └── src
│ │ │ │ ├── types.ts
│ │ │ │ └── index.vue
│ │ ├── modelForm
│ │ │ ├── index.ts
│ │ │ └── src
│ │ │ │ └── index.vue
│ │ ├── chooseArea
│ │ │ ├── index.ts
│ │ │ └── src
│ │ │ │ └── index.vue
│ │ ├── chooseCity
│ │ │ ├── index.ts
│ │ │ ├── src
│ │ │ │ ├── types.ts
│ │ │ │ └── index.vue
│ │ │ └── lib
│ │ │ │ └── province.json
│ │ ├── chooseDate
│ │ │ ├── index.ts
│ │ │ └── src
│ │ │ │ └── index.vue
│ │ ├── chooseIcon
│ │ │ ├── index.ts
│ │ │ └── src
│ │ │ │ └── index.vue
│ │ ├── chooseTime
│ │ │ ├── index.ts
│ │ │ └── src
│ │ │ │ └── index.vue
│ │ ├── notification
│ │ │ ├── index.ts
│ │ │ └── src
│ │ │ │ └── index.vue
│ │ ├── chooseAreaFour
│ │ │ ├── index.ts
│ │ │ └── src
│ │ │ │ └── index.vue
│ │ └── index.ts
│ └── layout
│ │ ├── navHeader.vue
│ │ ├── index.vue
│ │ └── sideBar.vue
├── views
│ ├── Setting.vue
│ ├── chooseCity
│ │ └── index.vue
│ ├── trend
│ │ └── index.vue
│ ├── Home.vue
│ ├── About.vue
│ ├── chooseTime
│ │ └── index.vue
│ ├── notification
│ │ ├── index.vue
│ │ └── data.ts
│ ├── progress
│ │ └── index.vue
│ ├── calendar
│ │ └── index.vue
│ ├── menu
│ │ └── index.vue
│ ├── table
│ │ └── index.vue
│ ├── modelForm
│ │ └── index.vue
│ └── form
│ │ └── index.vue
├── App.vue
├── env.d.ts
├── main.ts
├── mock
│ └── index.ts
└── router
│ └── index.ts
├── packages
├── menu
│ ├── src
│ │ ├── menu.scss
│ │ ├── types.ts
│ │ ├── index.vue
│ │ └── menu.tsx
│ └── index.ts
├── table
│ ├── README.md
│ ├── index.ts
│ └── src
│ │ ├── types.ts
│ │ └── index.vue
├── list
│ ├── index.ts
│ └── src
│ │ ├── types.ts
│ │ └── index.vue
├── form
│ ├── index.ts
│ ├── README.md
│ └── src
│ │ ├── types
│ │ ├── types.ts
│ │ └── rules.ts
│ │ └── index.vue
├── trend
│ ├── index.ts
│ └── src
│ │ └── index.vue
├── progress
│ ├── index.ts
│ └── src
│ │ └── index.vue
├── calendar
│ ├── index.ts
│ └── src
│ │ ├── types.ts
│ │ └── index.vue
├── modelForm
│ ├── index.ts
│ └── src
│ │ └── index.vue
├── chooseArea
│ ├── index.ts
│ └── src
│ │ └── index.vue
├── chooseCity
│ ├── index.ts
│ ├── src
│ │ ├── types.ts
│ │ └── index.vue
│ └── lib
│ │ └── province.json
├── chooseDate
│ ├── index.ts
│ └── src
│ │ └── index.vue
├── chooseIcon
│ ├── index.ts
│ └── src
│ │ └── index.vue
├── chooseTime
│ ├── index.ts
│ └── src
│ │ └── index.vue
├── notification
│ ├── index.ts
│ └── src
│ │ └── index.vue
├── chooseAreaFour
│ ├── index.ts
│ └── src
│ │ └── index.vue
├── vue.d.ts
└── index.ts
├── tsconfig.node.json
├── vite.config.ts
├── .gitignore
├── index.html
├── tsconfig.json
├── package.json
├── command
└── build.js
└── README.md
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": ["johnsoncodehk.volar"]
3 | }
4 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jlnvv-tom/Secondary-development-component/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jlnvv-tom/Secondary-development-component/HEAD/src/assets/logo.png
--------------------------------------------------------------------------------
/packages/menu/src/menu.scss:
--------------------------------------------------------------------------------
1 | .menu-icon-svg {
2 | svg {
3 | margin-right: 4px;
4 | width: 1em;
5 | height: 1em;
6 | }
7 | }
--------------------------------------------------------------------------------
/src/components/base/menu/src/menu.scss:
--------------------------------------------------------------------------------
1 | .menu-icon-svg {
2 | svg {
3 | margin-right: 4px;
4 | width: 1em;
5 | height: 1em;
6 | }
7 | }
--------------------------------------------------------------------------------
/packages/table/README.md:
--------------------------------------------------------------------------------
1 | ## 功能
2 | 1. 可配置型, 可维护
3 | 2. 具备`element-plus` 原有表格的所有功能
4 | 3. 可以自行拓展更多的功能
5 |
6 | ## 目的
7 | 1. 简单好用
8 | 2. 拓展性强
9 | 3. 可维护性强
--------------------------------------------------------------------------------
/src/components/base/table/README.md:
--------------------------------------------------------------------------------
1 | ## 功能
2 | 1. 可配置型, 可维护
3 | 2. 具备`element-plus` 原有表格的所有功能
4 | 3. 可以自行拓展更多的功能
5 |
6 | ## 目的
7 | 1. 简单好用
8 | 2. 拓展性强
9 | 3. 可维护性强
--------------------------------------------------------------------------------
/packages/list/index.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 | import list from './src/index.vue';
3 | export default {
4 | install(app: App) {
5 | app.component('w-list',list)
6 | }
7 | }
--------------------------------------------------------------------------------
/packages/form/index.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 | import wForm from './src/index.vue';
3 | export default {
4 | install(app: App) {
5 | app.component('w-form',wForm)
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/trend/index.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 | import trend from './src/index.vue';
3 | export default {
4 | install(app: App) {
5 | app.component('w-trend',trend)
6 | }
7 | }
--------------------------------------------------------------------------------
/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "module": "esnext",
5 | "moduleResolution": "node"
6 | },
7 | "include": ["vite.config.ts"]
8 | }
9 |
--------------------------------------------------------------------------------
/packages/menu/src/types.ts:
--------------------------------------------------------------------------------
1 | export interface MenuItem {
2 | icon?: string; // 图标
3 | i?: any; //
4 | name: string; // 导航名字
5 | index: string; // 标识
6 | children?: MenuItem[]; // 子菜单
7 | }
--------------------------------------------------------------------------------
/packages/table/index.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 | import wTable from './src/index.vue';
3 | export default {
4 | install(app: App) {
5 | app.component('w-table',wTable)
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/base/list/index.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 | import list from './src/index.vue';
3 | export default {
4 | install(app: App) {
5 | app.component('w-list',list)
6 | }
7 | }
--------------------------------------------------------------------------------
/packages/progress/index.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 | import progress from './src/index.vue';
3 | export default {
4 | install(app: App) {
5 | app.component('w-progress',progress)
6 | }
7 | }
--------------------------------------------------------------------------------
/src/components/base/form/index.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 | import wForm from './src/index.vue';
3 | export default {
4 | install(app: App) {
5 | app.component('w-form',wForm)
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/base/trend/index.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 | import trend from './src/index.vue';
3 | export default {
4 | install(app: App) {
5 | app.component('w-trend',trend)
6 | }
7 | }
--------------------------------------------------------------------------------
/packages/calendar/index.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 | import calendar from './src/index.vue'
3 |
4 | export default {
5 | install(app: App) {
6 | app.component('w-calendar', calendar)
7 | }
8 | }
--------------------------------------------------------------------------------
/packages/modelForm/index.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 | import modelForm from './src/index.vue';
3 | export default {
4 | install(app: App) {
5 | app.component('w-model-form',modelForm)
6 | }
7 | }
--------------------------------------------------------------------------------
/src/components/base/menu/src/types.ts:
--------------------------------------------------------------------------------
1 | export interface MenuItem {
2 | icon?: string; // 图标
3 | i?: any; //
4 | name: string; // 导航名字
5 | index: string; // 标识
6 | children?: MenuItem[]; // 子菜单
7 | }
--------------------------------------------------------------------------------
/src/components/base/table/index.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 | import wTable from './src/index.vue';
3 | export default {
4 | install(app: App) {
5 | app.component('w-table',wTable)
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/chooseArea/index.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 | import chooseArea from './src/index.vue';
3 | export default {
4 | install(app: App) {
5 | app.component('w-choose-area',chooseArea)
6 | }
7 | }
--------------------------------------------------------------------------------
/packages/chooseCity/index.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 | import chooseCity from './src/index.vue';
3 | export default {
4 | install(app: App) {
5 | app.component('w-choose-city',chooseCity)
6 | }
7 | }
--------------------------------------------------------------------------------
/packages/chooseDate/index.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 | import chooseDate from './src/index.vue';
3 | export default {
4 | install(app: App) {
5 | app.component('w-choose-date',chooseDate)
6 | }
7 | }
--------------------------------------------------------------------------------
/packages/chooseIcon/index.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 | import chooseIcon from './src/index.vue';
3 | export default {
4 | install(app: App) {
5 | app.component('w-choose-icon',chooseIcon)
6 | }
7 | }
--------------------------------------------------------------------------------
/packages/chooseTime/index.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 | import chooseTime from './src/index.vue';
3 | export default {
4 | install(app: App) {
5 | app.component('w-choose-time',chooseTime)
6 | }
7 | }
--------------------------------------------------------------------------------
/src/components/base/progress/index.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 | import progress from './src/index.vue';
3 | export default {
4 | install(app: App) {
5 | app.component('w-progress',progress)
6 | }
7 | }
--------------------------------------------------------------------------------
/packages/notification/index.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 | import notification from './src/index.vue';
3 | export default {
4 | install(app: App) {
5 | app.component('w-notification',notification)
6 | }
7 | }
--------------------------------------------------------------------------------
/src/components/base/calendar/index.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 | import calendar from './src/index.vue'
3 |
4 | export default {
5 | install(app: App) {
6 | app.component('w-calendar', calendar)
7 | }
8 | }
--------------------------------------------------------------------------------
/src/components/base/modelForm/index.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 | import modelForm from './src/index.vue';
3 | export default {
4 | install(app: App) {
5 | app.component('w-model-form',modelForm)
6 | }
7 | }
--------------------------------------------------------------------------------
/packages/calendar/src/types.ts:
--------------------------------------------------------------------------------
1 | export interface EventItem {
2 | // 事件标题
3 | title: string,
4 | // 开始时间
5 | start: string,
6 | // 结束时间
7 | end: string,
8 | // 是否可拖动编辑
9 | editable?: boolean
10 | }
--------------------------------------------------------------------------------
/src/components/base/chooseArea/index.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 | import chooseArea from './src/index.vue';
3 | export default {
4 | install(app: App) {
5 | app.component('w-choose-area',chooseArea)
6 | }
7 | }
--------------------------------------------------------------------------------
/src/components/base/chooseCity/index.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 | import chooseCity from './src/index.vue';
3 | export default {
4 | install(app: App) {
5 | app.component('w-choose-city',chooseCity)
6 | }
7 | }
--------------------------------------------------------------------------------
/src/components/base/chooseDate/index.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 | import chooseDate from './src/index.vue';
3 | export default {
4 | install(app: App) {
5 | app.component('w-choose-date',chooseDate)
6 | }
7 | }
--------------------------------------------------------------------------------
/src/components/base/chooseIcon/index.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 | import chooseIcon from './src/index.vue';
3 | export default {
4 | install(app: App) {
5 | app.component('w-choose-icon',chooseIcon)
6 | }
7 | }
--------------------------------------------------------------------------------
/src/components/base/chooseTime/index.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 | import chooseTime from './src/index.vue';
3 | export default {
4 | install(app: App) {
5 | app.component('w-choose-time',chooseTime)
6 | }
7 | }
--------------------------------------------------------------------------------
/src/components/base/notification/index.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 | import notification from './src/index.vue';
3 | export default {
4 | install(app: App) {
5 | app.component('w-notification',notification)
6 | }
7 | }
--------------------------------------------------------------------------------
/src/components/base/calendar/src/types.ts:
--------------------------------------------------------------------------------
1 | export interface EventItem {
2 | // 事件标题
3 | title: string,
4 | // 开始时间
5 | start: string,
6 | // 结束时间
7 | end: string,
8 | // 是否可拖动编辑
9 | editable?: boolean
10 | }
--------------------------------------------------------------------------------
/packages/chooseAreaFour/index.ts:
--------------------------------------------------------------------------------
1 | // 四级联动区域选择组件
2 | import { App } from 'vue'
3 | import chooseAreaFour from './src/index.vue';
4 | export default {
5 | install(app: App) {
6 | app.component('w-choose-areafour',chooseAreaFour)
7 | }
8 | }
--------------------------------------------------------------------------------
/src/views/Setting.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | setting
4 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/components/base/chooseAreaFour/index.ts:
--------------------------------------------------------------------------------
1 | // 四级联动区域选择组件
2 | import { App } from 'vue'
3 | import chooseAreaFour from './src/index.vue';
4 | export default {
5 | install(app: App) {
6 | app.component('w-choose-areafour',chooseAreaFour)
7 | }
8 | }
--------------------------------------------------------------------------------
/packages/chooseCity/src/types.ts:
--------------------------------------------------------------------------------
1 | export interface City {
2 | id: number,
3 | // 拼音
4 | spell: string,
5 | // 名字
6 | name: string
7 | }
8 |
9 | export interface Province {
10 | name: string,
11 | data: string[],
12 | id?: string
13 | }
--------------------------------------------------------------------------------
/src/views/chooseCity/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/components/base/chooseCity/src/types.ts:
--------------------------------------------------------------------------------
1 | export interface City {
2 | id: number,
3 | // 拼音
4 | spell: string,
5 | // 名字
6 | name: string
7 | }
8 |
9 | export interface Province {
10 | name: string,
11 | data: string[],
12 | id?: string
13 | }
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
18 |
--------------------------------------------------------------------------------
/packages/menu/index.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 | import menu from './src/index.vue';
3 | import infiniteMenu from './src/menu'
4 | export default {
5 | install(app: App) {
6 | app.component('w-menu',menu)
7 | app.component('w-infinite-menu',infiniteMenu)
8 | }
9 | }
--------------------------------------------------------------------------------
/src/components/base/menu/index.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 | import menu from './src/index.vue';
3 | import infiniteMenu from './src/menu'
4 | export default {
5 | install(app: App) {
6 | app.component('w-menu',menu)
7 | app.component('w-infinite-menu',infiniteMenu)
8 | }
9 | }
--------------------------------------------------------------------------------
/packages/table/src/types.ts:
--------------------------------------------------------------------------------
1 | export interface TableOptions {
2 | label: string, // 表头
3 | prop: string, // 字段名称
4 | width?: string | number, // 列宽
5 | align?: 'left' | 'center' | 'right',
6 | slot?: string, // 自定义列表名称
7 | action?: boolean, // 是否代表操作项
8 | editable?: boolean, // 是否可编辑
9 | }
--------------------------------------------------------------------------------
/src/components/base/table/src/types.ts:
--------------------------------------------------------------------------------
1 | export interface TableOptions {
2 | label: string, // 表头
3 | prop: string, // 字段名称
4 | width?: string | number, // 列宽
5 | align?: 'left' | 'center' | 'right',
6 | slot?: string, // 自定义列表名称
7 | action?: boolean, // 是否代表操作项
8 | editable?: boolean, // 是否可编辑
9 | }
--------------------------------------------------------------------------------
/src/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | declare module '*.vue' {
4 | import type { DefineComponent } from 'vue'
5 | // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
6 | const component: DefineComponent<{}, {}, any>
7 | export default component
8 | }
9 |
--------------------------------------------------------------------------------
/packages/vue.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | declare module '*.vue' {
4 | import type { DefineComponent } from 'vue'
5 | // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
6 | const component: DefineComponent<{}, {}, any>
7 | export default component
8 | }
9 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import vue from '@vitejs/plugin-vue'
3 | import vueJsx from '@vitejs/plugin-vue-jsx'
4 |
5 | // https://vitejs.dev/config/
6 | export default defineConfig({
7 | plugins: [vue(), vueJsx()],
8 | server: {
9 | port: 8080, // 自定义端口号,一般3000以后
10 | open: true, // 是否自动浏览器打开
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | lib
14 | *.local
15 |
16 | # Editor directories and files
17 | .vscode/*
18 | !.vscode/extensions.json
19 | .idea
20 | .DS_Store
21 | *.suo
22 | *.ntvs*
23 | *.njsproj
24 | *.sln
25 | *.sw?
26 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite App
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/views/trend/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 年度销售额度
5 | 月度销售额度
6 |
7 |
8 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/src/views/Home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | home
4 | 选择图标
5 | 粘贴到这里试一下
6 |
7 |
8 |
9 |
14 |
15 |
--------------------------------------------------------------------------------
/packages/form/README.md:
--------------------------------------------------------------------------------
1 | ## 功能
2 | 1. 可配置型的表单,通过json对象的方式自动生成表单
3 | 2. 具备完善的功能, 表单验证, 动态删减表单,集成第三方插件
4 | 3. 用法简单,扩展性好,便于维护
5 | 4. 多场景,如: 弹框嵌套表单
6 |
7 | ## 准备
8 | 1. 分析`element-plus`表单能够用在哪些方面做优化
9 | 2. 完善类型,支持ts
10 | 3. 具备原有的`element-plus`表单功能
11 | 4. 集成第三方插件: markdown编辑器,富文本编辑器等等。
12 |
13 | ## 资料
14 | `element-plus`使用的表单校验插件是async-validator这个库,
15 |
16 | [async-validator地址](https://github.com/yiminghe/async-validator/blob/master/src/interface.ts)
--------------------------------------------------------------------------------
/packages/list/src/types.ts:
--------------------------------------------------------------------------------
1 | export interface ListItem {
2 | avatar?: string;
3 | title?: string;
4 | desc?: string;
5 | time?: string;
6 | tag?: string; // 标签内容
7 | tagType?: "" | "success" | "info" | "warning" | "danger";
8 | }
9 |
10 | // 列表
11 | export interface ListOptions {
12 | title: string;
13 | content: ListItem[];
14 | }
15 |
16 | // 操作选项
17 | export interface ActionOptions {
18 | text: string;
19 | icon?: string;
20 | }
21 |
--------------------------------------------------------------------------------
/src/components/base/form/README.md:
--------------------------------------------------------------------------------
1 | ## 功能
2 | 1. 可配置型的表单,通过json对象的方式自动生成表单
3 | 2. 具备完善的功能, 表单验证, 动态删减表单,集成第三方插件
4 | 3. 用法简单,扩展性好,便于维护
5 | 4. 多场景,如: 弹框嵌套表单
6 |
7 | ## 准备
8 | 1. 分析`element-plus`表单能够用在哪些方面做优化
9 | 2. 完善类型,支持ts
10 | 3. 具备原有的`element-plus`表单功能
11 | 4. 集成第三方插件: markdown编辑器,富文本编辑器等等。
12 |
13 | ## 资料
14 | `element-plus`使用的表单校验插件是async-validator这个库,
15 |
16 | [async-validator地址](https://github.com/yiminghe/async-validator/blob/master/src/interface.ts)
--------------------------------------------------------------------------------
/src/components/base/list/src/types.ts:
--------------------------------------------------------------------------------
1 | export interface ListItem {
2 | avatar?: string;
3 | title?: string;
4 | desc?: string;
5 | time?: string;
6 | tag?: string; // 标签内容
7 | tagType?: "" | "success" | "info" | "warning" | "danger";
8 | }
9 |
10 | // 列表
11 | export interface ListOptions {
12 | title: string;
13 | content: ListItem[];
14 | }
15 |
16 | // 操作选项
17 | export interface ActionOptions {
18 | text: string;
19 | icon?: string;
20 | }
21 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "useDefineForClassFields": true,
5 | "module": "esnext",
6 | "moduleResolution": "node",
7 | "strict": true,
8 | "jsx": "preserve",
9 | "sourceMap": true,
10 | "resolveJsonModule": true,
11 | "isolatedModules": false,
12 | "esModuleInterop": true,
13 | "lib": ["esnext", "dom"],
14 | "skipLibCheck": true
15 | },
16 | "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
17 | "references": [{ "path": "./tsconfig.node.json" }]
18 | }
19 |
--------------------------------------------------------------------------------
/src/views/About.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 三级选择
5 |
6 |
7 |
8 |
9 | 四级选择
10 |
11 |
12 |
13 |
14 |
15 |
26 |
27 |
--------------------------------------------------------------------------------
/src/components/layout/navHeader.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
22 |
23 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import App from './App.vue'
3 | import router from './router/index'
4 | import ElementPlus from 'element-plus'
5 | import 'element-plus/dist/index.css'
6 | import * as Icons from '@element-plus/icons-vue'
7 | // import WComponents from './components/base';
8 |
9 | import WComponents from '../lib/wjh-element-component.es.js';
10 | import '../lib/style.css'
11 |
12 | // 单组件引入
13 | // import chooseIcon from '../lib/chooseIcon/index.es'
14 | // import '../lib/chooseIcon/style.css';
15 |
16 | import './mock'
17 |
18 | const app = createApp(App)
19 |
20 | // 遍历注册全局icon
21 | for(let icon in Icons) {
22 | app.component(icon, (Icons as any)[icon])
23 | }
24 |
25 | app.use(router).use(ElementPlus).use(WComponents)
26 | app.mount('#app')
27 |
--------------------------------------------------------------------------------
/src/components/layout/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
25 |
26 |
34 |
--------------------------------------------------------------------------------
/src/views/chooseTime/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/packages/notification/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/src/views/notification/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
12 |
13 |
19 |
20 |
21 |
22 |
23 |
24 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/src/views/progress/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
20 |
21 |
22 |
23 |
24 |
25 |
29 |
30 |
--------------------------------------------------------------------------------
/src/components/base/notification/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/packages/progress/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/components/base/progress/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/packages/index.ts:
--------------------------------------------------------------------------------
1 | import {App} from 'vue'
2 | import chooseIcon from './chooseIcon'
3 | import chooseArea from './chooseArea'
4 | import chooseAreaFour from './chooseAreaFour'
5 | import wForm from './form'
6 | import modelForm from './modelForm';
7 | import wTable from './table';
8 | import wTrend from './trend';
9 | import wNotification from './notification';
10 | import wList from './list';
11 | import wMenu from './menu';
12 | import wProgress from './progress';
13 | import chooseTime from './chooseTime'
14 | import chooseDate from './chooseDate'
15 | import chooseCity from './chooseCity'
16 | import calendar from './calendar'
17 |
18 | const components =[
19 | chooseIcon,
20 | chooseArea,
21 | chooseAreaFour,
22 | chooseTime,
23 | chooseDate,
24 | chooseCity,
25 | wForm,
26 | modelForm,
27 | wTable,
28 | wTrend,
29 | wNotification,
30 | wList,
31 | wMenu,
32 | wProgress,
33 | calendar
34 | ]
35 |
36 | export default {
37 | install(app: App) {
38 | components.map(item => {
39 | app.use(item)
40 | })
41 | }
42 | }
--------------------------------------------------------------------------------
/src/components/base/index.ts:
--------------------------------------------------------------------------------
1 | import {App} from 'vue'
2 | import chooseIcon from './chooseIcon'
3 | import chooseArea from './chooseArea'
4 | import chooseAreaFour from './chooseAreaFour'
5 | import wForm from './form'
6 | import modelForm from './modelForm';
7 | import wTable from './table';
8 | import wTrend from './trend';
9 | import wNotification from './notification';
10 | import wList from './list';
11 | import wMenu from './menu';
12 | import wProgress from './progress';
13 | import chooseTime from './chooseTime'
14 | import chooseDate from './chooseDate'
15 | import chooseCity from './chooseCity'
16 | import calendar from './calendar'
17 |
18 | const components =[
19 | chooseIcon,
20 | chooseArea,
21 | chooseAreaFour,
22 | chooseTime,
23 | chooseDate,
24 | chooseCity,
25 | wForm,
26 | modelForm,
27 | wTable,
28 | wTrend,
29 | wNotification,
30 | wList,
31 | wMenu,
32 | wProgress,
33 | calendar
34 | ]
35 |
36 | export default {
37 | install(app: App) {
38 | components.map(item => {
39 | app.use(item)
40 | })
41 | }
42 | }
--------------------------------------------------------------------------------
/src/mock/index.ts:
--------------------------------------------------------------------------------
1 | //mock.js 文件
2 | import Mock from 'mockjs' // 引入mockjs
3 | const Random = Mock.Random // Mock.Random 是一个工具类,用于生成各种随机数据
4 |
5 | interface DataList {
6 | date: string,
7 | name: string,
8 | address: string
9 | }
10 |
11 | const dataList: DataList[] = [] // 用于接受生成数据的数组
12 | for (let i = 0; i < 100; i++) { // 可自定义生成的个数
13 | const template = {
14 | date: Random.date(), // 生成一个随机日期,可加参数定义日期格式
15 | name: Random.name(), // 生成姓名
16 | address: Random.province() // 生成地址
17 | }
18 | dataList.push(template)
19 | }
20 | // list 分页接口()
21 |
22 | Mock.mock('/api/list', 'post', (params: any) => {
23 | let info = JSON.parse(params.body)
24 | let [index, size, total] = [info.current, info.pageSize, dataList.length]
25 | let len = total / size
26 | let totalPages = len - parseInt(String(len)) > 0 ? parseInt(String(len)) + 1 : len
27 | let newDataList = dataList.slice(index * size, (index + 1) * size)
28 | return {
29 | 'code': '200',
30 | 'message': '获取成功',
31 | 'data': {
32 | 'current': index,
33 | 'pageSize': size,
34 | 'rows': newDataList,
35 | 'total': total,
36 | 'totalPages': totalPages
37 | }
38 | }
39 | })
40 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "wjh-components",
3 | "private": true,
4 | "version": "0.0.0",
5 | "scripts": {
6 | "dev": "vite",
7 | "build": "vue-tsc --noEmit && vite build",
8 | "preview": "vite preview",
9 | "build:components": "node ./command/build.js",
10 | "lib": "npm run build:components",
11 | "lib2": "npm run build:components && copy package.json"
12 | },
13 | "dependencies": {
14 | "@element-plus/icons-vue": "^1.1.4",
15 | "@fullcalendar/core": "^5.11.0",
16 | "@fullcalendar/daygrid": "^5.11.0",
17 | "@fullcalendar/interaction": "^5.11.0",
18 | "@types/lodash": "^4.14.182",
19 | "@wangeditor/editor": "^5.0.1",
20 | "element-plus": "^2.1.10",
21 | "lodash": "^4.17.21",
22 | "vue": "^3.2.25",
23 | "vue-router": "^4.0.14"
24 | },
25 | "devDependencies": {
26 | "@types/mockjs": "^1.0.6",
27 | "@vitejs/plugin-vue": "^2.3.1",
28 | "@vitejs/plugin-vue-jsx": "^1.3.10",
29 | "axios": "^0.27.2",
30 | "fs-extra": "^10.1.0",
31 | "mockjs": "^1.1.0",
32 | "sass": "^1.50.1",
33 | "sass-loader": "^12.6.0",
34 | "typescript": "^4.5.4",
35 | "vite": "^2.9.5",
36 | "vue-tsc": "^0.34.7"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/packages/menu/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
32 |
33 |
34 |
55 |
56 |
62 |
--------------------------------------------------------------------------------
/src/views/calendar/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/src/components/base/menu/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
32 |
33 |
34 |
55 |
56 |
62 |
--------------------------------------------------------------------------------
/packages/trend/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
71 |
72 |
83 |
--------------------------------------------------------------------------------
/src/components/base/trend/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
71 |
72 |
83 |
--------------------------------------------------------------------------------
/packages/modelForm/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
87 |
88 |
--------------------------------------------------------------------------------
/src/components/base/modelForm/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
87 |
88 |
--------------------------------------------------------------------------------
/src/views/menu/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
14 |
15 |
16 |
87 |
88 |
94 |
--------------------------------------------------------------------------------
/packages/chooseDate/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
19 |
20 |
21 |
22 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/src/views/notification/data.ts:
--------------------------------------------------------------------------------
1 | export const list = [
2 | {
3 | title: '通知',
4 | content: [
5 | {
6 | title: '蒂姆·库克回复了你的邮件',
7 | time: '2019-05-08 14:33:18',
8 | avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png'
9 | },
10 | {
11 | title: '乔纳森·伊夫邀请你参加会议',
12 | time: '2019-05-08 14:33:18',
13 | avatar: 'https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png'
14 | },
15 | {
16 | title: '斯蒂夫·沃兹尼亚克已批准了你的休假申请',
17 | time: '2019-05-08 14:33:18',
18 | avatar: 'https://gw.alipayobjects.com/zos/rmsportal/kISTdvpyTAhtGxpovNWd.png'
19 | }
20 |
21 | ],
22 | },
23 | {
24 | title: '关注',
25 | content: [
26 | {
27 | avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
28 | title: '曲丽丽 评论了你',
29 | desc: '描述信息描述信息描述信息',
30 | time: '3小时前'
31 | },
32 | {
33 | avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
34 | title: '曲丽丽 评论了你',
35 | desc: '描述信息描述信息描述信息',
36 | time: '3小时前'
37 | },
38 | {
39 | avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
40 | title: '曲丽丽 评论了你',
41 | desc: '描述信息描述信息描述信息',
42 | time: '3小时前'
43 | }
44 | ]
45 | },
46 | {
47 | title: '代办',
48 | content: [
49 | {
50 | title: '任务名称',
51 | desc: '任务需要在 2017-01-12 20:00 前启动',
52 | tag: '未开始',
53 | tagType: ''
54 | },
55 | {
56 | title: '第三方紧急代码变更',
57 | desc: '冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务',
58 | tag: '马上到期',
59 | tagType: 'danger'
60 | },
61 | {
62 | title: '信息安全考试',
63 | desc: '指派竹尔于 2017-01-09 前完成更新并发布',
64 | tag: '已耗时8天',
65 | tagType: 'warning'
66 | }
67 | ]
68 | },
69 | ]
70 | export const actions = [
71 | {
72 | text: '清空代办',
73 | icon: 'delete'
74 | },
75 | {
76 | text: '查看更多',
77 | icon: 'edit'
78 | },
79 | ]
--------------------------------------------------------------------------------
/src/components/base/chooseDate/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
19 |
20 |
21 |
22 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/packages/chooseTime/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
21 |
22 |
23 |
24 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/src/components/base/chooseTime/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
21 |
22 |
23 |
24 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/src/router/index.ts:
--------------------------------------------------------------------------------
1 | import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
2 | import Home from "../views/Home.vue";
3 | import Layout from "../components/layout/index.vue";
4 |
5 | const routes: RouteRecordRaw[] = [
6 | {
7 | path: "/",
8 | component: Layout,
9 | children: [
10 | {
11 | path: "/",
12 | component: Home,
13 | },
14 | {
15 | path: '/about',
16 | name: 'About',
17 | component: () => import('../views/About.vue')
18 | },
19 | {
20 | path: '/setting',
21 | name: 'Setting',
22 | component: () => import('../views/Setting.vue')
23 | },
24 | {
25 | path: '/form',
26 | name: 'Form',
27 | component: () => import('../views/form/index.vue')
28 | },
29 | {
30 | path: '/modelForm',
31 | name: 'ModelForm',
32 | component: () => import('../views/modelForm/index.vue')
33 | },
34 | {
35 | path: '/wTable',
36 | name: 'wTable',
37 | component: () => import('../views/table/index.vue')
38 | },
39 | {
40 | path: '/wTrend',
41 | name: 'wTrend',
42 | component: () => import('../views/trend/index.vue')
43 | },
44 | {
45 | path: '/wNotification',
46 | name: 'wNotification',
47 | component: () => import('../views/notification/index.vue')
48 | },
49 | {
50 | path: '/wMenu',
51 | name: 'wMenu',
52 | component: () => import('../views/menu/index.vue')
53 | },
54 | {
55 | path: '/wProgress',
56 | name: 'wProgress',
57 | component: () => import('../views/progress/index.vue')
58 | },
59 | {
60 | path: '/chooseTime',
61 | name: 'chooseTime',
62 | component: () => import('../views/chooseTime/index.vue')
63 | },
64 | {
65 | path: '/chooseCity',
66 | name: 'chooseCity',
67 | component: () => import('../views/chooseCity/index.vue')
68 | },
69 | {
70 | path: '/calendar',
71 | name: 'calendar',
72 | component: () => import('../views/calendar/index.vue')
73 | },
74 | ],
75 | },
76 | ];
77 |
78 | const router = createRouter({
79 | routes,
80 | history: createWebHistory(),
81 | });
82 |
83 | export default router;
84 |
--------------------------------------------------------------------------------
/packages/chooseIcon/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
15 |
16 |
17 |
18 |
{{ item }}
19 |
20 |
21 |
22 |
23 |
24 |
25 |
68 |
69 |
--------------------------------------------------------------------------------
/src/components/base/chooseIcon/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
15 |
16 |
17 |
18 |
{{ item }}
19 |
20 |
21 |
22 |
23 |
24 |
25 |
68 |
69 |
--------------------------------------------------------------------------------
/packages/form/src/types/types.ts:
--------------------------------------------------------------------------------
1 | import { CSSProperties } from 'vue'
2 | import { RuleItem } from './rules'
3 | import { ValidateFieldsError } from 'async-validator'
4 |
5 | interface Callback {
6 | (isValid: boolean, invalidFields?: ValidateFieldsError): void
7 | }
8 |
9 | // 表单每一项的配置选项
10 | export interface FormOptions {
11 | // 表单项显示的元素
12 | type: 'cascader' | 'checkbox' | 'checkbox-group' | 'checkbox-button' | 'color-picker' |
13 | 'date-picker' | 'input' | 'input-number' | 'radio' | 'radio-group' | 'radio-button' | 'rate' |
14 | 'select' | 'option' | 'slider' | 'switch' | 'time-picker' | 'time-select' |
15 | 'transfer' | 'upload' | 'editor',
16 |
17 | value?: any, // 表单项的值
18 | label?: string, // 表单项label
19 | prop?: string, // 表单项的标识
20 | rules?: RuleItem[], // 表单项验证规则
21 | placeholder?: string, // 占位符
22 | // 表单元素特有的属性
23 | attrs?: {
24 | clearable?: boolean,
25 | showPassword?: boolean,
26 | disabled?: boolean,
27 | // CSS 样式属性
28 | style?: CSSProperties,
29 | }
30 | // 表单项的子元素
31 | children?: FormOptions[],
32 | // 处理上传组件的属性和方法
33 | uploadAttrs?: {
34 | action: string,
35 | header?: string,
36 | method?: 'post' | 'put' | 'patch',
37 | multiple?: boolean,
38 | data?: any,
39 | name?: string,
40 | withCreadentials?: boolean,
41 | howFileList?: boolean,
42 | drag?: boolean,
43 | accept?:string,
44 | thumbnailMode?: boolean,
45 | listType?: 'text' | 'picture' | 'picture-card',
46 | autoUpload?: boolean,
47 | limit?:number,
48 | }
49 | }
50 |
51 | export interface ValidateFieldCallback {
52 | (message: string, invalidFields?: ValidateFieldsError): void
53 | }
54 |
55 |
56 | export interface FormInstance {
57 | registerLabelWidth(width: number, oldWidth: number): void,
58 | deregisterLabelWidth(width: number): void,
59 | autoLabelWidth: string | undefined,
60 | emit: (evt: string, ...args: any[]) => void,
61 | labelSuffix: string,
62 | inline?: boolean,
63 | model?: Record,
64 | size?: string,
65 | showMessage?: boolean,
66 | labelPosition?: string,
67 | labelWidth?: string,
68 | rules?: Record,
69 | statusIcon?: boolean,
70 | hideRequiredAsterisk?: boolean,
71 | disabled?: boolean,
72 | validate: (callback?: Callback) => Promise,
73 | resetFields: () => void,
74 | clearValidate: (props?: string | string[]) => void,
75 | validateField: (props: string | string[], cb: ValidateFieldCallback) => void,
76 | }
--------------------------------------------------------------------------------
/src/components/base/form/src/types/types.ts:
--------------------------------------------------------------------------------
1 | import { CSSProperties } from 'vue'
2 | import { RuleItem } from './rules'
3 | import { ValidateFieldsError } from 'async-validator'
4 |
5 | interface Callback {
6 | (isValid: boolean, invalidFields?: ValidateFieldsError): void
7 | }
8 |
9 | // 表单每一项的配置选项
10 | export interface FormOptions {
11 | // 表单项显示的元素
12 | type: 'cascader' | 'checkbox' | 'checkbox-group' | 'checkbox-button' | 'color-picker' |
13 | 'date-picker' | 'input' | 'input-number' | 'radio' | 'radio-group' | 'radio-button' | 'rate' |
14 | 'select' | 'option' | 'slider' | 'switch' | 'time-picker' | 'time-select' |
15 | 'transfer' | 'upload' | 'editor',
16 |
17 | value?: any, // 表单项的值
18 | label?: string, // 表单项label
19 | prop?: string, // 表单项的标识
20 | rules?: RuleItem[], // 表单项验证规则
21 | placeholder?: string, // 占位符
22 | // 表单元素特有的属性
23 | attrs?: {
24 | clearable?: boolean,
25 | showPassword?: boolean,
26 | disabled?: boolean,
27 | // CSS 样式属性
28 | style?: CSSProperties,
29 | }
30 | // 表单项的子元素
31 | children?: FormOptions[],
32 | // 处理上传组件的属性和方法
33 | uploadAttrs?: {
34 | action: string,
35 | header?: string,
36 | method?: 'post' | 'put' | 'patch',
37 | multiple?: boolean,
38 | data?: any,
39 | name?: string,
40 | withCreadentials?: boolean,
41 | howFileList?: boolean,
42 | drag?: boolean,
43 | accept?:string,
44 | thumbnailMode?: boolean,
45 | listType?: 'text' | 'picture' | 'picture-card',
46 | autoUpload?: boolean,
47 | limit?:number,
48 | }
49 | }
50 |
51 | export interface ValidateFieldCallback {
52 | (message: string, invalidFields?: ValidateFieldsError): void
53 | }
54 |
55 |
56 | export interface FormInstance {
57 | registerLabelWidth(width: number, oldWidth: number): void,
58 | deregisterLabelWidth(width: number): void,
59 | autoLabelWidth: string | undefined,
60 | emit: (evt: string, ...args: any[]) => void,
61 | labelSuffix: string,
62 | inline?: boolean,
63 | model?: Record,
64 | size?: string,
65 | showMessage?: boolean,
66 | labelPosition?: string,
67 | labelWidth?: string,
68 | rules?: Record,
69 | statusIcon?: boolean,
70 | hideRequiredAsterisk?: boolean,
71 | disabled?: boolean,
72 | validate: (callback?: Callback) => Promise,
73 | resetFields: () => void,
74 | clearValidate: (props?: string | string[]) => void,
75 | validateField: (props: string | string[], cb: ValidateFieldCallback) => void,
76 | }
--------------------------------------------------------------------------------
/command/build.js:
--------------------------------------------------------------------------------
1 | const { defineConfig, build } = require('vite')
2 | const vue = require('@vitejs/plugin-vue')
3 | const vueJsx = require('@vitejs/plugin-vue-jsx')
4 | const path = require('path')
5 | const fsExtra = require('fs-extra')
6 | const fs = require('fs')
7 |
8 | // 打包入口文件夹
9 | const entryDir = path.resolve(__dirname, '../packages')
10 |
11 | // 出口
12 | const outDir = path.resolve(__dirname, '../lib')
13 |
14 | // vite基础配置
15 | const baseConfig = defineConfig({
16 | configFile: false,
17 | publicDir: false,
18 | plugins: [vue(), vueJsx()]
19 | })
20 |
21 | // rollup 配置
22 | const rollupOptions = {
23 | external: ['vue', 'vue-router'],
24 | output: {
25 | globals: {
26 | vue: 'Vue'
27 | }
28 | }
29 | }
30 |
31 | // 全量打包构建
32 | const buildAll = async () => {
33 | await build({
34 | ...baseConfig,
35 | build: {
36 | rollupOptions,
37 | lib: {
38 | entry: path.resolve(entryDir, 'index.ts'),
39 | name: 'wjh-element-component',
40 | fileName: 'wjh-element-component',
41 | formats: ['es', 'umd']
42 | },
43 | outDir
44 | }
45 | })
46 | }
47 |
48 | // 单组件打包构建
49 | /**
50 | * @param {*} name 组件名称
51 | */
52 | const buildSingle = async (name) => {
53 | await build({
54 | ...baseConfig,
55 | build: {
56 | rollupOptions,
57 | lib: {
58 | entry: path.resolve(entryDir, name),
59 | name: 'index',
60 | fileName: 'index',
61 | formats: ['es', 'umd']
62 | },
63 | outDir: path.resolve(outDir, name)
64 | }
65 | })
66 | }
67 |
68 | // 每个组件生成pagkage.json
69 | const ceratePackageJson = (name) => {
70 | const fileStr = `
71 | {
72 | "name": "${name}",
73 | "main": "index.umd.js",
74 | "module": "index.es.js",
75 | "style": "styles.css"
76 | }
77 | `
78 | // 输出
79 | fsExtra.outputFile(
80 | path.resolve(outDir, `${name}/package.json`),
81 | fileStr,
82 | 'utf-8'
83 | )
84 | }
85 |
86 | // 打包成库
87 | const buildLib = async () => {
88 | await buildAll()
89 |
90 | // 获取组件名称组成的数组
91 | const components = fs.readdirSync(entryDir).filter(name => {
92 | const componentDir = path.resolve(entryDir, name)
93 | const isDir = fs.lstatSync(componentDir).isDirectory()
94 | return isDir && fs.readdirSync(componentDir).includes('index.ts')
95 | })
96 |
97 | // 循环构建组件
98 | for (const name of components) {
99 | await buildSingle(name)
100 | ceratePackageJson(name)
101 | }
102 | }
103 |
104 | buildLib()
--------------------------------------------------------------------------------
/packages/menu/src/menu.tsx:
--------------------------------------------------------------------------------
1 | // tsx jsx 的组件对应递归比较合适
2 | import { defineComponent, PropType, useAttrs } from "vue";
3 | import { MenuItem } from "./types";
4 | import * as Icons from '@element-plus/icons-vue'
5 | import './menu.scss'
6 | export default defineComponent({
7 | props: {
8 | data: {
9 | type: Array as PropType