JavaScript数组方法综合应用案例

业务背景:
项目上有一个价格库的概念,对应于某个地区的某个时间段。即:在某年的某个季度或者月份,项目公司会对各个地区建立该地区的人工、材料、机械的价格库。
呈现视图如下:
这里写图片描述

数据库设计

对于上面的业务,由于地区和价格期数是作为字典维护的,有独立的前端模块进行维护,所以需要独立建表。
同时,出于效率方面的考虑,未采用物理外键,使用了逻辑外键,由程序全权保证业务逻辑的正确性和完整性。
最终的表结构如下图所示:
这里写图片描述

后台接口

项目采用前后端分离的结构,后台提供CRUD接口,前台进行逻辑呈现。后端采用SpringBoot构建微服务体系,前台为使用vue框架的SPA应用。
后台提供Restful API接口,并通过Swagger提供前端开发人员进行查询和联调的接口文档界面及联调工具。

地区接口

这里写图片描述

价格期数接口

这里写图片描述

价格库接口

这里写图片描述
价格库中,除了基础的增删改查接口之外,还有带字典获取列表的接口(即一个请求同时获取到价格库及地区字典、价格期数字典);另外,还有按照价格期数执行使能切换的接口。

前端呈现实现

前端呈现的一个复杂之处在于:
1. 将原本的无层级记录列表呈现为带层级的逻辑视图;
2. 一级记录为从原本记录中构造出来的交集;
3. 二级记录需要与一级记录构建层级关系;
4. 存在过滤状态(即按照关键字进行过滤的状态);

为此,作如下的处理:
1 三级请求获取数据(鉴于带字典请求数据的接口与目前的前端公共接口不兼容,因此暂时采用三级串行请求的方式):

function(currentItemId) {
        var vueObj = this;
        // 一级请求,请求价格期数数据
        periodModel().getTableDatas(function(items) {
          vueObj.periods = items;
          items.forEach(function(item) {
            vueObj.periodMap[item.id] = item.description;
          });
          // 二级请求,请求地区数据
          regionModel().getTableDatas(function(items) {
            vueObj.regions = items;
            items.forEach(function(item) {
              vueObj.regionMap[item.id] = item.description;
            });
            // 三级请求,请求价格库数据
            resPriceDBModel().getTableDatas(function(items) {
              vueObj.moving = false;
              vueObj.doFormatDisplayData(items);
              // 数据获取完成并进行修饰构造后,通过handsonTable进行呈现
              vueObj.$refs.table.$emit('show-grid', vueObj.tableData(), vueObj.fieldList, vueObj.getEditStyle, true, vueObj.getAlignment, 'all');
              vueObj.setCurrentRow(currentItemId);
            }, function(errMsg) {
              vueObj.moving = false;
              vueObj.$message({message: errMsg, type: 'error'});
            });
          }, function(errMsg) {
            vueObj.moving = false;
            vueObj.$message({message: errMsg, type: 'error'});
          });
        }, function(errMsg) {
          vueObj.moving = false;
          vueObj.$message({message: errMsg, type: 'error'});
        });
      }

2 其中,最关键的方式是doFormatDisplayData,该方法构造出最终呈现的数据视图;
算法逻辑为:
① 遍历获取到的价格库记录数组,按照需要填充前台呈现所需数据(采用数组的map方法);
② 如果处于过滤状态,则对构造后的数组执行过滤处理(采用数组的filter方法);
③ 对于构造后的数组执行排序(按照价格期数排序,采用数组的sort方法);
④ 通过构造后的数组,提取出一级记录的map(采用数组的reduce方法);
⑤ 将构造后的数据填充到handsonTable呈现对应的数组对象,对于一级记录直接压入(采用数组的push方法);
⑥ 对于二级记录,则将原数据数组进行slice处理提取出一级记录对应的子记录,然后调用forEach方法将各记录压入数组(采用数组的slice及forEach方法)。

function(items) {
        var vueObj = this;
        var keyword = vueObj.keyword;
        var datas = [];
        if (vueObj.inSearch) {
          datas = items.map(vueObj.makeupResPriceDB).filter(function(item) {
            return (item.period && item.period.indexOf(keyword) >= 0) ||
            (item.region && item.region.indexOf(keyword) >= 0) ||
            (item.auditor && item.auditor.indexOf(keyword) >= 0);
          }).sort(vueObj.doCompareResPriceDB);
        } else {
          datas = items.map(vueObj.makeupResPriceDB).sort(vueObj.doCompareResPriceDB);
        }
        var periodMap = datas.reduce(function (prevResult, currItem) {
          if (prevResult.has(currItem.period_id)) {
            prevResult.get(currItem.period_id).childCount += 1;
          } else {
            var periodObj = vueObj.makeupParentPeriodRec(currItem.period_id, currItem.enabled);
            prevResult.set(currItem.period_id, periodObj);
          }
          return prevResult;
        }, new Map());
        dataStore[vueObj._uid].tableData = [];
        var startIndex = 0;
        for (var value of periodMap.values()) {
          dataStore[vueObj._uid].tableData.push(value);
          datas.slice(startIndex, startIndex + value.childCount).forEach(function(data) {
            dataStore[vueObj._uid].tableData.push(data);
          });
          startIndex += value.childCount;
        }
      }

如上可知,该部分视图的构造逻辑还是有一些复杂的,其中综合运用了数组的各个方法,也算是对于JS数组的一次学习应用了。

JS数组方法总结

XMind总结数组方法,如下三张图:
这里写图片描述
这里写图片描述
这里写图片描述

猜你喜欢

转载自blog.csdn.net/achang07/article/details/79266831