aop 实现 layui table edit 新增功能

分享 已结 置顶 精帖 68 6962
单身狗278
单身狗278 2020-5-14
悬赏:20飞吻
一、概述

edit新增的功能是基于lay-event事件进行的aop增强实现的,因此在cols配置的属性中务必开启lay-event点击事件!由于在table.on('tool(yyy)',function (obj) {})方法基础上进行的aop代理而产生的AopEvent代理对象,因此此代理对象的on方法与table的on('tool(yyy)')方法使用方式是一致的,即table的on('tool(yyy)')方法里的回调函数可以作为代理对象的on方法的回调函数。因此使用者可以按照之前的代码格式编写代码,而不用担心代理对象内部发生了何种复杂的代码实现,以及layui table源码发生变化也不会导致组件的不可用或者需要对组件进行相应的修改(零入侵table源码)。----拿来即用

新增的功能
1、下拉框(单或多选)
2、日期选择框
3、下拉框联动(下拉框联动下拉框、日期框联动下拉框)
4、输入框(该输入框与官网的不一致,失去焦点事件会对table.on('tool(lay-filter)',function(obj){})进行回调)

lay-event开启例子
table.render({cols:[[{field:'name',title: '姓名',width:120,event:'name'}]]}); //开启event功能
二、问题

用官方模板实现的表格下拉框存在以下问题:
1、下拉框数据过多时,表格产生很长的滚动条
2、无关键词模糊搜索出相应的下拉数据
3、数据过多时,下拉框被表头所遮住,修改表格的样式会出现其他的bug
4、无法实现复杂操作(下拉框单多选和级联可配置等)
5、有部分表格下拉框组件还是比较优秀的,但是也还是无法解决以上所有的问题,或者解决了80%,但入侵layui table的源码过重,不利于使用与维护
6、无法与layui table的事件进行整合

用data-edit(cols中edit属性)实现的日期选择框存在以下问题:
1、只有输入框值改变时才触发的table.on('edit(lay-filter)',function(obj){})方法的回调,因此用户体验较差

三、解决方案

思路:单元格点击事件(可以是自定义事件) => 生成自定义的输入框(input) => 在当前窗口body元素生成最后一个div子元素(下拉框) => 给input注册值改变事件用于关键词搜索
=> 给div注册点击事件用于数据选择及相对应的事件回调

方案一
table表格渲染完成后,在done方法中自定义单元格事件。此方案能完成80%的功能,但因无法与layui table的事件进行整合,使用起来较为复杂。

方案二
在table.on('tool(yyy)',function (obj) {})方法回调的事件中,根据当前单元格(this)进行动态生成下拉框或者日期选择框。此方案已解决了所有的问题,但对使用者对layui table组件的熟练度有一定要求(从部分后端猿咨询中可知)。

方案三
在方案二的基础上对table.on('tool(yyy)',function (obj) {})中的方法进行aop代理增强,实现0入侵layui table源码无缝整合。此方案为最终的方案。

三、最简洁的栗子

