首页 > 其他分享 >查询模块数据流优化

查询模块数据流优化

时间:2022-10-28 21:58:41浏览次数:81  
标签:key paramsChanges 查询 参数 模块 params 数据流 query 路由

简介

上一篇介绍的查询模块数据流发现了一些问题:https://www.cnblogs.com/cjc-0313/p/16810460.html

  • 当用户没有操作视图,而是通过路由前后跳转时,并不会触发视图层数据的更新,因此需要调整部分数据流向
  • 路由参数和 API 参数的生成过程存在重复,需要合并;这是由一开始对生成过程的权责分配不清而导致的逻辑混乱

优化版

先上图:

与旧版相比,本此优化主要调整了“视图层 —— 路由 —— 本地数据 —— API 参数”四者之间的数据流向,不影响 API 层与服务器之间的交互。虚线部分仍是不需要处理路由参数变化时的数据流向

这是旧版的数据流向:

上图与示例代码其实有些区别,代码中是从视图层获取数据后保存到本地的同时重新生成路由参数,并不是从本地数据获取更新并生成路由参数。

而新版中改为:用户操作使得参数发生变化时,在事件处理其中只将更新值传给路由对象,而本地数据变量是从路由对象获取更新后的值,以便更新视图上的数据;同时,仍是通过监听路由的变化,自动触发生成新的 API 参数并调用相关接口。API 参数这里可以根据需要,更换成自动从路由对象获取新的值,或者像这里介绍的一样,在路由对象的侦听器中更新。这里采用在侦听器中更新的主要的目的是通过同步模式确保 API 参数能在发送请求前完成,因为 vue 的计算属性生成新的 API 参数并不能保证在侦听器之前执行完毕(注意是完毕,也就是生成了完整的新参数,而不是开始执行生成过程)。

示例代码

由于调整了数据流向,因此涉及到上述四部分的代码都需要调整。同时,将公共方法提取到外部,通过 mixins 导入方便复用。

searchParamsMixins.js(核心)

import isObjEmpty from '@/utils/utils/isObjEmpty';

const searchParamsMixins = {
    methods: {
        //#region 工具 --
        // params 或 query 对象可能有属性,但值为空,所以还需要额外判断
        isEmpty(obj) {
            return isObjEmpty(obj);
        },
        //#endregion --

        //#region 路由参数处理 --
        // 用户操作视图后,调用事件处理器方法,获取更新
        // 将更新的内容以特定格式传入处理方法,转化为新的路由参数对象,并 push 到路由器对象
        // watch 侦听路由对象,一旦改变,立即获取路由中的参数,自动生成 API 参数并请求服务器

        /* 参数示例:
         * 全保留 { queryChanges: 'allReserve', paramsChanges: 'allReserve' }
         * 只保留 query 或 只保留 params,保留的给一个 'allReserve',清空的给 undefined 或不给
         * 全清空 {}
         * 对 query 或 params 单独增、删、改,保留的参数给一个 'allReserve',要增加的参数的属性直接给值,删除的给 undefined,修改的也是直接给值
         */

        /**
         * 
         * @param {从路由对象获取旧的参数} oldParams
         * @param {根据用户输入,生成参数的更新值(不是完整的新参数)} paramsChanges
         * @param {参数的默认值,可选} defaultParams
         * @returns 返回更新后的完整 query 或 params 对象,用于路由显示参数
         */
        handleUpdateParams(oldParams, paramsChanges, defaultParams = {}) {
            let newParams = {}; // paramsChanges === undefined
            if (paramsChanges === 'allReserve') {
                newParams = oldParams;
            } else if (!this.isEmpty(paramsChanges)) {
                for (const key in paramsChanges) {
                    // 将同名参数重置为初始值
                    if (Object.hasOwnProperty.call(paramsChanges, key)) {
                        if (
                            Object.hasOwnProperty.call(oldParams, key) &&
                            paramsChanges[key] === undefined
                        )
                            newParams[key] = defaultParams?.[key]
                                ? defaultParams[key]
                                : undefined;
                        else {
                            newParams[key] = paramsChanges[key];
                        }
                    }
                }
            }
            return newParams;
        },
        /**
         * 
         * @param {查询组件在 router 中定义的 name} SearchRouterCompoName 
         * @param {$route 对象中 query 和 params 对象的属性的变化} changes 
         */
        handleUpdateRouteParams(SearchRouterCompoName, { queryChanges, paramsChanges }) {
            if (SearchRouterCompoName) {
                let location = { name: SearchRouterCompoName };
                let newQuery = this.handleUpdateParams(this.$route.query, queryChanges),
                    newParams = this.handleUpdateParams(this.$route.params, paramsChanges);
                if (!this.isEmpty(newQuery)) location.query = newQuery;
                if (!this.isEmpty(newParams)) location.params = newParams;
                this.$router.push(location);
            }
        },
        //#endregion --

        //#region 生成请求参数 --
        // 为了确保在请求之前获取到最新的路由参数,此处通过方法在请求函数前同步执行,而不是通过计算属性获取
        setupSearchParams(route) {
            return Object.assign({}, route.params, route.query);
        },
        //#endregion --
    }
}

export default searchParamsMixins;

isObjEmpty.js

import { isEmpty } from 'lodash'

