refactor: Element Plus 样式预构建改回硬编码组件清单,分页默认条数调整为 [10,20,50,100]
This commit is contained in:
@@ -16,49 +16,39 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const props = defineProps({
|
interface Props {
|
||||||
total: {
|
/** 数据总条数 */
|
||||||
type: Number as PropType<number>,
|
total: number;
|
||||||
default: 0,
|
/** 每页条数选项,默认 [10, 20, 50, 100] */
|
||||||
},
|
pageSizes?: number[];
|
||||||
pageSizes: {
|
/** 分页布局,控制显示哪些子组件及其顺序 */
|
||||||
type: Array as PropType<number[]>,
|
layout?: string;
|
||||||
default() {
|
/** 是否为分页按钮添加背景色 */
|
||||||
return [10, 20, 30, 50];
|
background?: boolean;
|
||||||
},
|
/** 是否隐藏整个分页条 */
|
||||||
},
|
hidden?: boolean;
|
||||||
layout: {
|
}
|
||||||
type: String,
|
|
||||||
default: "total, sizes, prev, pager, next, jumper",
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
},
|
total: 0,
|
||||||
background: {
|
pageSizes: () => [10, 20, 50, 100],
|
||||||
type: Boolean,
|
layout: "total, sizes, prev, pager, next, jumper",
|
||||||
default: true,
|
background: true,
|
||||||
},
|
hidden: false,
|
||||||
autoScroll: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
hidden: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(["pagination"]);
|
const emit = defineEmits<{
|
||||||
|
/** 页码或每页条数变化时触发,回调当前页码与每页条数 */
|
||||||
|
pagination: [query: { page: number; limit: number }];
|
||||||
|
}>();
|
||||||
|
|
||||||
const currentPage = defineModel("page", {
|
// 当前页码,双向绑定到父组件的 page
|
||||||
type: Number,
|
const currentPage = defineModel<number>("page", { default: 1 });
|
||||||
required: true,
|
|
||||||
default: 1,
|
|
||||||
});
|
|
||||||
|
|
||||||
const pageSize = defineModel("limit", {
|
// 每页条数,双向绑定到父组件的 limit
|
||||||
type: Number,
|
const pageSize = defineModel<number>("limit", { default: 10 });
|
||||||
required: true,
|
|
||||||
default: 10,
|
|
||||||
});
|
|
||||||
|
|
||||||
|
// 数据总量变化后,若当前页超出最后一页,则回退到最后一页
|
||||||
watch(
|
watch(
|
||||||
() => props.total,
|
() => props.total,
|
||||||
(newVal: number) => {
|
(newVal: number) => {
|
||||||
@@ -70,11 +60,13 @@ watch(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 切换每页条数时回到第一页,并触发分页请求
|
||||||
function handleSizeChange(val: number) {
|
function handleSizeChange(val: number) {
|
||||||
currentPage.value = 1;
|
currentPage.value = 1;
|
||||||
emit("pagination", { page: currentPage.value, limit: val });
|
emit("pagination", { page: currentPage.value, limit: val });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 切换页码时触发分页请求
|
||||||
function handleCurrentChange(val: number) {
|
function handleCurrentChange(val: number) {
|
||||||
emit("pagination", { page: val, limit: pageSize.value });
|
emit("pagination", { page: val, limit: pageSize.value });
|
||||||
}
|
}
|
||||||
|
|||||||
149
vite.config.ts
149
vite.config.ts
@@ -4,14 +4,12 @@ import { type ConfigEnv, type UserConfig, loadEnv, defineConfig } from "vite";
|
|||||||
|
|
||||||
import AutoImport from "unplugin-auto-import/vite";
|
import AutoImport from "unplugin-auto-import/vite";
|
||||||
import Components from "unplugin-vue-components/vite";
|
import Components from "unplugin-vue-components/vite";
|
||||||
import type { ComponentResolverObject } from "unplugin-vue-components";
|
|
||||||
import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
|
import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
|
||||||
|
|
||||||
import { mockDevServerPlugin } from "vite-plugin-mock-dev-server";
|
import { mockDevServerPlugin } from "vite-plugin-mock-dev-server";
|
||||||
|
|
||||||
import UnoCSS from "unocss/vite";
|
import UnoCSS from "unocss/vite";
|
||||||
import { resolve } from "path";
|
import { resolve } from "path";
|
||||||
import fs from "node:fs";
|
|
||||||
import { name, version } from "./package.json" with { type: "json" };
|
import { name, version } from "./package.json" with { type: "json" };
|
||||||
|
|
||||||
// 平台名称、版本信息
|
// 平台名称、版本信息
|
||||||
@@ -24,10 +22,8 @@ const __APP_INFO__ = {
|
|||||||
const pathSrc = resolve(import.meta.dirname, "src");
|
const pathSrc = resolve(import.meta.dirname, "src");
|
||||||
|
|
||||||
// Vite配置 https://cn.vitejs.dev/config
|
// Vite配置 https://cn.vitejs.dev/config
|
||||||
export default defineConfig(async ({ mode }: ConfigEnv): Promise<UserConfig> => {
|
export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
|
||||||
const env = loadEnv(mode, process.cwd());
|
const env = loadEnv(mode, process.cwd());
|
||||||
// 生成 Element Plus 组件样式预构建清单(resolver 驱动)
|
|
||||||
const elementPlusStyleImports = await collectElementPlusStyleImports();
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
resolve: {
|
resolve: {
|
||||||
@@ -117,9 +113,84 @@ export default defineConfig(async ({ mode }: ConfigEnv): Promise<UserConfig> =>
|
|||||||
"element-plus/es",
|
"element-plus/es",
|
||||||
"element-plus/es/locale/lang/en",
|
"element-plus/es/locale/lang/en",
|
||||||
"element-plus/es/locale/lang/zh-cn",
|
"element-plus/es/locale/lang/zh-cn",
|
||||||
// Element Plus 组件样式预构建(resolver 驱动):扫描 src 实际用到的组件/指令,
|
// Element Plus 组件样式预构建:按 src 实际用到的组件清单硬编码,首启即预加载,
|
||||||
// 解析出 base + 组件样式路径,首启即预加载,避免首次使用某组件时重优化导致页面刷新
|
// 避免首次使用某组件时触发依赖重优化导致页面刷新
|
||||||
...elementPlusStyleImports,
|
...[
|
||||||
|
"alert",
|
||||||
|
"avatar",
|
||||||
|
"backtop",
|
||||||
|
"badge",
|
||||||
|
"base",
|
||||||
|
"breadcrumb",
|
||||||
|
"breadcrumb-item",
|
||||||
|
"button",
|
||||||
|
"card",
|
||||||
|
"cascader",
|
||||||
|
"checkbox",
|
||||||
|
"checkbox-group",
|
||||||
|
"checkbox-button",
|
||||||
|
"col",
|
||||||
|
"color-picker",
|
||||||
|
"config-provider",
|
||||||
|
"collapse-transition",
|
||||||
|
"date-picker",
|
||||||
|
"descriptions",
|
||||||
|
"descriptions-item",
|
||||||
|
"dialog",
|
||||||
|
"divider",
|
||||||
|
"drawer",
|
||||||
|
"dropdown",
|
||||||
|
"dropdown-item",
|
||||||
|
"dropdown-menu",
|
||||||
|
"empty",
|
||||||
|
"form",
|
||||||
|
"form-item",
|
||||||
|
"icon",
|
||||||
|
"image",
|
||||||
|
"image-viewer",
|
||||||
|
"input",
|
||||||
|
"input-number",
|
||||||
|
"input-tag",
|
||||||
|
"link",
|
||||||
|
"loading",
|
||||||
|
"menu",
|
||||||
|
"menu-item",
|
||||||
|
"message",
|
||||||
|
"message-box",
|
||||||
|
"notification",
|
||||||
|
"option",
|
||||||
|
"pagination",
|
||||||
|
"popover",
|
||||||
|
"progress",
|
||||||
|
"radio",
|
||||||
|
"radio-button",
|
||||||
|
"radio-group",
|
||||||
|
"row",
|
||||||
|
"scrollbar",
|
||||||
|
"select",
|
||||||
|
"skeleton",
|
||||||
|
"skeleton-item",
|
||||||
|
"space",
|
||||||
|
"step",
|
||||||
|
"steps",
|
||||||
|
"sub-menu",
|
||||||
|
"switch",
|
||||||
|
"tab-pane",
|
||||||
|
"table",
|
||||||
|
"table-column",
|
||||||
|
"tabs",
|
||||||
|
"tag",
|
||||||
|
"text",
|
||||||
|
"time-picker",
|
||||||
|
"time-select",
|
||||||
|
"timeline",
|
||||||
|
"timeline-item",
|
||||||
|
"tooltip",
|
||||||
|
"tree",
|
||||||
|
"tree-select",
|
||||||
|
"upload",
|
||||||
|
"watermark",
|
||||||
|
].map((c) => `element-plus/es/components/${c}/style/index`),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
// 构建配置(Vite 8 使用 Rolldown + Oxc)
|
// 构建配置(Vite 8 使用 Rolldown + Oxc)
|
||||||
@@ -164,65 +235,3 @@ export default defineConfig(async ({ mode }: ConfigEnv): Promise<UserConfig> =>
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// ── 工具函数 ──────────────────────────────────────────────────────────────
|
|
||||||
// Element Plus 按需样式解析器(与上方 AutoImport/Components 同配置,保证解析结果一致)
|
|
||||||
const elementPlusComponentResolver = ElementPlusResolver({
|
|
||||||
importStyle: "sass",
|
|
||||||
})[0] as ComponentResolverObject;
|
|
||||||
|
|
||||||
// 扫描 src 实际用到的 Element Plus 组件/指令,经 resolver 解析出 base + 组件样式路径,
|
|
||||||
// 供 optimizeDeps 首启预构建,避免首次使用某组件时重优化导致页面刷新。
|
|
||||||
// 指令统一转成组件名解析(v-loading → ElLoading),与组件共用同一 resolver。
|
|
||||||
async function collectElementPlusStyleImports(): Promise<string[]> {
|
|
||||||
const files: string[] = [];
|
|
||||||
const walk = (dir: string) => {
|
|
||||||
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
||||||
if (entry.isDirectory()) {
|
|
||||||
walk(resolve(dir, entry.name));
|
|
||||||
} else if (/\.(vue|ts|tsx|js|jsx)$/.test(entry.name)) {
|
|
||||||
files.push(resolve(dir, entry.name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
walk(pathSrc);
|
|
||||||
|
|
||||||
// kebab-case 名转 El 前缀 PascalCase:el-button-group → ElButtonGroup
|
|
||||||
const toPascalName = (kebab: string) =>
|
|
||||||
`El${kebab
|
|
||||||
.split("-")
|
|
||||||
.filter(Boolean)
|
|
||||||
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
||||||
.join("")}`;
|
|
||||||
|
|
||||||
const names = new Set<string>();
|
|
||||||
for (const file of files) {
|
|
||||||
const source = fs.readFileSync(file, "utf-8");
|
|
||||||
|
|
||||||
for (const match of source.matchAll(/<el-([a-z0-9][a-z0-9-]*)/g)) {
|
|
||||||
names.add(toPascalName(match[1])); // <el-button> / <el-form-item>
|
|
||||||
}
|
|
||||||
for (const match of source.matchAll(/<([A-Z][A-Za-z0-9]*)/g)) {
|
|
||||||
if (match[1].startsWith("El")) names.add(match[1]); // <ElTable> / <ElButton>
|
|
||||||
}
|
|
||||||
for (const match of source.matchAll(/\bEl[A-Z][A-Za-z0-9]*\b/g)) {
|
|
||||||
names.add(match[0]); // ElMessage / ElMessageBox 等脚本标识符
|
|
||||||
}
|
|
||||||
for (const match of source.matchAll(/\bv-(loading|popover|infinite-scroll)\b/g)) {
|
|
||||||
names.add(toPascalName(match[1])); // v-loading → ElLoading
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 每个名字经 resolver 解析出的副作用即所需样式路径(sideEffects 支持 string / ImportInfo / 数组)
|
|
||||||
const styleImports = new Set<string>();
|
|
||||||
for (const name of names) {
|
|
||||||
const resolved = await elementPlusComponentResolver.resolve(name);
|
|
||||||
if (!resolved || typeof resolved === "string") continue;
|
|
||||||
const { sideEffects } = resolved;
|
|
||||||
if (!sideEffects) continue;
|
|
||||||
for (const effect of Array.isArray(sideEffects) ? sideEffects : [sideEffects]) {
|
|
||||||
styleImports.add(typeof effect === "string" ? effect : effect.from);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return [...styleImports];
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user