精华内容
下载资源
问答
  • 2019-04-07 10:20:45

    一、我们在开发过程中,表格无疑也是最常用到的,那么快速的制作表格和绑定数据的方法就是渲染了, 执行渲染之前,需要进行表格的数据查询,并绑定表格数据。只有把前面查询出来的数据绑定到表格里面才能进行渲染。而且需要把数据绑定到页面上去,因为数据来源于数据库,就会涉及到软件与数据库的对接。就要绑定页面数据的状态,但是在绑定数据之前,又要对数据库的数据进行截取,截取的方法就是分页了,对数据绑定完成后,就是表格的渲染了。

    然后使用Layui的框架对表格进行方法渲染,因为layui渲染的表格功能很多,而且会对数据有分页的效果,在下面输入需要显示的页数,页面会自动跳转到对应的页面,所以对它的操作也相对便捷方便。
    在这里插入图片描述
    二、渲染第一步就是引入插件。

    数据表格在渲染它之前,首先就要声明一个表格,接着就是执行渲染了。当然它里面也有很多有意思的属性,比如elem后面跟的就是要绑定的那个元素,但是如果写的是一个even:true就会开启隔行换景的表格样式(见图1),size用来设置表格大小,skin则可以设置表格边框的样式。这里需要注意的是,引号里面的的元素不能留空格,不然就会识别不出来。

    在这里插入图片描述

    三 、渲染主要有两个部分 1.是你要使用的主键2.渲染的具体内容

    如果只需要一个渲染的内容就直接引用可以了,要是两个以上的话就要使用数组的格式引用,比如[‘layer’, ‘table’] 。

    然后的第一步,就是使用elem的ID选择器选择到你的表格ID,当然高度也可以自己设置,不设置的话它也会自适应,如果表格大小不足再设置也不迟。

    分页我们还是默认开启的,因为不开启的话,渲染出来的表格数据就会全部显示到一页上,且不方便查看,渲染最后面设置的每页显示条数和每页条数的选择项就会没有效果,这样查看数据的话就会在一个页面上一直翻,操作十分不方便。

    在这里插入图片描述

    Cols里面就是整个渲染最主要的部分了,这里需要注意它的括号是怎么打的。首先是一个方括号,然后里面再是一个方括号,接着就是把两个方括号一起分开,再里面的花括号才是表头
    的列,注意每一个花括号的后面是用逗号分开的而不是分号。列也有很多种类,比如排列的方式,给每一个行添加序号等等,而且一些需要的且不想显示出来的ID也可以把它隐藏起来。

    最后的就是分页的操作了,分页也就是底下可以进行换页操作的功能栏,用到page里面的两个属性 limit 指的是默认的行数,不设置的话默认是10行;limits设置的也是行数,不过它的是个手动选择的下拉框,需要显示多少行只需点击切换就行。

    在这里插入图片描述

    更多相关内容
  • 表格数据变更,一般包括几个内容:新增、修改、删除、移动,开发经常会面临的一个问题就是变更之后如何将数据同步到节点上,一直以来个人的建议还是利用表格重载,不管是url模式的还是data模式的实际都是需要重载...

    参考链接

    https://www.html.cn/framework/layui/15886.html
    

    表格数据变更,一般包括几个内容:新增、修改、删除、移动,开发中经常会面临的一个问题就是变更之后如何将数据同步到节点上,一直以来个人的建议还是利用表格重载,不管是url模式的还是data模式的实际都是需要重载,url重载自然会重新请求后台得到最新的数据,data模式一般就是对data的操作,之后重新以新的data去渲染出来。

    同时会考虑的是如何尽量减少请求,可能感受最深的就是update操作,为了要更新这一条记录而重载整个表格,请求一遍数据感觉划不来,那么一般来说就可以利用表格的tool事件中的obj.update这个方法去更新。

    不过具体使用中就会发现其诸多的不足的地方,本文就是主要针对这些不足进行一个处理给出一个tablePlug.update的方法,然后进而衍生出add和remove和move,同时新增了更新统计行数据的方法。

    测试页面: 综合测试页面 流加载表格测试页面 定时刷新表格测试页面

    一、update

    正如上面说的obj.update(data)有诸多限制,优点上来说就是用最小的修改代价,实现了数据的更新,他就更新参数中的data中的键的数据,不会整个行更不会整个table的节点更新;缺陷是底层的实现逻辑有点问题:

    1、是通过遍历data,更新缓存cache中对应的记录的key的value,然后根据cols的配置信息更新td的内容,但是如果是想要更新toolbar列的话就没戏,目前解析的只有templet的,所以如果想要更新toolbar的话基本就只能设置成templet,而且要给这个列添加一个field,才有理论上的可能。

    2、toolbar列即使加了field改成templet也未必能更新过来,因为内部的实现逻辑是先判断原始的data是否有这个key,所以如果field命名是原始的data里面没有的,后面用obj.update也更新不进去的,这个是一个比较大的限制。

    因为拿我们项目来说,后台给我们的数据如果原始的记录里面没有这个key的值他不会给一个key: ''的,那么后面要想利用obj.update这个key就变得不可能,除非利用parseData在渲染之前对后台给的数据做一个人工的初始化把对应的key添加上,但是可想而知有多麻烦。

    3、数据他是一个一个更新进去,然后更新一个值就更新对应的td,但是这个就存在另外一个风险了,就是遍历对象他是无序的,比如update{a: 1, b:2},如果a字段的cols中会用到b字段的值做一个处理再显示出来。

    那么如果遍历顺序是先更新a的值,然后就开始更新a的td的内容,这个时候cache中b的值还是旧的不是你要更新进去的2,等到更新了b字段了他又不能说检测到其他字段有使用了这个字段会去再次更新对方的内容,这就导致了a出来的结果还是错的。

    4、更新了统计列的某一个值统计行的对应数据没有重新计算。

    总结的来说就是,obj.update实现的还是太过理想化太过简单,一条记录从数据上来说每个key是独立的这个没什么问题,但是到页面显示就不然了,因为页面的内容它不一直是单个字段的简单值显示,还会进行一些特殊处理。

    所以需要一个templet来转化,来自定义,所以有可能一个td里面会用到多个字段这个很正常,工具列的按钮也会根据数据的状态去决定部分按钮是否显示等等。

    所以个人认为要更新这个数据不能是一个独立的小单元的更新,而是先update这一行的数据然后在update这一行,而不是遍历被update的key一个个更新,再往大了看,实际这个表的记录也是一个整体。

    也是不能说你改了这条记录其他的记录必定是不变的,不排除某个字段的td他会根据当前页面的同一个field做了什么处理现实,比如统计行,所以目前的思路就是直接将值先update到cache中,然后再调用table内部的渲染tr td的内容。

    大致的代码:

    1579059007896296.png

    前面是针对参数做了一些处理让参数更加灵活,最关键的是后半部分的更新cache的部分,还要一个最关键的renderData的方法:

    1579059017111371.png

    他的作用就是将cache中的数据重新解析渲染一遍,同时针对是否是移动数据还有默认点击那一条记录的处理,但是核心是渲染cache,调用table.js内部的renderData。

    使用场景:

    1、知道当前编辑修改的是那一条记录,可以看看一个最常用的场景就是点击编辑弹出一个form然后修改提交,完成之后希望尽量不要重新请求接口更新到data和页面中去,

    gif很不好录,自己使用测试的例子里面的编辑按钮测试效果即可

    调用的更新数据的形式是:

    tablePlug.update(表格实例的id, 当前tr的index, newData)
    

    1579059027272235.png

    2、不知道当前的trIndex的情况下update某一条记录的话,必须有一个限制就是必须是有主键的表格,并且更新的数据中必须包含主键的字段,不然你也不知道更新的到底是哪条记录。

    tablePlug.update('demo', {id: 10002, username: '贤心'});
    

    3、一次性更新多条记录,这个参数trIndex就没有意义了,加了也没用,因为是更新多条记录,所以可以这么写

    tablePlug.update('demo', [{id: 10002, username: '贤心'}, {id: 10006, username: '小偷', age: 18, sign: '大叔'}]);
    

    这个测试页面可以看看头部toolbar中的“积分清零”还有“女性积分加100”这两个测试按钮以及背后的事件执行的方法

    4.png

    4、更加任性的,只要传入一个tableId,update会将当前按照cache中的数据给渲染一次,这个是非常实用的,比如如果你觉得我update中的逻辑针参数对cache的修改的逻辑不满意可以自己用自己觉得更好的方法去处理cache,最后执行一下tablePlug.update(‘demo’)就好了,提供更高的自由度,和拓展的可能性。

    二、addData

    addData添加的记录是已经请求接口完成返回的数据记录,本质上来说就是不一样的,所以不要混淆。

    具体addData的代码:

    1579059045223457.png

    data模式的话,实际也是往data里面添加一些记录,然后也是再reload一下。

    // 添加单条记录:

    tablePlug.addData ('demo', {id: newId, username: '甲'});
    

    // 添加多条记录

    tablePlug.addData ('demo', [{id: newId1, username: '乙'},{id: newId2, username: '丙'}]);
    

    关于addData的有一个比较综合的例子可以看看利用table的data模式怎么跟流加载配合使用,弄成一个流加载的表格

    https://sun_zoro.gitee.io/layuitableplug/testTableFlow
    

    三、del

    新增和删除实际个人建议还是reload比较稳妥,不管是url还是data模式都是,所以删除对应的处理方式也跟新增实际差不多,只不过删除麻烦一点的就是data模式要在原始的记录里面去删除指定的记录。

    而且有可能开启了复选的状态记忆删除了就要将关于他的状态给调整一下;还是为了使用更方便,参数同样做了处理,

    1、删除指定的下标的数据,可以查看表格行的toolbar中的删除按钮的监听处理,但是注意,如果表格是url的模式,目前测试页面写的都是json文件,所以reload也不会有效果的。

    所以要测试请在data模式的测试,不用纠结这个,url的如果是实际的服务接口的话是后台返回数据,一般删除成功了后面查询是不会再出来的,除非后台接口有问题。

    6.png

    2,删除指定的一些记录,这个一般有两种形式,但是要求一样就是必须是有主键的表格

    // id集合

    tablePlug.del('demo', [1,2,3,4]);
    

    // 对象数组

    tablePlug.del('demo', [{id: 1, name: 'name1'}, {id:2}, {id:4}]);
    

    根据得到哪种数据比较方便就用哪种形式,可以参考测试页面的批量删除的处理方式

    1579059068662686.png

    四、move

    这个处理基本跟update差不多,将数据在cache中调整位置,然后调用一下组件内部的renderData的方法让他重新渲染出来就好

    8.png

    然后为了使用方便衍生出来一个上移跟下移的方法

    9.png

    效果

    10.gif

    理论上利用一些拖拽事件或者其他的插件在事件中调用一下tablePlug.move(‘demo’, form, to);就能够实现顺序的任意改变了

    限制:注意!这个只是针对数据移动,不会有单条数据记录的变动,如果原始的数据里面有点击了排序,那么移动之后默认是会去掉这个排序的状态了的,因为移动之后很可能就不能满足当前的排序规则了,所以建议在使用移动的时候不要跟sort搭配,如果有sort而且所谓的移动是会发起请求改变数据的,那么这个建议还是使用请求接口得到两个新的数据然后用update去更新他们的位置。

    五、renderTotal

    在记录更新之后,如果存在统计行有需要统计的列,那么值一般也要跟着变,另外一个更加重要的作用就是可以自定义统计规则,而不是自带的求和,可以自定一定计算的函数,或者可以直接类似templet一样的去自定义返回的内容,包括异步的去读取想要显示的数据。

    代码大概如下:

    11.png

    从实现代码可以看出就是给cols的字段配置新增一个totalFormat的设置,可以设置一个规则如果不设置的话就是sum(目前也只是添加了sum,其他的规则后面会加入或者自己加入,比如平均。

    最大最小不过个人觉得主要意义是可以自定义方法,这个才是实用常用的),也可以设置一个方法,如果不是异步的可以直接把结果返回,如果是需要异步的那么也可以在得到最终想要的结果的时候执行:

    tablePlug.renderTotal(tableId, field, res);
    

    比如下面的:

    12.png

    平时实用的话不是都要自己去调用的,在插件内部已经在renderDone回调里面会去执行他了:

    13.png

    参数也是比较自由,不同的组合会有不同的效果,

    // 触发更新某个表格的所有列的统计数据

    renderTotal(tableId);
    

    // 触发更新某个表格的某个字段的数据

    renderTotal(tableId, fieldName);
    

    // 更新某个表格的某个字段的统计数据为value

    renderTotal(tableId, fieldName, totalValue);
    

    六、refresh

    之前做过一个智能reload的修改,即在执行table.reload的时候会根据传过去的option来判断只是重新请求数据还是需要重载一下,个人觉得效果可以了。

    不过对于有强迫症(有追求)的小伙伴来说,在一些场景下还是不够好,就是那些定时刷新的,表现就是一方面滚动条会回到top:0,left:0,还有其他的比如鼠标在操作分页组件的时候会觉得失去焦点,新增一个tablePlug.refresh来试一试能否满足要求。

    先看效果:

    14.gif

    事件背后做的事情:

    15.png

    表格config:

    16.png

    背后的实现思路

    17.png

    修改table的Class.prototype.pullData支持refresh模式

    renderData的时候根据是否refresh去做一些细节的处理,还有一个限定就是返回的数据中关于总数应该是不变的,如果发生了改变,那么还是会renderData,会重新渲染page组件。

    另外一个限制就是这种refresh的表格不建议再加什么按钮呀edit呀,因为它一直会在变,基本主要就是用来做一个单纯用来显示用的表格,比如一些经常变化的数据,访问人次,股票动态之类的。

    使用:

    // 启动表格demo的自动刷新功能,500毫秒一次
    
    tablePlug.refresh('demo', 500);
    
    // 取消表格demo的自动刷新
    
    tablePlug.refresh('demo', false);
    
    // 停止所有已开启自动刷新的表格的自动刷新
    
    tablePlug.refresh(false);
    
    展开全文
  • 《别说你懂Excel:500招玩转Excel表格数据处理》按照“学以致用”的原则,力求解决用户使用Excel遇到的各种疑难问题,以及传授提高工作效率的相关经验与技巧。 全书共分为18章,由浅入深,全面地讲解了Excel...
  • 《别说你懂Excel:500招玩转Excel表格数据处理》按照“学以致用”的原则,力求解决用户使用Excel遇到的各种疑难问题,以及传授提高工作效率的相关经验与技巧。 全书共分为18章,由浅入深,全面地讲解了Excel...
  • 表格数据变更,一般包括几个内容:新增、修改、删除、移动,开发经常会面临的一个问题就是变更之后如何将数据同步到节点上,一直以来个人的建议还是利用表格重载,不管是url模式的还是data模式的实际都是需要重载...

    本篇文章为大家提供了一种表格数据变更的处理方式,有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。

    表格数据变更,一般包括几个内容:新增、修改、删除、移动,开发中经常会面临的一个问题就是变更之后如何将数据同步到节点上,一直以来个人的建议还是利用表格重载,不管是url模式的还是data模式的实际都是需要重载,url重载自然会重新请求后台得到最新的数据,data模式一般就是对data的操作,之后重新以新的data去渲染出来。

    同时会考虑的是如何尽量减少请求,可能感受最深的就是update操作,为了要更新这一条记录而重载整个表格,请求一遍数据感觉划不来,那么一般来说就可以利用表格的tool事件中的obj.update这个方法去更新。

    不过具体使用中就会发现其诸多的不足的地方,本文就是主要针对这些不足进行一个处理给出一个tablePlug.update的方法,然后进而衍生出add和remove和move,同时新增了更新统计行数据的方法。

    一、update

    正如上面说的obj.update(data)有诸多限制,优点上来说就是用最小的修改代价,实现了数据的更新,他就更新参数中的data中的键的数据,不会整个行更不会整个table的节点更新;缺陷是底层的实现逻辑有点问题:

    1、是通过遍历data,更新缓存cache中对应的记录的key的value,然后根据cols的配置信息更新td的内容,但是如果是想要更新toolbar列的话就没戏,目前解析的只有templet的,所以如果想要更新toolbar的话基本就只能设置成templet,而且要给这个列添加一个field,才有理论上的可能。

    2、toolbar列即使加了field改成templet也未必能更新过来,因为内部的实现逻辑是先判断原始的data是否有这个key,所以如果field命名是原始的data里面没有的,后面用obj.update也更新不进去的,这个是一个比较大的限制。

    因为拿我们项目来说,后台给我们的数据如果原始的记录里面没有这个key的值他不会给一个key: ''的,那么后面要想利用obj.update这个key就变得不可能,除非利用parseData在渲染之前对后台给的数据做一个人工的初始化把对应的key添加上,但是可想而知有多麻烦。

    3、数据他是一个一个更新进去,然后更新一个值就更新对应的td,但是这个就存在另外一个风险了,就是遍历对象他是无序的,比如update{a: 1, b:2},如果a字段的cols中会用到b字段的值做一个处理再显示出来。

    那么如果遍历顺序是先更新a的值,然后就开始更新a的td的内容,这个时候cache中b的值还是旧的不是你要更新进去的2,等到更新了b字段了他又不能说检测到其他字段有使用了这个字段会去再次更新对方的内容,这就导致了a出来的结果还是错的。

    4、更新了统计列的某一个值统计行的对应数据没有重新计算。

    总结的来说就是,obj.update实现的还是太过理想化太过简单,一条记录从数据上来说每个key是独立的这个没什么问题,但是到页面显示就不然了,因为页面的内容它不一直是单个字段的简单值显示,还会进行一些特殊处理。

    所以需要一个templet来转化,来自定义,所以有可能一个td里面会用到多个字段这个很正常,工具列的按钮也会根据数据的状态去决定部分按钮是否显示等等。

    所以个人认为要更新这个数据不能是一个独立的小单元的更新,而是先update这一行的数据然后在update这一行,而不是遍历被update的key一个个更新,再往大了看,实际这个表的记录也是一个整体。

    也是不能说你改了这条记录其他的记录必定是不变的,不排除某个字段的td他会根据当前页面的同一个field做了什么处理现实,比如统计行,所以目前的思路就是直接将值先update到cache中,然后再调用table内部的渲染tr td的内容。

    大致的代码:

    前面是针对参数做了一些处理让参数更加灵活,最关键的是后半部分的更新cache的部分,还要一个最关键的renderData的方法:

    他的作用就是将cache中的数据重新解析渲染一遍,同时针对是否是移动数据还有默认点击那一条记录的处理,但是核心是渲染cache,调用table.js内部的renderData。

    使用场景:

    1、知道当前编辑修改的是那一条记录,可以看看一个最常用的场景就是点击编辑弹出一个form然后修改提交,完成之后希望尽量不要重新请求接口更新到data和页面中去,

    gif很不好录,自己使用测试的例子里面的编辑按钮测试效果即可

    调用的更新数据的形式是:tablePlug.update(表格实例的id, 当前tr的index, newData)

    2、不知道当前的trIndex的情况下update某一条记录的话,必须有一个限制就是必须是有主键的表格,并且更新的数据中必须包含主键的字段,不然你也不知道更新的到底是哪条记录。tablePlug.update('demo', {id: 10002, username: '贤心'});

    3、一次性更新多条记录,这个参数trIndex就没有意义了,加了也没用,因为是更新多条记录,所以可以这么写tablePlug.update('demo', [

    {id: 10002, username: '贤心'},

    {id: 10006, username: '小偷', age: 18, sign: '大叔'}

    ]);

    这个测试页面可以看看头部toolbar中的“积分清零”还有“女性积分加100”这两个测试按钮以及背后的事件执行的方法

    4、更加任性的,只要传入一个tableId,update会将当前按照cache中的数据给渲染一次,这个是非常实用的,比如如果你觉得我update中的逻辑针参数对cache的修改的逻辑不满意可以自己用自己觉得更好的方法去处理cache,最后执行一下tablePlug.update('demo')就好了,提供更高的自由度,和拓展的可能性。

    二、addData

    addData添加的记录是已经请求接口完成返回的数据记录,本质上来说就是不一样的,所以不要混淆。

    具体addData的代码:

    data模式的话,实际也是往data里面添加一些记录,然后也是再reload一下。// 添加单条记录:

    tablePlug.addData ('demo', {id: newId, username: '甲'});

    // 添加多条记录

    tablePlug.addData ('demo', [{id: newId1, username: '乙'},{id: newId2, username: '丙'}]);

    关于addData的有一个比较综合的例子可以看看利用table的data模式怎么跟流加载配合使用,弄成一个流加载的表格

    三、del

    新增和删除实际个人建议还是reload比较稳妥,不管是url还是data模式都是,所以删除对应的处理方式也跟新增实际差不多,只不过删除麻烦一点的就是data模式要在原始的记录里面去删除指定的记录。

    而且有可能开启了复选的状态记忆删除了就要将关于他的状态给调整一下;还是为了使用更方便,参数同样做了处理,

    1、删除指定的下标的数据,可以查看表格行的toolbar中的删除按钮的监听处理,但是注意,如果表格是url的模式,目前测试页面写的都是json文件,所以reload也不会有效果的。

    所以要测试请在data模式的测试,不用纠结这个,url的如果是实际的服务接口的话是后台返回数据,一般删除成功了后面查询是不会再出来的,除非后台接口有问题。

    2,删除指定的一些记录,这个一般有两种形式,但是要求一样就是必须是有主键的表格// id集合

    tablePlug.del('demo', [1,2,3,4]);

    // 对象数组

    tablePlug.del('demo', [{id: 1, name: 'name1'}, {id:2}, {id:4}]);

    根据得到哪种数据比较方便就用哪种形式,可以参考测试页面的批量删除的处理方式

    四、move

    这个处理基本跟update差不多,将数据在cache中调整位置,然后调用一下组件内部的renderData的方法让他重新渲染出来就好

    然后为了使用方便衍生出来一个上移跟下移的方法

    效果

    理论上利用一些拖拽事件或者其他的插件在事件中调用一下tablePlug.move('demo', form, to);就能够实现顺序的任意改变了限制:注意!这个只是针对数据移动,不会有单条数据记录的变动,如果原始的数据里面有点击了排序,那么移动之后默认是会去掉这个排序的状态了的,因为移动之后很可能就不能满足当前的排序规则了,所以建议在使用移动的时候不要跟sort搭配,如果有sort而且所谓的移动是会发起请求改变数据的,那么这个建议还是使用请求接口得到两个新的数据然后用update去更新他们的位置。

    五、renderTotal

    在记录更新之后,如果存在统计行有需要统计的列,那么值一般也要跟着变,另外一个更加重要的作用就是可以自定义统计规则,而不是自带的求和,可以自定一定计算的函数,或者可以直接类似templet一样的去自定义返回的内容,包括异步的去读取想要显示的数据。

    代码大概如下:

    从实现代码可以看出就是给cols的字段配置新增一个totalFormat的设置,可以设置一个规则如果不设置的话就是sum(目前也只是添加了sum,其他的规则后面会加入或者自己加入,比如平均。

    最大最小不过个人觉得主要意义是可以自定义方法,这个才是实用常用的),也可以设置一个方法,如果不是异步的可以直接把结果返回,如果是需要异步的那么也可以在得到最终想要的结果的时候执行:tablePlug.renderTotal(tableId, field, res);

    比如下面的:

    平时实用的话不是都要自己去调用的,在插件内部已经在renderDone回调里面会去执行他了:

    参数也是比较自由,不同的组合会有不同的效果,// 触发更新某个表格的所有列的统计数据

    renderTotal(tableId);

    // 触发更新某个表格的某个字段的数据

    renderTotal(tableId, fieldName);

    // 更新某个表格的某个字段的统计数据为value

    renderTotal(tableId, fieldName, totalValue);

    六、refresh

    之前做过一个智能reload的修改,即在执行table.reload的时候会根据传过去的option来判断只是重新请求数据还是需要重载一下,个人觉得效果可以了。

    不过对于有强迫症(有追求)的小伙伴来说,在一些场景下还是不够好,就是那些定时刷新的,表现就是一方面滚动条会回到top:0,left:0,还有其他的比如鼠标在操作分页组件的时候会觉得失去焦点,新增一个tablePlug.refresh来试一试能否满足要求。

    先看效果:

    事件背后做的事情:

    表格config:

    背后的实现思路

    修改table的Class.prototype.pullData支持refresh模式

    renderData的时候根据是否refresh去做一些细节的处理,还有一个限定就是返回的数据中关于总数应该是不变的,如果发生了改变,那么还是会renderData,会重新渲染page组件。

    另外一个限制就是这种refresh的表格不建议再加什么按钮呀edit呀,因为它一直会在变,基本主要就是用来做一个单纯用来显示用的表格,比如一些经常变化的数据,访问人次,股票动态之类的。

    使用:// 启动表格demo的自动刷新功能,500毫秒一次

    tablePlug.refresh('demo', 500);

    // 取消表格demo的自动刷新

    tablePlug.refresh('demo', false);

    // 停止所有已开启自动刷新的表格的自动刷新

    tablePlug.refresh(false);

    更多web前端开发知识,请查阅 HTML中文网 !!

    展开全文
  • 如何识别图片表格数据

    万次阅读 多人点赞 2018-12-24 10:34:44
      很多时候,我们的数据来源形式是多种多样的,有时候数据(或表格)也会呈现图片。那么,我们如何来获取图片的有用数据呢?当一张图片含有表格数据的时候,我们可以用OpenCV识别表格中的直线,然后再用...

      在很多时候,我们的数据来源形式是多种多样的,有时候数据(或表格)也会呈现在图片中。那么,我们如何来获取图片中的有用数据呢?当一张图片中含有表格数据的时候,我们可以用OpenCV识别表格中的直线,然后再用OCR技术识别其中的文字。
      本文仅作为如何识别图片中的表格的一个例子,希望能给读者一些启示。笔者用到的工具如下:

    • opencv
    • pyteressact
    • numpy

    我们用opencv来识别表格中的直线,用pyteressact来识别单元格文字,用numpy做数值处理。我们要识别的示例图片(AI.png)如下:

    示例图片 AI.png

    我们分以下几步进行识别:

    1. 识别表格中的横线,即分割记录(每一行)的横线;
    2. 识别表格中的竖线,即每个列的分割线;
    3. 找到数据所在的单元格;
    4. 利用pyteressact识别单元格的文字。

    识别表格中的横线

      识别横线之前,我们先创建一个图片表格识别类(ImageTableOCR),如下:

    # -*- coding: utf-8 -*-
    import cv2
    import pytesseract
    import numpy as np
    
    class ImageTableOCR(object):
    
        # 初始化
        def __init__(self, ImagePath):
            # 读取图片
            self.image = cv2.imread(ImagePath, 1)
            # 把图片转换为灰度模式
            self.gray = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY)
    

    其中self.image为RGB模块的图片,self.gray为灰度模式的图片。
      接下来,我们识别图片中的分割两条记录的横线。注意到,相邻两条记录之间的颜色是不一致的,因此,我们利用图片灰度化后,每一行像素的平均值的差的绝对值来作为相邻两条记录的分割线,这样就能检测出分割两条记录的横线了。具体的识别横线的函数的Python代码如下:(接以上代码)

        # 横向直线检测
        def HorizontalLineDetect(self):
    
            # 图像二值化
            ret, thresh1 = cv2.threshold(self.gray, 240, 255, cv2.THRESH_BINARY)
            # 进行两次中值滤波
            blur = cv2.medianBlur(thresh1, 3)  # 模板大小3*3
            blur = cv2.medianBlur(blur, 3)  # 模板大小3*3
    
            h, w = self.gray.shape
    
            # 横向直线列表
            horizontal_lines = []
            for i in range(h - 1):
                # 找到两条记录的分隔线段,以相邻两行的平均像素差大于120为标准
                if abs(np.mean(blur[i, :]) - np.mean(blur[i + 1, :])) > 120:
                    # 在图像上绘制线段
                    horizontal_lines.append([0, i, w, i])
                    cv2.line(self.image, (0, i), (w, i), (0, 255, 0), 2)
    
            horizontal_lines = horizontal_lines[1:]
            # print(horizontal_lines)
            return horizontal_lines
    

    首先对图片进行二值化处理,再进行两次中值滤波,这样是为了使相邻两条记录之间的像素区别尽可能大。然后对该图片中的每一行的像素进行检测, 以相邻两行的平均像素差大于120为标准, 识别出分割两条记录的横线。识别后的横线如下:(图片中的绿色线段)

    识别横线后的图片

    识别表格中的竖线

      在这一步中,我们利用opencv中的Hough直线检测方法来检测图片中的竖线。完整的Python代码如下:(接以上代码)

        #  纵向直线检测
        def VerticalLineDetect(self):
            # Canny边缘检测
            edges = cv2.Canny(self.gray, 30, 240)
    
            # Hough直线检测
            minLineLength = 500
            maxLineGap = 30
            lines = cv2.HoughLinesP(edges, 1, np.pi/180, 100, minLineLength, maxLineGap).tolist()
            lines.append([[13, 937, 13, 102]])
            lines.append([[756, 937, 756, 102]])
            sorted_lines = sorted(lines, key=lambda x: x[0])
    
            # 纵向直线列表
            vertical_lines = []
            for line in sorted_lines:
                for x1, y1, x2, y2 in line:
                    # 在图片上绘制纵向直线
                    if x1 == x2:
                        print(line)
                        vertical_lines.append((x1, y1, x2, y2))
                        cv2.line(self.image, (x1, y1), (x2, y2), (0, 0, 255), 2)
    
            return vertical_lines
    

    首先我们对灰度图片进行Canny边缘检测,在此基础上再利用Hough直线检测方法识别图片中的直线,要求识别的最大间距为30,线段长度最小为500,并且为竖直直线(x1 == x2),当然,也有一些人为的因素,那就是笔者自己添加了两条竖直直线([[13, 937, 13, 102]],[[756, 937, 756, 102]])。运行上述方法,输出的结果如下:

    [[13, 937, 13, 102]]
    [[75, 937, 75, 102]]
    [[77, 937, 77, 102]]
    [[270, 937, 270, 104]]
    [[272, 937, 272, 102]]
    [[756, 937, 756, 102]]

    识别竖直直线后的图片如下:(图片中的红色线段)

    识别竖线后的图片

    可以看到,图片六条竖直的线段都已经完整标记出来了。

    识别图片中的单元格

      在识别图片中的单元格之前,我们先来识别每个单元格所在的顶点,也就是上述识别后的横线与竖线的交点。完整的Python代码如下:(接以上代码)

        # 顶点检测
        def VertexDetect(self):
            vertical_lines = self.VerticalLineDetect()
            horizontal_lines = self.HorizontalLineDetect()
    
            # 顶点列表
            vertex = []
            for v_line in vertical_lines:
                for h_line in horizontal_lines:
                    vertex.append((v_line[0], h_line[1]))
    
            #print(vertex)
    
            # 绘制顶点
            for point in vertex:
                cv2.circle(self.image, point, 1, (255, 0, 0), 2)
    
            return vertex
    

    顶点检测后的图片如下:(图片中的蓝色点即为每个单元格的顶点)

    顶点检测后的图片

    由此可见,我们识别出来的单元格的顶点是正确的。接着,我们把这些单元格取出来,代码如下:(接以上代码)

    # 寻找单元格区域
        def CellDetect(self):
            vertical_lines = self.VerticalLineDetect()
            horizontal_lines = self.HorizontalLineDetect()
    
            # 顶点列表
            rects = []
            for i in range(0, len(vertical_lines) - 1, 2):
                for j in range(len(horizontal_lines) - 1):
                    rects.append((vertical_lines[i][0], horizontal_lines[j][1], \
                                  vertical_lines[i + 1][0], horizontal_lines[j + 1][1]))
    
            # print(rects)
            return rects
    

    以第一个单元格为例,其图像如下:

    第一个单元格的图片

    识别单元格的文字

      在识别出图片中表格的单元格后,我们可以对该单元格图片进行文字识别,我们使用的OCR工具为Teressact, 其Python的接口为pyteressact 。具体的Python代码如下:(接以上代码)

    # 识别单元格中的文字
        def OCR(self):
            rects = self.CellDetect()
            thresh = self.gray
    
            # 特殊字符列表
            special_char_list = ' `~!@#$%^&*()-_=+[]{}|\\;:‘’,。《》/?ˇ'
            for i in range(20):
                rect1 = rects[i]
                DetectImage1 = thresh[rect1[1]:rect1[3], rect1[0]:rect1[2]]
    
                # Tesseract所在的路径
                pytesseract.pytesseract.tesseract_cmd = 'C://Program Files (x86)/Tesseract-OCR/tesseract.exe'
                # 识别数字(每行第一列)
                text1 = pytesseract.image_to_string(DetectImage1, config="--psm 10")
                print(text1, end='-->')
    
                # 识别汉字(每行第二列)
                rect2 = rects[i+20]
                DetectImage2 = thresh[rect2[1]:rect2[3], rect2[0]:rect2[2]]
                text2 = pytesseract.image_to_string(DetectImage2, config='--psm 7', lang='chi_sim')
                text2 = ''.join([char for char in text2 if char not in special_char_list])
                print(text2, end='-->')
    
                # 识别汉字(每行第三列)
                rect3 = rects[i+40]
                DetectImage3 = thresh[rect3[1]:rect3[3], rect3[0]:rect3[2]]
                text3 = pytesseract.image_to_string(DetectImage3, config='--psm 7', lang='chi_sim')
                text3 = ''.join([char for char in text3 if char not in special_char_list])
                print(text3)
    

    识别后的结果如下:

    I–>度一–>开放的人一智能服务平台
    2–>肌讯–>互联网综合服务
    3–>标为–>人一智能自动化业务、智能屹片
    4–>阿里巴巴–>互联网综合服务
    5–>平安集口–>人T智能金融研发平仄
    6–>华大基因–>精准检测、医疗数据运营服务
    d–>搜狗–>综合人T智能解决方案平台
    8–>一科大讯飞–>智能语音技术
    9–>一中利创汤–>智能终端平台技术
    10–>珍山集团–>SaaS级智能营销云平台
    i–>商汤科技–>人工智能视觉深度学习平台
    12–>神州泰岳–>综合类软件产品及服务
    13–>寒武红科技–>深度学对专用的智能盂片
    14–>汉王科技–>文字识别技术与智能交工
    15–>全志刑技–>智能芯片设计
    16–>face旷视科技–>人T智能产品和行业解夷方案
    17–>创略科技–>智能客户数据平台
    18–>海云数据–>企业级大数据整体运营与分析服务
    19–>影渭科技–>视觉技术、智能影像生产企业
    20–>智蹈智能–>智能机器人技术提供和平台运萧

    下面,我们来统计一下识别的准确率。在原来的表格中,一共是20个数字加上280个汉字(包括标点)加上10个英语字母(包括标点),对于识别的结果,其中数字类识别正确17个,汉字正确256个,英语字母8个,因此,总的识别的准确率为90.6% ,识别的结果还是可以的。

    总结

      本文仅作为如何识别图片中的表格的一个例子,希望能给读者一些启示。对于不同的图片表格,需要具体问题具体分析。
      虽然笔者尽可能把整个过程写得简单明了,但其中的探索过程却是很复杂的。而且值得注意的是,在本文中的检测横线的方法仅适用于相邻两条记录有颜色差别的表格图片。
      完整的Python代码如下,希望能给大家一些思考。

    # -*- coding: utf-8 -*-
    import cv2
    import pytesseract
    import numpy as np
    
    class ImageTableOCR(object):
    
        # 初始化
        def __init__(self, ImagePath):
            # 读取图片
            self.image = cv2.imread(ImagePath, 1)
            # 把图片转换为灰度模式
            self.gray = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY)
    
        # 横向直线检测
        def HorizontalLineDetect(self):
    
            # 图像二值化
            ret, thresh1 = cv2.threshold(self.gray, 240, 255, cv2.THRESH_BINARY)
            # 进行两次中值滤波
            blur = cv2.medianBlur(thresh1, 3)  # 模板大小3*3
            blur = cv2.medianBlur(blur, 3)  # 模板大小3*3
    
            h, w = self.gray.shape
    
            # 横向直线列表
            horizontal_lines = []
            for i in range(h - 1):
                # 找到两条记录的分隔线段,以相邻两行的平均像素差大于120为标准
                if abs(np.mean(blur[i, :]) - np.mean(blur[i + 1, :])) > 120:
                    # 在图像上绘制线段
                    horizontal_lines.append([0, i, w, i])
                    # cv2.line(self.image, (0, i), (w, i), (0, 255, 0), 2)
    
            horizontal_lines = horizontal_lines[1:]
            # print(horizontal_lines)
            return horizontal_lines
    
        #  纵向直线检测
        def VerticalLineDetect(self):
            # Canny边缘检测
            edges = cv2.Canny(self.gray, 30, 240)
    
            # Hough直线检测
            minLineLength = 500
            maxLineGap = 30
            lines = cv2.HoughLinesP(edges, 1, np.pi/180, 100, minLineLength, maxLineGap).tolist()
            lines.append([[13, 937, 13, 102]])
            lines.append([[756, 937, 756, 102]])
            sorted_lines = sorted(lines, key=lambda x: x[0])
    
            # 纵向直线列表
            vertical_lines = []
            for line in sorted_lines:
                for x1, y1, x2, y2 in line:
                    # 在图片上绘制纵向直线
                    if x1 == x2:
                        # print(line)
                        vertical_lines.append((x1, y1, x2, y2))
                        # cv2.line(self.image, (x1, y1), (x2, y2), (0, 0, 255), 2)
    
            return vertical_lines
    
        # 顶点检测
        def VertexDetect(self):
            vertical_lines = self.VerticalLineDetect()
            horizontal_lines = self.HorizontalLineDetect()
    
            # 顶点列表
            vertex = []
            for v_line in vertical_lines:
                for h_line in horizontal_lines:
                    vertex.append((v_line[0], h_line[1]))
    
            #print(vertex)
    
            # 绘制顶点
            for point in vertex:
                cv2.circle(self.image, point, 1, (255, 0, 0), 2)
    
            return vertex
    
        # 寻找单元格区域
        def CellDetect(self):
            vertical_lines = self.VerticalLineDetect()
            horizontal_lines = self.HorizontalLineDetect()
    
            # 顶点列表
            rects = []
            for i in range(0, len(vertical_lines) - 1, 2):
                for j in range(len(horizontal_lines) - 1):
                    rects.append((vertical_lines[i][0], horizontal_lines[j][1], \
                                  vertical_lines[i + 1][0], horizontal_lines[j + 1][1]))
    
            # print(rects)
            return rects
    
        # 识别单元格中的文字
        def OCR(self):
            rects = self.CellDetect()
            thresh = self.gray
    
            # 特殊字符列表
            special_char_list = ' `~!@#$%^&*()-_=+[]{}|\\;:‘’,。《》/?ˇ'
            for i in range(20):
                rect1 = rects[i]
                DetectImage1 = thresh[rect1[1]:rect1[3], rect1[0]:rect1[2]]
    
                # Tesseract所在的路径
                pytesseract.pytesseract.tesseract_cmd = 'C://Program Files (x86)/Tesseract-OCR/tesseract.exe'
                # 识别数字(每行第一列)
                text1 = pytesseract.image_to_string(DetectImage1, config="--psm 10")
                print(text1, end='-->')
    
                # 识别汉字(每行第二列)
                rect2 = rects[i+20]
                DetectImage2 = thresh[rect2[1]:rect2[3], rect2[0]:rect2[2]]
                text2 = pytesseract.image_to_string(DetectImage2, config='--psm 7', lang='chi_sim')
                text2 = ''.join([char for char in text2 if char not in special_char_list])
                print(text2, end='-->')
    
                # 识别汉字(每行第三列)
                rect3 = rects[i+40]
                DetectImage3 = thresh[rect3[1]:rect3[3], rect3[0]:rect3[2]]
                text3 = pytesseract.image_to_string(DetectImage3, config='--psm 7', lang='chi_sim')
                text3 = ''.join([char for char in text3 if char not in special_char_list])
                print(text3)
    
        # 显示图像
        def ShowImage(self):
            cv2.imshow('AI', self.image)
            cv2.waitKey(0)
            # cv2.imwrite('E://Horizontal.png', self.image)
    
    ImagePath = 'E://AI.png'
    imageOCR = ImageTableOCR(ImagePath)
    imageOCR.OCR()
    

    注意:本人现已开通微信公众号: Python爬虫与算法(微信号为:easy_web_scrape), 欢迎大家关注哦~~

    展开全文
  • 介绍一个用Python对Excel表格数据进行去重、分类、异常处理及分析的实例。
  • layUI数据表格和弹出层综合案例

    千次阅读 2019-10-04 16:34:03
    数据表格+弹出层的综合案例【重点】 json准备 { "code": 0, "msg": "", "count": 101, "data": [ { "id": "10001", "username"...
  • html中表格table的内容居中显示

    万次阅读 2018-11-06 18:16:17
    html中表格table的内容居中显示
  • 用OpenCV和OCR识别图片表格数据

    千次阅读 2019-03-24 21:00:00
    ♚作者:jclian,喜欢算法,热爱分享,希望能结交更多志同道合的朋友,一起学习Python的道路上走得更远!  很多时候,我们的数据来源形式是多种多样的,有时候数...
  • 本文从三篇表格识别领域的精选论文出发,深入分析了深度学习在表格识别任务的应用。 表格识别是文档分析与识别领域的一个重要分支,其具体目标是从表格中获取和访问数据及其它有效信息。众所周知,本质上表格是...
  •   很多时候,我们的数据来源形式是多种多样的,有时候数据(或表格)也会呈现图片。那么,我们如何来获取图片的有用数据呢?当一张图片含有表格数据的时候,我们可以用OpenCV识别表格中的直线,然后再用...
  • Python 与 Excel 表格综合实例(一):给表格增加序号,根据表格已有内容增加索引前言:需求一:增加序列号需求二:按已有内容新增列结尾: 前言: 前面我们花了6篇博客,把Python的xlwt与xlrd两个第三方模块对Excel...
  • 用Qt的模型视图实现数据库的基本操作,增删改查,是练习Qt数据库、模型视图、布局的一个综合实例
  • 智能制造数据分析综合应用方案

    千次阅读 2021-12-06 14:25:15
    智能制造数据分析综合应用方案 最全智能制造数字化应用方案 智能制造数字化应用全...电子看板大屏系统广泛应用于各种行业的生产制造企业,可以自动将生产数据、质量数据、异常信息等车间生产信息自动实时显示在车间
  • latex 表格中单元格换行,显示多行

    千次阅读 2016-07-16 19:58:06
    除了使用multirow的方式(比较麻烦),更好地办法是用下面的语句,可以使得一个单元格中显示多行,再配合其它格式语句,就能使得表格非常美观。\newcommand{\tabincell}[2]{\begin{tabular}{@{}#1@{}}#2\end{tabular...
  • JSP分页显示数据

    万次阅读 多人点赞 2017-01-20 16:35:09
    最近做一个小程序,用到了JSP的分页。虽然只是最简单的分页,但是还是花了我不少时间。这看似简单的功能,实现起来还是稍微有点麻烦。实现分页功能,需要知道数据的总个数,每页应该有多少条数据,以及当前页码。...
  • python修改docx文档的表格内中文字体

    千次阅读 2020-10-01 22:07:42
    from docx import Document from docx.enum.text import WD_PARAGRAPH_ALIGNMENT...#读取文档的第一个表格数据 tables = document.tables[0] #第该表格3行1列的单元格内输入“能几日又中秋?as12A” run = tables.c.
  • Python -- 爬虫中国大学排行榜并将数据存储到表格

    千次阅读 热门讨论 2021-06-19 22:58:06
    1. 爬虫中国大学排行榜并将数据存储到表格 爬取网站:2021中国大学排名1200强【完整版】 完整代码:(这里给出完整的代码只是为了方便大家理解下面具体的步骤,请不要盲目的抄袭代码,重要的是掌握知识,谢谢了。) ...
  • 计算机日常办公综合应用

    千次阅读 2021-07-02 14:21:14
    计算机日常办公综合应用摘要:计算机的应用以及遍布到各个行业,成为日常工作、生活、学习的必备工具,尤其日常办公。本文通过办公软件具体工作实践的应用,分析了计算机软件的简单应用及它的强大...
  • 前言 软科中国大学排名以专业、客观、透明的优势赢得了高等教育领域和社会的广泛关注和认可,本次将利用Python对我国大学...csv_writer = csv.DictWriter(f, fieldnames=['名次', '学校名称', '综合得分', '星级排名'
  • 表格以简洁明了和高效快捷的方式将图片、文本、数据和表单的元素有序地显示在页面上,从而设计出漂亮的页面。 这里先弄清一个概念且熟记:什么是行?是什么是列? 常用表格标记及说明: 表格由表头<thead>...
  • SQL查询单表数据(一)

    万次阅读 多人点赞 2020-02-17 21:21:48
    SQL ,字符 “*” 具有特殊的含义,使用用它,将从指定的表返回每一列,这里由于没有使用 where 子句,所以将会返回每一行,即是 查询表所有的行与列,就是所有的数据 。 还有一种写法就是分别列出每一列...
  • 可以处理Excel数据、公式、样式,在表格里面插入图表等 pip install openpyxl -i https://pypi.tuna.tsinghua.edu.cn/simple windows系统下使用此条指令进行第三方库的安装省时间,Mac端直接使用pip3 insta...
  • 使用cSS美化表格和表单元素 网页中表格的应用无处不在,HTML,最 初希望用于纯数据,却发展为基本页面布局子语言 但是Web标准,正在渐渐地恢复表格原来的用 途,即只用来显示表格数据如今,表格已经成为 可视化...
  • 数据库, 数据仓库, 数据集市,数据湖,数据中

    万次阅读 多人点赞 2019-02-22 16:21:47
    数据仓库和数据集市的区别 作者:修鹏李 出处:CSDN 大数据:数据仓库和数据库的区别 作者:南宫蓉 出处:简书 第一篇:数据仓库概述 第二篇:数据库关系建模 作者:穆晨 出处:CNBLOS 摘要 本文简要介绍...
  • 作为一个学习用Python进行数据分析的新手来说,通过本文来记录分享一些我用Python的pandas、numpy来分析Excel表中数据数据清洗和整理的工作,目的是熟悉numpy以及pandas基础操作,所有操作利用Excel均可以方便...
  • Python 与 Excel 表格综合实例:处理校运会报名 Excel 表格,多表整合、数据汇总及统计实例前言:需求:主要思路及实现代码:1、先获取目标文件路径下的所有Excel文件:2、读取所有Excel表格数据:3、按需求汇总数据...
  • 物联网-传输课程设计-数据采集与显示

    千次阅读 多人点赞 2020-06-12 15:24:51
    步骤说明一、环境准备(1)Arduino、ESP8266 Node MCU的开发环境搭建(没有单片机就略过)(2)JDK、Eclipse、Tomcat插件的环境搭建(3)SQL Server的环境搭建二、数据采集1.(第一种方式)单片机采集数据2.(第二...
  • 本文代码实现基本按照《数据结构》课本目录顺序,外加大量的复杂算法实现,一篇文章足够。能换你一个收藏了吧?

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 28,873
精华内容 11,549
关键字:

在表格中如何显示数据综合