万象EXCEL开发(八)excel公式解析与依赖映射 ——东方仙盟金丹期

公式解析与依赖映射实现方案

一、公式解析函数:提取依赖项并构建 dependentsMap

针对你带左右等式、支持分号分隔多公式的格式,先实现解析函数,从公式中提取 "被依赖的 param" 和 "当前公式所属的 param",并更新到 dependentsMap。

1. 核心解析函数 parseFormulaToDependents

javascript

复制代码
/**
 * 解析带左右等式的公式,更新依赖映射表
 * @param {string} formula - 完整公式(如 "$param7=$param4*$param5+$param3-$param1;$param8=$param7/2")
 * @param {object} dependentsMap - 依赖反向映射表(需提前初始化,如 {})
 * @returns {object} 更新后的 dependentsMap
 */
function parseFormulaToDependents(formula, dependentsMap) {
  // 1. 按分号分割多公式(处理一个单元格的多重计算)
  const formulaList = formula.split(';').filter(item => item.trim() !== '');
  
  formulaList.forEach(singleFormula => {
    // 2. 分割左右等式(左侧是当前公式所属的param,右侧是计算逻辑)
    const [leftPart, rightPart] = singleFormula.split('=').map(item => item.trim());
    if (!leftPart || !rightPart) return; // 跳过格式错误的公式
    
    // 3. 提取左侧的当前param(如 "$param7" → "param7")
    const currentParam = leftPart.match(/\$(\w+)/)[1]; // 匹配 $ 后的param名称
    if (!currentParam) return;
    
    // 4. 提取右侧所有被依赖的param(如 "$param4*$param5" → ["param4", "param5"])
    const dependentParams = rightPart.match(/\$(\w+)/g) || [];
    const cleanDependents = dependentParams.map(param => param.slice(1)); // 去掉 $ 符号
    
    // 5. 更新 dependentsMap:给每个被依赖param,添加当前param到依赖列表
    cleanDependents.forEach(depParam => {
      if (!dependentsMap[depParam]) {
        dependentsMap[depParam] = []; // 初始化依赖列表
      }
      // 避免重复添加同一依赖
      if (!dependentsMap[depParam].includes(currentParam)) {
        dependentsMap[depParam].push(currentParam);
      }
    });
  });
  
  return dependentsMap;
}

2. 调用示例(用你给的公式测试)

javascript

复制代码
// 初始化依赖映射表
let dependentsMap = {};

// 你的测试公式
const testFormula = "$param7=$param4*$param5+$param3-$param1";

// 执行解析
parseFormulaToDependents(testFormula, dependentsMap);

// 解析结果:dependentsMap 变成
// {
//   param4: ["param7"],
//   param5: ["param7"],
//   param3: ["param7"],
//   param1: ["param7"]
// }
console.log(dependentsMap);

二、依赖触发函数:通过 data-key 找到依赖项并执行计算

当焦点离开 data-key="param4" 的文本框时,调用此函数,通过 data-key 从 dependentsMap 找到所有依赖它的 param,再执行你的计算逻辑(计算部分你已实现,这里只负责 "找到要计算的目标 param")。

1. 依赖触发函数 triggerDependentCalculation

javascript

复制代码
/**
 * 通过 data-key 找到依赖项,触发计算
 * @param {string} dataKey - 文本框的 data-key 值(如 "param4")
 * @param {object} dependentsMap - 已构建的依赖反向映射表
 * @param {function} calculateFunc - 你的计算函数(参数为目标param,需你实现)
 * @returns {void}
 */
function triggerDependentCalculation(dataKey, dependentsMap, calculateFunc) {
  // 1. 从 dependentsMap 中找到所有依赖当前dataKey的目标param
  const targetParams = dependentsMap[dataKey] || [];
  
  if (targetParams.length === 0) {
    console.log(`没有参数依赖 ${dataKey}`);
    return;
  }
  
  // 2. 遍历目标param,调用你的计算函数(计算逻辑由你实现)
  targetParams.forEach(targetParam => {
    console.log(`触发计算:${targetParam}`);
    calculateFunc(targetParam); // 你已实现的计算函数,传入要计算的param
  });
}

