普通视图

发现新文章,点击刷新页面。
今天 — 2026年2月12日首页

Vue3文本差异对比器实现方案

作者 滕青山
2026年2月12日 11:00

Vue3文本差异对比器实现方案

本文将介绍本项目中 文本差异对比器 (Text Diff Checker) 工具的技术实现细节。该工具基于 Vue 3 框架开发,核心对比逻辑采用原生的 JavaScript 实现,通过动态加载的方式与 Vue 组件进行交互。

在线工具网址:see-tool.com/diff-checke…
工具截图:
在这里插入图片描述

1. 架构设计

为了保证核心算法的独立性和复用性,我们将 Diff 算法逻辑封装在 public/js/diff-checker.js 中,而 Vue 组件 pages/diff-checker.vue 仅负责 UI 交互和数据展示。

  • 数据层 (Core JS): 负责文本的预处理、Diff 算法计算、HTML 渲染字符串生成以及统计信息计算。
  • 视图层 (Vue): 负责用户输入、选项配置、调用核心方法并展示结果。

2. 核心算法实现 (diff-checker.js)

核心逻辑是一个基于 最长公共子序列 (LCS, Longest Common Subsequence) 的 Diff 算法。

2.1 文本预处理与并在

根据用户选择的“对比模式”,我们将输入文本分割成不同的单元:

  • 行模式 (Line): 使用 split('\n') 按换行符分割。
  • 词模式 (Word): 使用 split(/\s+/) 按空白字符分割。
  • 字符模式 (Char): 使用 split('') 逐字符分割。

同时,根据配置选项处理“忽略空格”和“忽略大小写”:

if (ignoreWhitespace) {
    processedText1 = processedText1.replace(/\s+/g, ' ').trim();
    processedText2 = processedText2.replace(/\s+/g, ' ').trim();
}
// 忽略大小写则统一转为小写

2.2 LCS 算法与回溯

使用动态规划构建 DP 表,计算最长公共子序列的长度:

// DP 表构建
for (let i = 1; i <= m; i++) {
    for (let j = 1; j <= n; j++) {
        if (arr1[i - 1] === arr2[j - 1]) {
            dp[i][j] = dp[i - 1][j - 1] + 1;
        } else {
            dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
        }
    }
}

构建完成后,通过回溯 (Backtrack) 找出具体的 LCS 路径。

2.3 构建 Diff 结果

根据 LCS 路径,遍历原始序列,确定哪些部分是“新增 (added)”、“删除 (removed)”或“未变 (unchanged)”。

  • 如果当前元素在 LCS 中,标记为 unchanged
  • 如果原序列中有但 LCS 中没有,标记为 removed
  • 如果新序列中有但 LCS 中没有,标记为 added

2.4 结果渲染

为了提高性能,Diff 的结果直接由 JS 生成 HTML 字符串,而不是在 Vue 中使用 v-for 渲染成千上万个 DOM 节点。生成的 HTML 包含了行号、差异标识(+/-)以及高亮样式类。

/* 生成的 HTML 结构示例 */
<div class="diff-line diff-line-removed">
  <span class="diff-line-number">1</span>
  <span class="diff-line-number"></span>
  <span class="mr-2">-</span>
  Content
</div>

3. Vue 组件实现 (diff-checker.vue)

3.1 动态加载脚本

Vue 组件在挂载或需要使用时,通过创建 <script> 标签动态加载核心 JS 文件。为了防止重复加载,我们通过检查 window.DiffChecker 是否存在来判断。

const loadDiffCheckerScript = () => {
  if (window.DiffChecker) return Promise.resolve();
  // 创建 script 标签加载 /js/diff-checker.js
  // 监听 onload 和 onerror 事件
}

3.2 调用对比

当用户点击“开始对比”时,组件收集 leftTextrightText 以及 compareModeignoreWhitespace 等选项,调用核心对象的 compare 方法:

const result = window.DiffChecker.compare(leftText.value, rightText.value, compareMode.value, {
  ignoreWhitespace: ignoreWhitespace.value,
  ignoreCase: ignoreCase.value,
  showLineNumbers: showLineNumbers.value
})

3.3 结果展示

核心方法返回的 result 对象中包含了 diffHtml(差异内容的 HTML)和 statisticsHtml(统计信息的 HTML)。Vue 组件直接使用 v-html 指令将其渲染到页面上:

<div v-if="statisticsHtml" v-html="statisticsHtml"></div>
<div ref="diffOutput" v-html="diffOutputHtml"></div>

通过这种 Vue 处理交互 + 原生 JS 处理计算密集任务的分离模式,我们既保持了前端框架的开发效率,又保证了对比功能的性能与灵活性。

昨天以前首页

Vue项目BMI计算器技术实现

作者 滕青山
2026年2月8日 00:05

BMI计算器工具开发技术实现

