• 使用FineUIGrid控件实现购物车功能时遇到的问题
  • 发布于 2个月前
  • 205 热度
    0 评论
  • Zappos
  • 18 粉丝 35 篇博客
  •   
昨天使用FineUIGrid写了一个购物车,主要是改变数量和单价计算总价的功能,纯前端。在实现时遇到了坑,解决后使用了闭包的结构优化,这里推演下应用的过程。

1. 代码概览
首先购物车需要两个列,数量和单价,可以编辑,这里使用了 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">`;
}
/**
 * 堆代码 duidaima.com
 * 新增方法
 * @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);
}

2. 问题

熟悉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();
}
3. 优化
这时让我别扭的地方来了,我最讨厌割裂,明显 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);
  }
}

用户评论