参考
项目文件说明
-
package.json 项目的配置文件
-
gulpfile.js 项目通过gulp进行打包和开发
-
/dist 打包之后的输出文件
-
/doc 说明文档
-
/node_modules
-
/src 源文件
-
config.js 项目的默认配置文件
-
core.js 项目的入口文件,通过这里的create进行初始化和加载对应的事件处理函数
-
index.html 开发使用的index.html,但是在master分支的index.html太大了,有差不多2000行,根本没法使用,这里可以自己写一个简单的index.html来替换它提供的index.html. 这里我们如果修改了index.html中的代码,会立刻被打包复制到/dist的目录下。
-
index.js 就是专门为火狐做了fix,然后就是导出luckysheet
-
/controllers 各种控制器
- alternateformat.js 颜色单元格的控制器
- conditionformat.js 条件格式
- constant.js 一些常量定义,包括右键和整个表格的dom结构
- controlHistory.js 记录一些操作历史,为了回退等操作
- dropCell.js 在单元格中一些下拉的操作
- expendPlugins.js 注册一些插件,目前只支持chart和print,但是写了chart,还会抛出错误,被浏览器给捕获到
- filter.js 筛选相关的操作
- keyboard.js 键盘相关的一些操作
- searchReplace.js 查找替换相关的操作
-
/css 样式相关的目录
-
/data 和插件chart有关的配置
-
/demoData 这个目录下一共9个sheet的配置,可以引入到index.html中分别展示查看
-
/expendPlugins 和chart插件相关
-
/fonts 字体
-
/function 封装一些常用的函数相关的操作
-
/global 封装一些常用的函数
-
/locale 本地化相关,显示中文或者英文
-
/methods 封装一些常用的函数
-
/plugins 引用的一些插件
-
/store 类似redux,顶层数据流
-
/utils 封装一些工具函数
-
core.js 分析
-
类似webpack,合并所有的config,把一部分config的设置挂载到store上面,成为全局的配置
-
initPlugins(extendsetting.plugins, extendsetting.data); 注册插件
-
如果没有设置loadurl,也就是数据不是从后端获取,就会从sheetmanage.initialjfFile(menu, title);去获取当前sheet需要展示的数据
-
然后通过initialWorkBook 完成需要的初始化事件,其实也就两件事,渲染和绑定相应的事件处理函数。
function initialWorkBook() { // 创建dom,并且绑定事件处理 luckysheetHandler(); //Overall dom initialization initialFilterHandler(); //Filter initialization initialMatrixOperation(); //Right click matrix initialization initialSheetBar(); //bottom sheet bar initialization formulaBarInitial(); //top formula bar initialization rowColumnOperationInitial(); //row and coloumn operate initialization keyboardInitial(); //Keyboard operate initialization orderByInitial(); //menu bar orderby function initialization zoomInitial(); //zoom method initialization printInitial(); //print initialization initListener(); }
初次渲染流程
-
首先获取当前sheet对应的渲染数据,这里的格式和demoData中的一致
-
最后的渲染在global/createdom.js 中的luckysheetcreatedom(colwidth, rowheight, data, menu, title),参数函数比较清晰.
-
然后就是通过gridHTML来拿到模板字符串,通过replaceHtml来替换模板字符串中的变量。
-
中间的显示区域使用canvas来根据data画出来,也比较简单,
-
最后就会渲染出入下图所示:
监听事件
当我们点击之后,会到controllers/handler.js里边进行处理,里边通过在$("#luckysheet-cell-main, #luckysheetTableContent")上面绑定了单击和双击事件,单击是选中当前的单元格,双击之后,会在controllers/updateCell.js里边把编辑框加进去。
如何更新数据,比如我们编辑一个单元格
-
当我们双击某个单元格之后,会在当前插入一个dom元素,id为luckysheet-rich-text-editor,然后我们编辑的时候,就是通过在controllers/keyboard.js里边的luckysheet-input-box绑定的keydown来捕获,通过functionInputHanddler来更新。
formula.functionInputHanddler( $("#luckysheet-functionbox-cell"), $("#luckysheet-rich-text-editor"), kcode );
-
当我们更新完之后,这个时候并没有把数据写到Store.flowData里边,而是等到你下次点击其他单元格的时候,被controllers/handler.js里边的$("#luckysheet-cell-main, #luckysheetTableContent")绑定的mousedown事件获取,通过updatecell来更新,
// 上次更新的会在这里把数据写到Store.flowData,Store.luckysheetCellUpdate[0],表 示上次更新的行号,Store.luckysheetCellUpdate[1]表示上次更新的列号
formula.updatecell(
Store.luckysheetCellUpdate[0],
Store.luckysheetCellUpdate[1]
);
-
updatecell 函数在global/formula.js中,
// 当通过普通的点击编辑之后,再点击其他单元格的时候,在这里更新 // r 是上次更新的行的坐标 // c 是上次更新的列的坐标 // value 为空 // isRefresh 默认为true,也就是说默认会刷新, // 这里主要的作用就是通过获取r和c此单元格的值,用来更新Store.flowData, // 然后调用jfrefreshgrid更新canvas updatecell: function(r, c, value, isRefresh = true)
- jfrefreshgrid 在global/refresh中,然后这里调用luckysheetDrawMain来重新渲染可视区域,这里是全部重新渲染的,以后应该可以优化为只渲染修改的那部分。到此所有的流程基本走完了。
mini-luckySheet
初始化环境
-
下载代码git@github.com-mini-luckysheet:zsjun/mini_luckysheet.git,然后把代码回退到初始化环境的 commitId ,也就是执行命令
git reset --hard a6a60d0d71fd9da2c1a22d04480e62643111bb1b
然后执行下面的命令,下载安装包,因为现在src里边暂时还没有文件,所以暂时启动不了
npm install
基本渲染
- version 是59ef7e82d7972782c3c0689153d36a49552aaf10
- 基本流程就是首先获取所有的配置,然后通过createdom把定义的一些html全部append到body里边去,再通过luckysheetsizeauto使用canvas把表格画出来。
增加滚动和resize
-
version 是26bace3b69dbb88fc2ea0aa398f0e569307ff69d
-
这里主要是增加了src/controllers/handle.js,在里边通过jquery绑定了scroll事件处理函数。
$("#luckysheet-scrollbar-x") .scroll(function() { luckysheetscrollevent(); }) .mousewheel(function(event, delta) { event.preventDefault(); }); $(window).resize( debounce(function() { let luckysheetDocument = document.getElementById(Store.container); console.log(luckysheetDocument); if (luckysheetDocument) { luckysheetsizeauto(); } }, 500) );
增加单元格可以选中
- version: 56b10f35334fed4e1ec4caf77280a324c1daa9b5
-
在store/index.js 中增加一个数组luckysheet_select_save用来保存选中的单元格
-
在constant/gridHTML中的luckysheet-cell-main下面增加
- 在controller/handle里边增加事件处理函数,也就是在canvas和覆盖整个canvas的div上面添加mousedown事件处理函数,事件处理函数也很简单,就是获取到当前的坐标,计算出在canvas中属于第几行和第几列,然后把该单元格高亮就ok了
- 这里最关键的就是如何根据坐标定位出来在第几行和第几列,这里的处理逻辑是在
global/location.js里边,这里的处理逻辑也很简单
function colLocation(x) {
// 通过global/rhchInit.js里边根据每个单元格的宽度先形成数组Store.visibledatacolumn
// 然后根据x的坐标定位在哪个单元格里边
let col_index = luckysheet_searcharray(Store.visibledatacolumn, x);
if (col_index == -1 && x > 0) {
col_index = Store.visibledatacolumn.length - 1;
} else if (col_index == -1 && x <= 0) {
col_index = 0;
}
return colLocationByIndex(col_index);
}
增加双击单元格可以编辑
这里的总体逻辑也比较简单,就是我们首先在html中添加inputhtml,然后再在覆盖canvas的div上绑定双击事件,当我们双击之后,拿到当前的行和列,把对应的inputhtml定位到该位置就ok了
- version: f7039cb8aa9e3d475f35182e85dd9882c3179709
- 在constant里边增加inputHTML,并且在global/createDom中,通过append把html添加到body中
- 在controller/handle.js 中增加dbclick事件处理函数,逻辑比较简单。