Schema-driven CRUD page rendering engine
npm install super-element-jsSchemaView 模板页,适用于大多数简单的 CRUD 页面场景。如果你需要进行二次开发、自定义模板页或扩展功能,请访问 Gitee 仓库 获取完整源码。
schemaConfig 一次性描述表格、搜索、表单、弹窗等所有结构
SchemaView 只是一个内置模板,你可以很容易开发"长得不一样"的模板页
apiParamsConfig函数,统一管理请求参数
bash
npm install super-element-js
或
yarn add super-element-js
或
pnpm add super-element-js
`
---
📺演示
>使用superElementJs,渲染的页面 👇






---
🚀 快速开始
> 💡 提示
> 这里的“快速开始”只关注前端如何使用 superElement,包括:初始化引擎、路由配置与使用,以及完全前端配置模式。
> 更完整的后端 JSON Schema 配置与高级能力,请看后面的 进阶配置 章节。
$3
在一个典型的后台项目中,推荐由后端返回整棵模型 / 菜单配置,然后在前端一次性初始化引擎(createSchemaViewEngine):
`javascript
// main.js
import { createApp } from "vue";
import { createPinia } from "pinia";
import { createSchemaViewEngine } from "super-element-js";
import App from "./App.vue";
import request from "@/common/request"; // 你项目中封装的请求函数(推荐)
import { apiParamsConfig } from "@/config/api-params-config"; // API 参数配置(前端补充)
import { getModelInfo } from "@/superElementConfig/super-api"; // 获取 schema 配置的 API
const app = createApp(App);
const pinia = createPinia();
app.use(pinia);
async function initApp() {
const res = await getModelInfo();
if (!res || !res.success || !res.data) return;
const { menu } = res.data;
const models = menu; // 即后端返回的菜单 / 模型配置数组
createSchemaViewEngine({
models, // schema 配置数组
request, // 请求函数(推荐传入你项目封装的 request)
dictApi: "/system/dict/data/list", // 可选:字典获取 API 接口地址,默认 '/system/dict/data/list'
apiParamsConfig, // 前端补充的 API 参数配置
pinia, // 传入主项目的 Pinia 实例,确保使用同一个 store
});
app.mount("#app");
}
initApp();
`
参数说明:
- options.models (Array):后端返回的模型配置数组(通常是菜单树)
- options.request (Function):请求函数,不传则使用内部默认实现
- options.dictApi (String):字典获取 API 接口地址,默认 '/system/dict/data/list'
- options.apiParamsConfig (Object):前端补充的 API 参数配置
- options.pinia (Pinia):Pinia 实例,确保使用同一个 store
$3
如果你暂时没有后端 JSON Schema,也可以完全在前端写一个 schemaConfig 对象,直接传给 SchemaView 使用,下面是简化示例:
`vue
`
这种模式不依赖后端 JSON Schema,非常适合:
- 在现有项目中快速引入一个基于 schema 的 CRUD 页
- Demo / PoC 验证
- 逐步把“写死的页面”迁移为 Schema 驱动的配置
---
⚙️ 进阶配置
> 本章节对应完整的后端 JSON Schema 配置、API 配置、前端 apiParamsConfig 以及配置校验能力,更适合中大型项目或团队规范化接入。
$3
在后端服务(Node.js、Java 等)中,需要配置 JSON Schema 并提供一个接口返回解析后的配置。以 Node.js 为例(参考 super-node 实现):
目录结构:
`bash
your-backend/
├── model/
│ ├── index.js # 解析 model 配置的入口
│ └── model.js # JSON Schema 配置文件
├── app/
│ ├── controller/
│ │ └── project/
│ │ └── ProjectController.js
│ ├── service/
│ │ └── project/
│ │ └── project.js
│ └── router/
│ └── project/
│ └── project.js
`
1.1 创建 Controller:
`javascript
// app/controller/project/ProjectController.js
module.exports = (app) => {
const BaseController = require("../base")(app);
return class ProjectController extends BaseController {
getProject(ctx) {
const projectService = app.service?.project?.project;
if (!projectService) throw new Error("Service 未加载");
const projConfig = projectService.get();
if (!projConfig) {
return this.fail(ctx, "获取项目异常", 50000);
}
this.success(ctx, projConfig);
}
};
};
`
1.2 创建 Service:
`javascript
// app/service/project/project.js
module.exports = (app) => {
const BaseService = require("../base")(app);
// 从 model/index.js 加载配置
const modelList = require("../../../model/index")(app);
return new (class ProjectService extends BaseService {
get() {
const projConfig = modelList[0].model;
return projConfig;
}
})();
};
`
1.3 配置路由:
`javascript
// app/router/project/project.js
module.exports = (app, router) => {
const controller = app.controller?.project?.ProjectController;
if (!controller) throw new Error("Controller 未加载");
router.get("/api/project", controller.getProject.bind(controller));
};
`
1.4 接口返回格式:
接口 /api/project 建议返回如下结构:
`json
{
"success": true,
"data": {
"model": "dashboard",
"name": "电商系统",
"menu": [
{
"key": "product",
"name": "商品管理",
"menuType": "module",
"moduleType": "schema",
"route": "system/product",
"schemaConfig": { / ... / }
}
]
}
}
`
---
$3
在后端 model/model.js 中,通过 JSON Schema 定义页面结构(字段 + 表格 + 搜索 + 表单等):
`javascript
// model/model.js
module.exports = {
model: "dashboard",
name: "电商系统",
menu: [
{
key: "product", // 唯一标识,对应路由中的 key
name: "商品管理",
menuType: "module",
moduleType: "schema",
route: "system/product", // 路由路径
schemaConfig: {
// API 配置
api: {
list: "/api/proj/product/list",
detail: "/api/proj/product/:product_id",
create: "/api/proj/product",
update: "/api/proj/product",
delete: "/api/proj/product/:product_id",
params: {}, // 函数无法 JSON 序列化,留空,由前端 apiParamsConfig 补充
},
// JSON Schema 定义
schema: {
type: "object",
properties: {
product_id: {
type: "string",
label: "商品ID",
tableOption: {
width: 300,
"show-overflow-tooltip": true,
},
editFormOption: {
comType: "input",
disabled: true,
},
},
product_name: {
type: "string",
label: "商品名称",
maxLength: 20,
minLength: 3,
tableOption: {
width: 200,
},
searchOption: {
comType: "input",
default: "",
},
createFormOption: {
comType: "input",
default: "",
rules: [
{ required: true, message: "商品名称不能为空" },
{ min: 3, max: 20, message: "商品名称长度在 3 到 20 个字符" },
],
},
editFormOption: {
comType: "input",
rules: [{ required: true, message: "商品名称不能为空" }],
},
},
// ... 更多字段
},
required: ["product_name"],
},
// 表格配置
tableConfig: {
comType: "table",
},
// 搜索配置
searchConfig: {},
},
},
// ... 更多菜单项
],
};
`
关键配置说明:
- key:菜单项的唯一标识,必须与路由中的 key 一一对应
- schemaConfig.api:定义 CRUD 接口地址
- schemaConfig.schema:JSON Schema 定义,字段中通过 xxxOption 扩展表格 / 搜索 / 表单行为:
- tableOption:表格列配置
- searchOption:搜索区域配置
- createFormOption:新增表单配置
- editFormOption:编辑表单配置
---
$3
当你采用“后端驱动模型 + 引擎初始化”的模式时,路由只需要指向内置模板页 SchemaView,并在路由query 中配置 key 来关联后端的模型:
`javascript
// router/index.js
import { SchemaView } from "super-element-js";
const routes = [
{
path: "/system/product",
component: SchemaView,
meta: {
title: "商品管理",
key: "product", // 对应后端 model 配置中的 key
},
},
];
`
关键点:
- 路由querykey 必须与后端 model 配置中的 key 一致
若采用若依动态路由风格,可以在路由过滤阶段统一把 schemaView 映射为 SchemaView:
`javascript
// store/permission.js(示意)
import { SchemaView } from "super-element-js";
function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) {
return asyncRouterMap.filter((route) => {
if (type && route.children) {
route.children = filterChildren(route.children);
}
if (route.component) {
if (route.component === "Layout") {
route.component = Layout;
} else if (route.component === "schemaView") {
// 约定:后端 component = 'schemaView' 时,渲染 SchemaView 模板页
route.component = SchemaView;
}
}
if (route.children != null && route.children && route.children.length) {
route.children = filterAsyncRouter(route.children, route, type);
} else {
delete route["children"];
delete route["redirect"];
}
return true;
});
}
`
---
$3
由于函数无法 JSON 序列化,后端通常只返回 api.xxx 的 URL,参数拼装逻辑放在前端统一维护。推荐在前端声明一个 apiParamsConfig:
`js
// /src/config/api-params-config.js
export const apiParamsConfig = {
product: {
// 商品列表:合并搜索参数
list: (ctx) => ({
query: ctx.apiParams || {},
}),
// 商品详情:从行数据中取主键 product_id,支持 camelCase / snake_case
detail: (ctx) => ({
path: {
product_id: ctx.row.product_id ?? ctx.row.productId,
},
}),
// 新增商品:直接提交表单数据
create: (ctx) => ({
body: ctx.form || {},
}),
// 修改商品:直接提交表单数据
update: (ctx) => ({
body: ctx.form || {},
}),
// 删除商品:从当前行取 product_id 作为 path 参数
delete: (ctx) => ({
path: {
product_id: ctx.row.product_id ?? ctx.row.productId,
},
}),
},
// ... 更多模块配置
};
`
在初始化引擎时传入:
`js
createSchemaViewEngine({
models,
request,
apiParamsConfig,
});
`
引擎内部会在 modelStore.setModels() 时自动把 apiParamsConfig[key] 合并进对应菜单项的 schemaConfig.api.params,从而在请求列表 / 详情 / 新增 / 修改 / 删除时,自动套用你定义的参数拼装逻辑。
---
$3
如何在你的项目中开启校验(推荐只在开发环境开启):
1. 在主项目入口(例如 main.js)中,在开发环境设置全局开关:
`js
// main.js(示意)
if (import.meta.env.DEV) {
// 显式打开 superElement 配置校验
window.__SUPER_ELEMENT_DEV__ = true;
}
`
2. 当 window.__SUPER_ELEMENT_DEV__ === true,或检测到 Vue DevTools / import.meta.env.DEV === 'development' 时,validateSchemaConfig 会在构建 schemaConfig 时自动运行:
- 校验必填字段:如 key、name、schemaConfig、moduleType 等
- 校验 API 配置:是否缺失 list,detail 路径格式是否合理等
- 校验 Schema 配置:字段类型、comType 是否已注册、rules 是否为数组等
- 校验 TableConfig:comType 是否在允许范围内(如 tablePanel | treeTablePanel)
3. 如果存在错误:
- 在控制台输出详细错误信息
- 抛出异常中断当前页面渲染,避免“带病上线”
4. 如果仅存在警告:
- 以 console.warn 的形式输出提示,但不会中断渲染
生产环境下,isDev 为 false` 时会直接跳过校验,不产生任何性能损耗,非常适合作为团队内部的“配置规范守护神”。