昨天使用FineUIGrid写了一个购物车,主要是改变数量和单价计算总价的功能,纯前端。在实现时遇到了坑,解决后使用了闭包的结构优化,这里推演下应用的过程
首先购物车需要两个列,数量和单价,可以编辑,这里使用了 RendererFunction
进行绘制,绘制函数就是返回个 input
标签
购物车的项需要新增和删除,这里对应两个方法 adddata
和 removedata
,在修改数据后需要计算合计价格:updateTotal
,所以有代码如下,这里抽象一下,细节不重要
/**绘制输入数量*/ const renderNumber = function(v, { rowId, rowValue }, m, g){ return `<input id="Number_${rowId}" value="${v}" class="number" style="width:98%;" type="text">`; }
/** * 新增方法 * @param {[MsINVMB]} values 新增的数据数组 */ function adddata(values){ F.ui.Grid1.addNewRecords(data, true); //更新总价 updateTotal(); }
/** * 删除方法 * @param {ID} rowId 删除的ID */ function removedata(rowId){ F.ui.Grid1.deleteRow(rowId, true); //更新总价 updateTotal(); }
/** * 更新总价 */ function updateTotal(){ //计算总价 let res = GetSummary(); //更新总价 F.ui.Grid1.setSummaryData(res); }
熟悉FineUI前端的能感觉到坑来了,调用过 addNewRecords
或 deleteRow
的同学都知道,这两个方法会重绘Grid,即触发 renderNumber
函数,造成输入的值会被重置,比如我在某行的数量输入了2,然后新增了一行,执行 addNewRecords
,然后输入的2没了,成默认项了,这时总价也不对了;这里不讨论为什么会触发绘制,对外可能是逆天的,但是对内是自洽的;
最直接的解决方法就是在 新增 或 删除 行之前先得到录入的值,执行新增后再给赋上,然后计算总价;所以多了两个方法 GetInputVal
和 SetInputVal
,改造如下;
/** * 新增方法 * @param {[MsINVMB]} values 新增的数据数组 */ function adddata(values){ let rawvalue = GetInputVal(); F.ui.Grid1.addNewRecords(data, true); SetInputVal(rawvalue); //更新总价 updateTotal(); } /** * 删除方法 * @param {ID} rowId 删除的ID */ function removedata(rowId){ let rawvalue = GetInputVal(); F.ui.Grid1.deleteRow(rowId, true); SetInputVal(rawvalue); //更新总价 updateTotal(); }
这时让我别扭的地方来了,我最讨厌割裂,明显 GetInputVal
和 SetInputVal
是一对,在调用时中间间隔其他的逻辑,而且他俩本身不参与其他逻辑,SetInputVal
只接收 GetInputVal
返回的值,rawvalue
外露没有意义还有可能被篡改,所以我感觉他俩应该是一个函数,为什么方法我还要写两个,我能不能塞到一个函数里,并且中间还可以跨其他的逻辑;
/**得到值*/ function GetInputVal(){} /**设置值*/ function SetInputVal(values){}
这个场景下,我想到了使用闭包的方式,有一个函数 RestoreInputVal
,如果要跨过其他逻辑,这个函数返回的应该是 SetInputVal
的实现而不是调用,它应该这么写
/**还原值*/ function RestoreInputVal(){ const GetInputVal = ()=>...; const SetInputVal = (values)=>...; let rawvalue = GetInputVal(); return ()=>{ SetInputVal(rawvalue); }; }
用的时候像这样
/** * 新增方法 * @param {[MsINVMB]} values 新增的数据数组 */ function adddata(values){ let restorval = RestoreInputVal(); F.ui.Grid1.addNewRecords(data, true); restorval(); //更新总价 updateTotal(); } /** * 删除方法 * @param {ID} rowId 删除的ID */ function removedata(rowId){ let restorval = RestoreInputVal(); F.ui.Grid1.deleteRow(rowId, true); restorval(); //更新总价 updateTotal(); }
这样就实现了 rawvalue
的闭包,以此作为一个典型的应用案例
其实要按照面向对象的思路应该是一个 class ,这里也不考虑继承扩展,所以就不深入了
class InputRestore { #rawValue; constructor() { this.#rawValue = this.#getInputValue(); } #getInputValue() { // 原逻辑 } #setInputValue(value) { // 原逻辑 } restore() { this.#setInputValue(this.#rawValue); } }
本文作者:没想好
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!