function isObjEmpty(obj) {
    if (isEmpty(obj)) return true;
    // lodash.isEmpty 无法排除对象有属性,但属性值为空的情况
    for (const key in obj) {
        if (Object.hasOwnProperty.call(obj, key)) {
            if (obj[key]) return false;
        }
    }
    return true;
}

export default isObjEmpty;

业务组件中使用

将定义好的方法作为业务组件的 mixins,然后在本地重新包装一个传入查询组件 name 值的方法。

对于用户操作后从视图层返回的数据,在本地的事件处理方法中,仅将更新作为参数传递给 handleSearchParamsChaned 方法。

import searchParamsMixins from '@/utils/mixins/searchParams';

...
  mixins: [searchParamsMixins],
...

  methods: {
    // 从外部混入,本地只包装一个传入路由组件名称的方法
    handleUpdateRoute(changes) {
      this.handleUpdateRouteParams('Search', changes);
    },
    // 增加或修改 query 参数;params 同理
    handleUpdateCurrentName(name) {
      this.handleUpdateRoute({
        queryChanges: { name: name},
        paramsChanges: 'allReserve', // 由于只有 query 的变化,params 的属性全部保留
      });
    },
    // 更新数组类型的参数
    handleUpdateCurrentTags(tagId, tagValue) {
      const oldTags = this.$route.query.tags;
      let newTags = oldTags instanceof Array ? [].concat(oldTags ) : [];
      const findIdx = this.oldTags.findIndex(oldTagVal => oldTagVal === tagValue);
      if (findIdx > -1) {
        newTags [findIdx ] = tagValue;
      } else {
        newTags .push(tagValue);
      }
      this.handleUpdateRoute({
        queryChanges: { newTags },
        paramsChanges: 'allReserve',
      });
    },
    // 显示全部结果(无参查询)
    handleGetAllResult() {
      this.handleUpdateRoute({});
    },
  },
...

考虑到参数的变化规则不可穷举,因此将变化的处理过程放在通用方法之外,由业务组件负责。通常会放在事件的 handler 中,或者多处 handler 存在相同变化的,可以抽象为单独的函数,但仍然是在业务组件之中。

总结

本次升级主要是解决了开头提到的两个问题,让数据流向的规则更加简化,通过降低模块的重复与耦合来提升模块协作能力,提高程序的复用性和稳定性,更加方便开发和调试,略微加深了对于软件分层、逻辑复用、权责分配等方面的理解。

标签:key,paramsChanges,查询,参数,模块,params,数据流,query,路由
From: https://www.cnblogs.com/cjc-0313/p/16837624.html

相关文章

  • 第三方模块,hashlib,subprocess,logging
    hashlib加密模块#1.加密就是把明文数据变为密文#2.加密的目的是为了保证数据的安全#3.加密后的数据是一串没有规律的字符串#4.加密后的密文越长说明使用的加密算......
  • JavaScript--原型及模块入门
    面向对象回顾核心概念:万物皆对象(顶层对象Object)抽取行为作为方法抽取名词作为属性俩种构建对象的方式构造函数构建es6的形式classclassPerson{ constructor(){/......
  • wireshark 跟踪数据流
     过滤ip地址:ip.addr==192.168.1.1//只显示IP为192.168.1.1的数据包notip.src==192.168.1.1//不显示源ip为192.168.1.1的数据包过滤端口:tcp.port==80......
  • MSSQL三表/两表联合查询
    两张表的联合查询语句select* from User101219_Expandinnerjoin  user_101445onUser101219_Expand.userid=user_101445.userid 三表联合查询语句select* f......
  • 树状结构查询报错Error querying database. Cause: java.sql.SQLSyntaxErrorException
    Errorqueryingdatabase.Cause:java.sql.SQLSyntaxErrorException:Unknowncolumn...报这个错一般出现在新增字段或者修改字段,以及操作连表的时候1.可能左链接或内......
  • 关于VM系列振弦传感器测量模块 固件版本SF3.50相较于SF3.33的新特性说明
    测频性能提升微弱信号增强,进一步增强了微弱信号的识别和处理算法。增加辅助测频,在不改变以往固件使用的前提下,利用预置噪声、特征频率模型及过滤算法SFC(SmartFrequencyC......
  • 企业库5.0——参数化查询、带有事务的参数化查询
    SqlDatabasem_db=DatabaseFactory.CreateDatabase("数据库连接串配置节名");///<summary>///执行带有查询参数的sql语句,返回受影响行数///</summary>......
  • ESP8266 WIFI 模块
    发送“AT”(AT指令集后要换行),AT+RST复位一下模块配置ESP8266的工作模式为sta,输入AT+CWMODE=1AT+CWLAP扫描附近的无线AT+CWJAP="CIMS-GUEST","a1b2c3d4e5f6"AT+CWQAP......
  • sql查询语句典例整理
    简单查询:1、SELECT*FROM表名称WHERE字段名LIKE'查询内容'1)、SELECT*FROMmemberWHERENickNameLIKE'贝克汉姆':查询member表NickName字段值为'贝克汉姆'数......
  • 智慧矿山无人驾驶模块_DW狂奔的小熊猫的博客
    先看效果图实现步骤获取点在​​editHelper​​中获取运动的路线获取的路线数据如下://移动线路const__gps_pos:any=[[[-810.738647,717.010071,-59.492......