本文主要分享一下我最近开发的 BMI 计算器工具的技术实现细节。这个工具基于 Vue 3 和 Nuxt.js 构建,包含核心计算逻辑和交互式的用户界面。我们将重点关注其功能实现部分。

在线工具网址:see-tool.com/bmi-calcula…

工具截图: 在这里插入图片描述

项目结构

这个工具的实现主要分为两个部分:

  1. 逻辑层utils/bmi-calculator.js —— 负责核心的 BMI 数值计算和状态判定。
  2. 视图层pages/bmi-calculator.vue —— 负责用户交互、输入验证和结果展示。

1. 核心计算逻辑

计算逻辑封装在 calculateBmi 函数中。它接收用户的身高(cm)和体重(kg)作为输入,返回计算后的 BMI 值以及对应的身体状态类别和健康风险等级。

1.1 输入验证

在进行计算之前,我们需要确保输入的数据是有效的数值且大于 0。如果输入无效,函数会抛出一个错误,以便前端捕获处理。

  const height = Number(heightCm)
  const weight = Number(weightKg)

  if (!Number.isFinite(height) || !Number.isFinite(weight) || height <= 0 || weight <= 0) {
    throw new Error('INVALID_INPUT')
  }

1.2 BMI 计算公式

BMI 的计算公式是:体重(公斤)除以身高(米)的平方。

  const heightInMeters = height / 100
  // 体重 / (身高^2)
  const bmiRaw = weight / (heightInMeters * heightInMeters)
  // 保留一位小数
  const bmi = Number(bmiRaw.toFixed(1))

1.3 状态判定

根据计算出的 BMI 值,我们可以判定用户的身体状态。这里我们参照了常见的 BMI 标准进行分类:

  • BMI < 18.5: 偏瘦(Underweight),存在营养不良风险。
  • 18.5 ≤ BMI < 24: 正常(Normal),健康风险低。
  • 24 ≤ BMI < 28: 超重(Overweight),通过轻度风险。
  • BMI ≥ 28: 肥胖(Obese),存在较高健康风险。
  if (bmi < 18.5) {
    return { bmi, categoryKey: 'underweight', riskKey: 'malnutrition' }
  }
  if (bmi < 24) {
    return { bmi, categoryKey: 'normal', riskKey: 'low' }
  }
  if (bmi < 28) {
    return { bmi, categoryKey: 'overweight', riskKey: 'mild' }
  }
  return { bmi, categoryKey: 'obese', riskKey: 'high' }

2. Vue 页面实现

页面组件主要由输入表单和结果展示两大部分组成。使用 Vue 3 的 Composition API (<script setup>) 来管理状态和逻辑。

2.1 状态管理

我们使用 ref 来定义响应式变量,用于存储用户的输入和计算结果。

const heightCm = ref('')  // 用户输入的身高
const weightKg = ref('')  // 用户输入的体重
const result = ref(null)  // 用于存储计算结果对象,初始为 null

2.2 用户交互处理

计算操作

当用户点击“计算”按钮或在体重输入框按下回车时,会触发 handleCalculate 方法。

该方法首先调用核心计算函数 calculateBmi。如果计算成功,将结果赋值给 result,页面会自动渲染结果区域;如果捕获到错误(如输入无效),则会提示用户。

const handleCalculate = () => {
  try {
    // 调用工具函数进行计算
    const r = calculateBmi(Number(heightCm.value), Number(weightKg.value))
    result.value = r
  } catch (e) {
    // 计算失败,清空结果并提示错误
    result.value = null
    safeMessage('error', '请输入有效的身高和体重')
  }
}
加载示例

为了方便用户快速体验,我们提供了一个 loadExample 方法,一键填入预设的示例数据并触发计算。

const loadExample = () => {
  heightCm.value = '170'
  weightKg.value = '65'
  handleCalculate()
}
清空重置

clearForm 方法用于重置所有输入和结果,让用户可以重新开始。

const clearForm = () => {
  heightCm.value = ''
  weightKg.value = ''
  result.value = null
}

2.3 结果动态展示

在模板中,我们使用 v-if="result" 来控制结果卡片的显示。只有当 result 有值时,结果区域才会渲染。这种设计保证了页面初始状态的整洁。

结果卡片通过 grid 布局展示了三个关键信息:BMI 数值、身体状态和健康风险。这些信息都直接来自于 result 对象。

<div v-if="result" class="...">
  <!-- BMI 数值 -->
  <p>{{ result.bmi }}</p>
  
  <!-- 身体状态分类 -->
  <p>{{ t(`bmiCalculator.result.categoryMap.${result.categoryKey}`) }}</p>
  
  <!-- 健康风险评估 -->
  <p>{{ t(`bmiCalculator.result.riskMap.${result.riskKey}`) }}</p>
</div>

通过将计算逻辑与界面展示分离,我们保持了代码的清晰和可维护性。Vue 强大的响应式系统让我们能够轻松地通过改变数据状态来驱动界面的更新。

❌
❌