从列表页到规则引擎:一个组件封装过程中的前端认知进阶

你是不是也写过几十个中后台页面:

  • 搜索表单重复粘贴?
  • 状态字段手动判断?
  • 时间字段反复 format?
  • 页面跳转状态丢失?

看起来你"很会写",但其实你只是写得多。

这次我们来讲点硬的,不止封装功能,而是把一个列表页写成系统、抽成规则

🚩 一个最普通的中后台列表页

你熟得不能再熟的结构:

  • 搜索 + 表单
  • Tab 状态切换
  • 表格展示 + 分页
  • 编辑跳转 or 弹窗操作

以前我们怎么写?👇

vue 复制代码
<el-form>
  <el-input v-model="query.name" />
  <el-date-picker v-model="query.date" />
  <el-button @click="fetchData">搜索</el-button>
</el-form>

<el-table :data="tableData" />

写是能写,但每次都得重复处理这些:

  • query 对象手动构造
  • 表单字段手动初始化
  • 跳转回来状态丢了
  • loading、分页拼来拼去

🎯 我要的不是组件,而是规则系统

我希望的列表页只需要这样 👇

vue 复制代码
<SmartListView
  :form-rule="rule"
  :table-setup="tableSetup"
  :fetch-setup="fetchSetup"
  :tabs-static-list="tabsArr"
/>

剩下的交给组件:

✅ 表单结构自动渲染

✅ 默认值 + 时间字段自动处理

✅ 查询 / 分页 / 缓存集成

✅ Tab 切换自动记忆

✅ 自定义 slot 灵活扩展

🧱 设计重点拆解

1️⃣ 字段 schema + formModel 解耦

js 复制代码
formSetup = [
  {
    type: 'datePicker',
    field: 'updateDate',
    title: '时间范围',
    value: [new Date(), moment().add(30, 'days').toDate()],
    props: { type: 'range' }
  }
]

🔍 schema 控结构,formModel 控值

🧠 这就是典型的配置驱动,字段即规则。

2️⃣ fetchSetup 接管一切行为

js 复制代码
fetchSetup = {
  url: '/api/list',
  tabs: {
    tabFilterKey: 'status',
    formDefaults: {
      updateDate: [new Date(), moment().add(30, 'days').toDate()]
    }
  },
  timeAdapter: {
    updateDate: ['startTime', 'endTime']
  }
}

你不需要再 format时间字段,也不需要自己转换字段名了。

3️⃣ Tab 切换自动触发查询 + 状态缓存

  • 每个 Tab 对应一个搜索状态
  • 切换时恢复上一次状态
  • 再次挂载保留分页信息

这不就是"列表状态保持"的理想体验?

4️⃣ 搜索 + 清空统一封装

js 复制代码
@submit → getFormData() → processTimeAdapter() → fetch()
@clear  → resetFields + clearStorage

再也不写 search()、reset()、page = 1,这些都应该在组件内搞定!

🧨 实战踩坑回顾(是真的踩了)

setValue 后值又被清空?

👉 是 v-model 自动同步值导致的,得放在 this.$nextTick 后。

❌ formDefaults 被污染?

👉 记得 deepClone,Vue 响应式会污染原始值!

❌ tabsArr 是接口来的,但子组件不更新?

👉 用 :key="smartListKey" 让组件重新挂载。

🧠 软件工程视角的组件设计

🧩 设计模式:

模式 体现
策略模式 不同字段转换策略
模板方法 SmartListView 结构统一,slot 灵活插入
观察者模式 watch formRule 响应变更

🧱 工程思想更重要:

  • 字段结构统一
  • 状态行为集中管理
  • 页面逻辑降到最低

🧬 真正的统一方案:我把一页内容,封成了一份 schema

经过一轮又一轮封装、踩坑、重构,我最终把所有列表页的结构 ------ 表单、表格、请求、tabs ------ 都抽象成了一个 pageSchema 配置对象。

从此,页面不再是写出来的,而是「定义出来的」。

ini 复制代码
<SmartListView :schema="pageSchema" />

一行组件调用,搞定整个列表页。

✅ 我实现了这些功能:

  • form.fields → 自动渲染搜索表单 + 默认值填充
  • table.columns → 自动生成表格结构 + 权限 + 字典映射
  • fetch.url → 统一封装查询逻辑 + 时间字段转换 + loading 管理
  • tabs.options → 动态状态 Tab + 状态缓存 + 自动切换请求
  • schema.transform → 自动把字段从组件值映射到接口字段(如日期 range)

再复杂的业务,只需要维护一份 schema 配置。

🔥 现在新增一个列表页只需要:

css 复制代码
export const logPageSchema = {
  form: {{ fields: [...] }},
  table: {{ columns: [...] }},
  fetch: {{ url: '/api/logs' }},
};

以前你要写 300 行 Vue,现在你只需要写 30 行配置。

💬 配置是抽象能力

很多人一看到 schema 就说:

"太麻烦了,还不如直接写。"

但你要知道:

写代码是为了抽象,抽象是为了规模化。

v-model 和写 schema,不是谁轻松谁牛逼,而是:

谁能写出 更多人复用未来还能自演化 的页面,谁就赢了。

🎯 思考:你以为你在写页面,其实你在构建规则系统

封装 SmartListView 的过程,不是把逻辑揉进组件,而是把行为抽象成规则,把重复变成结构。

你在做的,不只是「减少代码量」,而是:

  • 让表单字段具备声明式规则性
  • 让页面状态具备可还原能力
  • 让组件逻辑具备平台通用性

SmartListView 渲染实现结构图

真正的高级工程感,是这样的:

  • 字段有定义中心
  • 状态有恢复机制
  • 表单有 schema 驱动
  • 页面不再"实现功能",而是"组合能力"

到这一步,你不再是"封装组件的人",而是:

在定义规则的人

在推动系统的人

在构建平台能力的人

总结一句话:页面≠代码堆砌,字段≠值输入,表单≠UI控件。

真正的前端能力,是让规则生成页面,而不是手写页面。

如果你也在封装列表页、踩坑表单 schema、搞不定状态回填------欢迎评论区分享,我们一起把组件写成系统,写成能力!

🏁 结语:页面 ≠ 技术,规则才是资产

页面能跑只是初级

页面清晰是中级

页面可控是高级

真正的高级前端,不写页面,而是定义页面怎么写。

欢迎留言交流 👉 你最近写的列表页,还在重复写啥?

相关推荐
崔庆才丨静觅11 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby606112 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了12 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅12 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅12 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅13 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment13 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅13 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊13 小时前
jwt介绍
前端
yunteng52113 小时前
通用架构(同城双活)(单点接入)
架构·同城双活·单点接入