vue-excel-editor源码解析:7个Vue组件如何协作实现一个Excel风格数据编辑器
【免费下载链接】vue-excel-editorVue2 plugin for displaying and editing the array-of-object in Excel style项目地址: https://gitcode.com/gh_mirrors/vu/vue-excel-editor
vue-excel-editor是一个 Vue 2 的 Excel 风格数据编辑器插件,它能对"对象数组(Array of Object)"进行展示与双向绑定编辑,内置筛选、排序、分页、校验、导入导出 Excel/CSV 等表格能力。本文带你从源码层面拆解它:整个项目src/目录下只有 6 个 Vue 单文件组件加 1 个入口文件,却组合出了一个完整的表格系统。
一、项目全景:7 个文件的分工
打开src/目录,组件规模一目了然(按代码量排序):
| 文件 | 行数 | 角色 |
|---|---|---|
src/VueExcelEditor.vue | 3289 | 核心容器:表格渲染、焦点编辑、分页、筛选、排序、导入导出 |
src/PanelFilter.vue | 447 | 筛选面板(右击列头弹出) |
src/VueExcelColumn.vue | 272 | 列定义组件 |
src/PanelSetting.vue | 296 | 表格设置面板(导出/导入/列拖拽) |
src/VueExcelFilter.vue | 165 | 固定筛选行的单元格 |
src/PanelFind.vue | 167 | 查找对话框(Ctrl+F) |
src/main.js | 18 | 插件入口,注册全局组件 |
🧩 结构上是一个典型的"一个大脑 + 一个列模型 + 一个筛选输入 + 三个弹窗面板"的分层:VueExcelEditor掌握全部状态,其余组件都是它的"遥控器"。
二、插件入口:两行注册,全局可用
src/main.js只有 18 行,核心是在install里注册两个全局组件:
vue-excel-editor→VueExcelEditor.vuevue-excel-column→VueExcelColumn.vue
注册完成后,开发者只需在模板里声明<vue-excel-editor v-model="jsondata">加上若干<vue-excel-column>,无需其他配置。
三、VueExcelEditor:表格的"大脑"
这个 3289 行的组件承担了所有重活,理解它要先抓住数据流水线:
v-model 原始数组(value) ↓ refresh() 自动推断列 / 重置状态 ↓ calTable() 按 columnFilter 逐条过滤 ↓ table 过滤后的完整数据集 ↓ pagingTable(计算属性) 按页切片 ↓ <tbody> v-for 只渲染当前页几个关键方法值得注意:
- refresh():入口方法。若用户没有声明任何列,它会调用
autoRegisterAllColumns(src/VueExcelEditor.vue#L710),用前 25 行样本"猜"出列名、宽度、字符串/数字类型——这就是为什么只写<vue-excel-editor v-model="jsondata" />也能直接工作。 - calTable()(
src/VueExcelEditor.vue#L755-L885):把筛选字符串解析成 10 种过滤类型(包含、前后缀、通配符*/?、正则~、大小比较等),逐列过滤后生成table。 - pagingTable(
src/VueExcelEditor.vue#L491-L493):一个只有两行的计算属性table.slice(pageTop, pageTop + pageSize),配合按屏幕高度自动计算的pageSize,实现了"大数据量也只渲染一页 DOM"的高性能分页。 - updateCell()(
src/VueExcelEditor.vue#L2534-L2602):所有单元格修改的唯一出口。它先调用列的change钩子(可返回 Promise 做异步校验),再写值、执行validate校验、累加汇总,最后把修改打包成 transaction 推入redo撤销栈,并$emit('update')通知外部——v-model 双向绑定和撤销(Ctrl+Z)都靠这一条链路。
四、VueExcelColumn:一个"什么都不渲染"的组件
VueExcelColumn.vue的模板只有<div />(src/VueExcelColumn.vue#L1-L3),它是整个项目最巧妙的部分:
created()钩子中调用init()(src/VueExcelColumn.vue#L123-L125),按type(string/number/select/map/checkYN/date 等 13 种)自动补齐键盘白名单、对齐方式、长度限制等默认值;- 随后调用
this.$parent.registerColumn({...})(src/VueExcelColumn.vue#L223-L268),把列定义(含toValue/toText转换函数)"上供"给父组件的fields数组; toValue/toText这对默认方法负责"存储值 ↔ 显示文本"互转,比如把M显示为Male、把时间戳格式化为yyyy-mm-dd。
💡 换句话说:<vue-excel-column>不是"渲染列的组件",而是"声明列的配置组件"。真正的列渲染全部发生在VueExcelEditor的模板里,这样列的增删、拖拽、隐藏只需操作fields数组即可。
五、VueExcelFilter:筛选行的"活单元格"
当启用filter-row时,表头下方会出现一行筛选格,每个格子就是VueExcelFilter.vue:
- 它是一个
contenteditable的<td>,输入内容通过v-model写回父组件的columnFilter哈希(src/VueExcelFilter.vue#L76-L84); - 支持左右方向键在格子间移动(
keyWest/keyEast),与 Excel 筛选行操作手感一致; - 点击格子右缘 15px 区域(
mouseDown,src/VueExcelFilter.vue#L145-L153)会调用this.$parent.$refs.panelFilter.showPanel(this),把自身作为参数交给筛选面板。
VueExcelEditor监听到columnFilterString变化后触发calTable()重算——输入即筛选,全程不引入任何虚拟 DOM 框架,纯靠 Vue 2 的响应式。
六、三个 Panel 面板:统一模式的"遥控器"
PanelFilter、PanelSetting、PanelFind三个弹窗组件共享同一套骨架:全屏半透明遮罩 + 居中面板 + Esc 关闭 + 点击空白处关闭。区别只在内容:
- PanelFilter(筛选面板):
showPanel(ref)接收刚才的VueExcelFilter引用作为"通道"。面板内先对整列值做去重排序生成候选列表,提供"≒ 接近 / = 精确 / ≠ 不等 / ≥ / ≤ / ~ 正则"等条件符号,点击应用时通过columnFilterRef.$emit('input', opt)把结果写回筛选格(src/PanelFilter.vue#L170-L175);排序按钮则直接调this.$parent.sort(direction, colPos)(src/PanelFilter.vue#L146-L149)。 - PanelSetting(设置面板):通过
v-model="fields"直接双向绑定列数组,内部用vuedraggable实现拖拽调整列顺序,勾选框控制列显隐,并提供导出/导入按钮,转发给父组件的exportTable/importTable(src/PanelSetting.vue#L107-L114)。列宽、列名等设置还可通过remember属性存入 localStorage,下次打开自动恢复。 - PanelFind(查找面板):最轻量的一个(167 行),输入文本后调用
this.$parent.doFind(text)(src/PanelFind.vue#L43-L47),由父组件的doFind在整张表中顺序搜索并自动翻页、移动焦点框,Ctrl+G 继续查找。
🔁 三个面板对父组件的调用方式高度统一:this.$refs.panelX.showPanel()打开、this.$parent.方法()执行动作,状态永远单向地流回VueExcelEditor。
七、编辑交互:一个"漂浮"的文本框
传统表格为每个单元格放一个<input>,而 vue-excel-editor 全表只维护一个<textarea>(src/VueExcelEditor.vue#L157-L173):
- 点击单元格或键盘方向键时,
moveInputSquare()(src/VueExcelEditor.vue#L2309-L2394)用getBoundingClientRect()计算目标格子的精确位置,把这个输入框"漂"过去,同时自动滚动让目标格可见、跨页时整页移动一行; - 输入完成后
inputCellWrite()走updateCell()统一写回; - 多选行时,修改会经
updateSelectedRows()批量套用到所有选中行——即 Excel 式的批量更新。
这个设计让 6 列 × 100 行也只监听 1 个输入框,键盘导航(Tab、Enter、Esc、PageUp/Down、Ctrl+A/C/V/Z/F/G/L)的体验因此非常流畅。
八、架构总结:值得借鉴的 3 个设计
- 状态集中于父组件:
value、fields、table、selected、columnFilter、redo全部是VueExcelEditor的 data,子组件只做"遥控器",事件流简单可追踪; - 配置组件与渲染分离:
VueExcelColumn只声明、不渲染,VueExcelEditor只渲染、不解析配置,列的动态增删改全靠fields数组; - 单一数据出口 + 事务日志:一切修改收敛到
updateCell(),天然获得校验、汇总、事件通知、撤销四件套。
📌 想动手验证,可用npm install vue-excel-editor引入后在模板中声明组件,配合v-model传入一个对象数组即可看到完整效果;更完整的 Props/Events/Methods 列表可参阅 README.md。
【免费下载链接】vue-excel-editorVue2 plugin for displaying and editing the array-of-object in Excel style项目地址: https://gitcode.com/gh_mirrors/vu/vue-excel-editor
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考