引入组件
    layui.config({
base: 'module/'
}).extend({
tableEdit:'js/tableEdit'
}).use(['table','tableEdit'], function () {
var table = layui.table,tableEdit = layui.tableEdit;
});
完整栗子
<table class="layui-hide" id="tableId" lay-filter="tableEvent"></table>
<script>
layui.config({
base: 'module/'
}).extend({
tableEdit:'js/tableEdit'
}).use(['table','tableEdit','layer'], function () {
var table = layui.table,tableEdit = layui.tableEdit,$ = layui.$;
var params = [{name:1,value:"张三1"},{name:2,value:"张三2"},{name:3,value:"张三3"},{name:4,value:"张三4"},{name:5,value:"张三5"}];
var cols = table.render({
elem: '#tableId'
,id:'id'
,url:'module/json/data.json'
,height: 'full-90'
,page: true
,cols: [[
{type:'checkbox'}
//type的类型值:select(下拉框)date(时间选择框)input(输入框)
//input为输入框,失去焦点会触发回调,aopTable.on()中触发的回调
,{field:'name',title: '输入框',width:120,event:'name',config:{type:'input'}}
//data 为下拉框数据
,{field:'danxuan',align:'center', title: '单选',width:120,event:'danxuan',config:{type:'select',data:params},templet:function (d) {
return d.danxuan && d.danxuan.value ? d.danxuan.value : '';
}}
// enabled => true:多选,false:单选。默认为false
,{field:'duoxuan', title: '多选',width:120,event:'duoxuan',config:{type:'select',data:params,enabled:true},templet:function (d) {
var str = [];
d.duoxuan.forEach(function (e) {
str.push(e.value)
});
return str.join(' || ');
}}
//dateType表示日期时间格式,date为“yyyy-MM-dd”,datetime为“yyyy-MM-dd HH:ss:mm”
,{field:'birthday', title: '生日',width:120,event:'birthday',config:{type:'date',dateType:'date'}}
//cascadeSelectField字段为级联开关字段(存在该字段则级联,否则不级联)
,{field:'xlkjl', title: '下拉框联动(上级)',width:150,event:'xlkjl',config:{type:'select',data:params,cascadeSelectField:'xialaxiaji'},templet:function (d) {
return d.xlkjl && d.xlkjl.value ? d.xlkjl.value : '';
}}
,{field:'xialaxiaji', title: '下拉框联动(下级)',width:150,event:'xiaji',config:{type:'select',data:params},templet:function (d) {
return d.xialaxiaji && d.xialaxiaji.value ? d.xialaxiaji.value : '';
}}
,{field:'rqjl', title: '日期联动(上级)',width:150,event:'rqjl',config:{type:'date',dateType:'date',cascadeSelectField:'rqxiaji'}}
,{field:'rqxiaji', title: '日期框联动(下级)',width:150,event:'rqxiaji',config:{type:'select',data:params},templet:function (d) {
return d.rqxiaji && d.rqxiaji.value ? d.rqxiaji.value : '';
}}
]]
}).config.cols;

/**
* 参数cols是table.render({})中的cols属性值
* aop代理是基于event点击事件进行操作的,因此cols中务必开启event点击事件!
**/
var aopTable = tableEdit.aopObj(cols); //获取一个aop对象
/**
* 注意:
* 1、 aopTable.on('tool(xxx)',function (obj) {})
* 2、 table.on('tool(yyy)',function (obj) {})
* 如果1中的xxx与2中的yyy字符串相同时,不能同时用,用了会造成后调用者覆盖前调用者。
* 应该直接用1来代替2,因为1中包含了2中的事件。
* 如果不相同,则可以同时使用。
**/
aopTable.on('tool(tableEvent)',function (obj) {
var field = obj.field; //单元格字段
var value = obj.value; //修改后的值
var data = obj.data; //当前行旧数据
var event = obj.event; //当前单元格事件属性值
var update = {};
update[field] = value;
//把value更新到行中
obj.update(update);
/**
*说白了,此obj与table.on('tool(tableEvent)',function (obj) {})
*中的obj对象是同一个,所以可以如此操作。
*
* */
});


/**
* 级联下拉框 => 点击事件生成下拉框之前的回调函数
* 主要用于 => 动态获取单元格下拉数据
* tableEvent => table的lay-filter属性值
* 如示例代码所示
*/
tableEdit.on('clickBefore(tableEvent)',function (obj) {
var cascadeSelectData = obj.data; //级联数据
var cascadeSelectField = obj.field; //级联字段
if(Array.isArray(cascadeSelectData)){
cascadeSelectData = cascadeSelectData[0];
}
var reslut = null;
//下拉数据 只可ajax同步请求后台
if(cascadeSelectField === 'rqjl'){ //日期级联下拉框
if(cascadeSelectData === '2020-05-11'){
reslut = {
data:[{name:1,value:'语文'},{name:2,value:'数学'},{name:3,value:'英语'},{name:4,value:'物理'},{name:5,value:'化学'}],
enabled:false //单选 true为多选
};
}else {
reslut = {
data:[{name:6,value:'政治'},{name:7,value:'地理'},{name:8,value:'历史'},{name:9,value:'生物'},{name:10,value:'音乐'}],
enabled:false //单选 true为多选
};
}
}else {
if(cascadeSelectData.name+'' === '1'){
reslut = {
data:[{name:11,value:'贵州'},{name:12,value:'云南'},{name:13,value:'四川'},{name:14,value:'湖南'}],
enabled:false //单选 true为多选
};
}else {
reslut = {
data:[{name:15,value:'荆州'},{name:16,value:'扬州'},{name:17,value:'杭州'},{name:18,value:'苏州'}],
enabled:false //单选 true为多选
};
}
}
return reslut;
});
});
</script>
效果图

单选下拉框


多选下拉框


日期选择框


下拉框级联下拉框


日期选择框级联下拉框


麻烦的gif图片终于制作完成了[嘻嘻] [哈哈]

四、总结
设计模式的应用,解决了代码的重复性问题! [嘻嘻]
一个轮子,最重要的是思路,好的思路有了,轮子就成功了90%了!

码云地址: https://gitee.com/yangqianlong98/layuiTableColumnEdit
回帖
  • 感谢分享 挺好用.
    发现个小bug

    typeof othis.selectedData === 'string' 没有判断为number的情况 导致单选选中后再次点击无法取得当前选中项
    另外 name,value 这两个参数名是不是搞反了 value是值 name是显示出来的内容才对 [微笑]
    0 回复
  • 看不太懂,但是感觉挺牛批的样子
    2 回复
  • 2 回复
  • ruike007
    2020-5-15
    牛哦,这个功能很实用
    2 回复
  • 1 回复
  • @ruike007 嘎嘎。[嘻嘻]
    1 回复
  • @Highbig上 改我的源码就能实现
    1 回复
  • @橘子男神jz 请说详细一点,这图我看不出什么来。[嘻嘻]
    0 回复
  • @落叶x name和value没有搞混,故意这样搞的!确实是没有考虑到数值类型的情况!明天改进。[哈哈]
    0 回复
  • 拖鞋a
    2020-5-15
    之前官方有 获取先中行数据,请问这个组件要怎么用呢?
    以前是
    table.on('toolbar(tableEvent)', function (obj) {
    var checkStatus = table.checkStatus('tableId');
    }
    0 回复