提供一种form组件更精准render一个节点的思路

讨论 未结
5 208
岁月小偷
悬赏:80飞吻
这个记得很久很久之前社区就有小伙伴问过,目前form.render只能render一个layui-form下面的一类或者所有类型的节点,能否精确限制到某一个节点上,比如我就修改了表单中的某一个select然而表单里面还有很多其他的select,form.render的时候把所有的都给渲染了,效率是有可以提升的空间的,当时觉得没必要那么细的粒度其实,但是实际开发中就打脸了。
效率可以提升是一方面,还有一种情况就是比如有两个select,一个是一开始就有的,一个是后面异步加进去的,用多了就知道动态修改下拉复选单选这些节点的属性都需要render一下,但是即使你写了他们所在的layui-form的lay-filter,那么它会render这个layui-form下面所有的相关类型的节点,这个时候如果你刚好打开了前面的那个select,正准备选择的时候,后面那个执行了form.render一下直接就把你当前打开的这个select也给重新渲染一遍,也就是下拉就会“关掉”,这个是很影响用户体验的。
那么解决方法其实可以给后面要异步渲染的select包在一个layui-form里面变成一个独立的小空间,加上对应的lay-filter,后面render的时候render这个小范围就好了,但是这个很显然不太方便用起来。
下面提供一种自己使用的方式,就是有技巧的重写form.render;具体看代码吧:
// 保留一下原始的form.render
var formRender = form.render;
form.render = function (type, filter, jqObj) {
var that = this;
var retObj;
if (jqObj && jqObj.length) {
layui.each(jqObj, function (index, elem) {
elem = $(elem);
var elemP = elem.parent();
var formFlag = elemP.hasClass('layui-form');
var filterTemp = elemP.attr('lay-filter');
// mark一下当前的
formFlag ? '' : elemP.addClass('layui-form');
filterTemp ? '' : elemP.attr('lay-filter', 'tablePlug_form_filter_temp_' + new Date().getTime() + '_' + Math.floor(Math.random() * 100000));
// 将焦点集中到要渲染的这个的容器上
retObj = formRender.call(that, type, elemP.attr('lay-filter'));
// 恢复现场
formFlag ? '' : elemP.removeClass('layui-form');
filterTemp ? '' : elemP.attr('lay-filter', null);
});
} else {
retObj = formRender.call(that, type, filter);
}
return retObj;
};
大概的思路:其实修改的方式跟上面说的方法差不多,只不过不需要你都自己写节点也不需要自己去写那些layui-form、lay-filter啥的,说到重写,你可能会觉得是直接修改源码或者整个逻辑都自己重新写,实际不是的,正如上面说的是有技巧的重写。
首先先把原始的方法用变量给记录起来,后面在需要的时候会用到;
然后重写form.render,实际就是给这个方法在原来两个参数的基础上加多一个第三参数,我这里用的是接收jquery对象,实际如果你要的是对应的select节点上的lay-filter也是可以的处理方式不太一样而已,这里主要是一个思路,后面可以根据自己喜欢的去调整。然后检测到有没有第三个参数,如果没有,那么就走layui提供给我们的form.render去渲染,如果有,那么就先不着急渲染,而是遍历传过来的要渲染的节点,检查一下它的容器是否加了layui-form和lay-filter,如果没有就给临时的加上去,然后再调用layui提供的那个form.render,只不过这个时候传进去的参数就不再是一开始进去这个回调的参数了而是将临时生成那个小范围的filter作为第二个参数,也就是说实际上form是如何重新渲染表单的这些我们都不用管,还是原始的form.render的逻辑去处理,只不过我们在外层又加多了一些逻辑控制。然后有一个要注意的就是要确保执行原始form.render的时候的上下文还是要保持一致,所以用了call,还有一个就是原始的return回去原始的form.render返回的对象;最后render完毕之后如果是精准的刷新,注意把现场恢复回去就好了。
使用示例:
效果图?实际也比较简单,普通情况下看不出啥就不动图了,但是理论上效率会更高的,如果要测试一下上面说的有异步的重载select的效果会不会影响一个已经打开的额,这个可以自己写个测试的例子设置一个定时器一直去刷新后面一个select,看看前面的下拉会有什么结果就好了,然后我给出的方法里面实际就是给要渲染的父节点添加临时的属性和class如果需要的话,那么会有一个漏洞就是你把select都怼在一个容器里面去,这样子本来不想render的节点就还是会被找到,当然估计这么使的人是很少的,只要确保他们的直接父亲不是同一个节点就行。
回帖