layui之关于表格数据变更的一种处理方式

表格数据变更,一般包括几个内容:新增、修改、删除、移动,开发中经常会面临的一个问题就是变更之后如何将数据同步到节点上,一直以来个人的建议还是利用表格重载,不管是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的内容。

大致的代码:

1.png

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

2.png

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

使用场景:

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

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

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

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

3.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的代码:

5.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}]);

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

7.png

四、move

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

8.png

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

9.png

效果

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

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

五、renderTotal

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

代码大概如下:

10.png

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

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

tablePlug.renderTotal(tableId, field, res);

比如下面的:

11.png

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

12.png

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

// 触发更新某个表格的所有列的统计数据
renderTotal(tableId);
// 触发更新某个表格的某个字段的数据
renderTotal(tableId, fieldName);
// 更新某个表格的某个字段的统计数据为value
renderTotal(tableId, fieldName, totalValue);

六、refresh

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

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

先看效果:

2.gif事件背后做的事情:

13.png

表格config:

14.png

背后的实现思路

15.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);

推荐文章
浅谈layui表单中的inline和block

layui表单中的inline和block:block:block元素会独自占一行,多个block元素各自新起一行,默认情况下,block元素宽度自动填充其父元素宽度 单行输入框 验证必填项

laypage组件常见用法总结

laypage的使用非常简单,指向一个用于存放分页的容器,通过服务端得到一些初始值,即可完成分页渲染。核心方法:laypage.render(options)来设置基础参数。一、laypage的常用基

浅谈Layui的时间选择框

Layui中时间格式的输入框:html代码: 选择日期: -- - js代码:layui.use(['layer','form','table','laydate'],function()

怎么修改layui提示样式?

一直以来都认为layui挺好看的,包括它的弹层组件layer,不过今天恰好碰到了layui表单验证弹框的位置和样式不能调整的问题;它的默认样式是这样的:因为我页面布局的关系,弹框挡住了按钮,所以我决定

Django+Layui学习之浅谈后台布局

前言Layui对于没有太多前端基础的我来说,第一次接触还是有点困难,不过文档还算详细,摸索着的逐渐的了解了,这次来说下后台布局。Layui后台布局:一、后台布局之顶边栏 layui后台布局 控制台

浅谈layui中iframe跳转链接和页面按钮跳转相关问题

一、导航跳转iframe页面问题:关于layui的iframe嵌套页面的导航跳转页面问题,如下图所示可以看到效果:在模板页的导航代码: 所有商品 商品列表 商品属性 商品分类 添加 解决方案

layui怎么隐藏表格行?

layui数据表格隐藏列在使用layui做数据表格的时候,插入的数据的id是不是一组连续的数字,那么就需要用到layui的cols的type属性。table.render({ elem:'#test'

浅谈layui数据表格隐藏列的方法

在使用layui做数据表格的时候,插入的数据的id是不是一组连续的数字,那么就需要用到layui的cols的type属性。table.render({ elem:'#test' ,url:'${pag

layui如何清除表单数据?

layui清空表单数据的方法:1、调用reset()方法清空functionfomrReset() { document.getElementById("myform").reset(); }2、使用

layui怎么固定表格的表头?

步骤:1、设置两个table,第一个table有thead没有tbody,第二个table有tbody没有table;2、第二个table需要一个div包住,并设置宽高,可用绝对布局3、tr下的th和

详解layui.layer独立组件

layer至今仍作为layui的代表作,她的受众广泛并非偶然,而是这五年多的坚持,不断完善和维护、不断建设和提升社区服务,使得猿们纷纷自发传播,乃至于成为今天的Layui最强劲的源动力。目前,laye

layui中的layer怎么进行宽高设置?

layui中的layer模块可以使用area设置宽高。类型:String/Array,默认:'auto'在默认状态下,layer是宽高都自适应的,但当你只想定义宽度时,你可以area:'500px',

layui动态表格之合并单元格

需求:下面用excel表格大概模拟下需求,左边是原来的,要改成右边这样的:①第一步:再生成表格后调用此方法,以合并重复的单元格done:function(res,curr,count){ merge(

layui和easyui的区别是什么?

layuilayui是一款采用自身模块规范编写的前端UI框架,它遵循原生的HTML/CSS/JS书写方式。它虽然外在极简,但是内容丰富,里面包含众多组件从核心代码到API都非常适合界面的快速开发。事实

layui如何支持 es5 写法?方法介绍

写js的时候会写一些es5的代码,但是打包到dist时,发现不支持语法,怎么办呢。两步添加es5支持:一、使用npm下载安装babel,进入gulpfile.js所在目录。$npminstall--s

layui如何实现下载功能?

layui实现下载功能的方法:a标签中的href属性可以直接给下载链接的地址,点击的时候会自动跳出下载保存窗口。用原生上传文件标签上传文件,获取上传文件的全路径:$('#file').change(f

layui时间控件清空之后无法正常使用怎么办?

解决layui时间控件清空之后无法正常使用的问题,以及时间范围的选择。共有两种解决方式:方式一(layui1.x):html代码: js代码:varstart={ istime:tru

浅谈layui弹出层(open)的属性

layui.open属性如:打开一个弹出层核心方法varindex=layer.open({ type:2, title:title, maxmin:true, offset:'100px', are

layui调用弹层的方法

两种调用方法:1、引用独立的layer.js文件引入好layer.js后,直接用即可 layer.msg('hello'); 2、调用layui中的layer模块layui.use('layer',

详解layui模块化与非模块化的不同引用方式

layui模块化与非模块化的不同引用方式:1、模块化与非模块化的区别layui中有许多不同的内置模块,如弹出层、日期与时间选择器、分页等不同模块。模块化:使用时加载相应的模块。非模块化:一次性加载所有