万象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.

相关推荐
tiantian_cool15 分钟前
HarmonyOS 开发环境配置指南 - macOS 版
前端
写不来代码的草莓熊35 分钟前
vue前端面试题——记录一次面试当中遇到的题(10)
前端·vue.js·面试
web守墓人35 分钟前
【go语言】gopls工具与LSP协议全面解析
excel
tiantian_cool41 分钟前
正确的 .gitignore 配置
前端·github
三小河43 分钟前
封装 classNames:让 Tailwindcss 类名处理更优雅
前端·javascript
起这个名字1 小时前
ESLint 导入语句的分组排序
前端·javascript
踩着两条虫1 小时前
VTJ.PRO低代码快速入门指南
前端·低代码
Lazy_zheng1 小时前
一场“数据海啸”,让我重新认识了 requestAnimationFrame
前端·javascript·vue.js
crary,记忆1 小时前
MFE: React + Angular 混合demo
前端·javascript·学习·react.js·angular·angular.js
Asort1 小时前
JavaScript设计模式(十七)——中介者模式 (Mediator):解耦复杂交互的艺术与实践
前端·javascript·设计模式