2. 调用示例(模拟焦点离开事件)

javascript

复制代码
// 1. 假设你的计算函数(示例,实际由你提供)
function myCalculateFunc(targetParam) {
  // 你的逻辑:读取 targetParam 的公式(dataset.formula)、执行计算、更新input值
  console.log(`执行计算逻辑:${targetParam}`);
}

// 2. 模拟焦点离开 data-key="param4" 的文本框
const changedDataKey = "param4"; // 从文本框的 data-key 属性获取
triggerDependentCalculation(changedDataKey, dependentsMap, myCalculateFunc);

// 执行结果:
// 触发计算:param7
// 执行计算逻辑:param7

三、整体流程梳理(和你的系统适配)

  1. 公式存储 :用户在某个单元格设置公式后,将公式存入该单元格的 dataset.formula(如 param7 的 dataset.formula 存 "\(param7=\)param4*\(param5+\)param3-$param1")。
  2. 解析公式 :调用 parseFormulaToDependents,传入公式和 dependentsMap,完成依赖关系构建。
  3. 值修改触发 :当 data-key="param4" 的文本框焦点离开时,获取 data-key 值,调用 triggerDependentCalculation,找到依赖 param4 的 param7,执行你的计算函数。

四、扩展:处理多公式场景

如果公式是多组(分号分隔),比如 $param7=$param4*$param5;$param8=$param7/2,解析后 dependentsMap 会变成:

javascript

复制代码
{
  param4: ["param7"],
  param5: ["param7"],
  param7: ["param8"]
}

此时修改 param4,会先触发 param7 计算,若你需要连动计算 param8,可在 myCalculateFunc 中递归调用 triggerDependentCalculation(计算完 param7 后,再触发它的依赖项 param8)。

需要调整解析规则或函数参数吗?比如 param 的命名规则(是否都是 $param + 数字)、多公式的分隔符等,都可以根据你的实际系统修改。

阿雪技术观

让我们积极投身于技术共享的浪潮中,不仅仅是作为受益者,更要成为贡献者。无论是分享自己的代码、撰写技术博客,还是参与开源项目的维护和改进,每一个小小的举动都可能成为推动技术进步的巨大力量

Embrace open source and sharing, witness the miracle of technological progress, and enjoy the happy times of humanity! Let's actively join the wave of technology sharing. Not only as beneficiaries, but also as contributors. Whether sharing our own code, writing technical blogs, or participating in the maintenance and improvement of open source projects, every small action may become a huge force driving technological progrss.

相关推荐
张一凡93几秒前
React 项目也能用依赖注入?我尝试了一下,真香
前端·react.js
somebody几秒前
零经验学 react 的第15天 - 过渡动画(使用 react-transition-group 库进行实现)
前端
SuperEugene15 分钟前
Vue3 + Element Plus 表单开发实战:防重复提交、校验、重置、loading 统一|表单与表格规范篇
前端·javascript·vue.js
SuperEugene17 分钟前
Vue3 + Element Plus 中后台弹窗规范:开闭、传参、回调,告别弹窗地狱|Vue 组件与模板规范篇
开发语言·前端·javascript·vue.js·前端框架
桜吹雪18 分钟前
在前端运行Qwen3.5原生多模态模型
前端·人工智能·机器学习
孟祥_成都19 分钟前
前端下午茶:这 3 个网页特效建议收藏(送源码)
前端·javascript·css
SuperEugene19 分钟前
VXE-Table 4.x 实战规范:列配置 + 合并单元格 + 虚拟滚动,避坑卡顿 / 错乱 / 合并失效|表单与表格规范篇
开发语言·前端·javascript·vue.js·前端框架·vxetable
火车叼位33 分钟前
Volta 下 `corepack` 失踪之谜:问题不在 Node,而在命令入口
前端
cmd36 分钟前
别再用错!5种JS类型判断方法,从原理到实战一文吃透
前端·javascript
小江的记录本39 分钟前
【Redis】Redis常用命令速查表(完整版)
java·前端·数据库·redis·后端·spring·缓存