vue展示修改前后对比,并显示修改标注diff
动态父组件
<template><el-buttontype="primary"size="small"plain@click="showDiffDialog(subItem)">查看修改内容</el-button><TextDiffDialogv-model:visible="diffDialogVisible":before="currentDiffItem?.before?.[currentDiffItem?.fieldName] || ''":after="currentDiffItem?.after?.[currentDiffItem?.fieldName] || ''"/></el-scrollbar>
</template><script>import TextDiffDialog from './TextDiffDialog.vue';export default {name: 'logIndex',components: { TextDiffDialog },data() {return {diffDialogVisible: false,currentDiffItem: null,};},props: {formId: String,},methods: {showDiffDialog(item) {this.currentDiffItem = item;this.diffDialogVisible = true;},},created() {},mounted() {},
};
</script><style scoped lang="scss">.el-button--small {padding: 0px 6px;height: 26px;line-height: 26px;border: 0;
}
</style>
npm install diff
//子组件
<template><el-dialogv-model="dialogVisible"title="变更对比"width="60%":before-close="handleClose"class="text-diff-dialog"><template #header><div class="diff-header"><div class="diff-title"><i class="iconfont icon-shejibiangeng"></i>变更对比</div><div class="diff-stats"><el-switch v-model="showDiff" active-text="显示修改标注" /><el-tooltipeffect="light"content="<p><span style='background: #52bd94;color: #172890;padding: 2px;border-radius: 2px;'>绿色背景</span> 表示新增</p><p><span style='background:#f4b6b6;color: #172890;padding: 2px;border-radius: 2px;'>红色背景</span> 表示删除</p>"raw-content><i style="color: #a5adba" class="el-icon-question"></i></el-tooltip></div></div></template><div class="diff-container"><div class="diff-content" ref="diffContent"><div class="diff-panel before"><div class="panel-header">修改前</div><div class="panel-content"><divv-for="(line, index) in beforeLines":key="'before-' + index"class="diff-line"><span class="line-number">{{ line.lineNumber }}</span><span class="line-content" v-html="line.content"></span></div></div></div><div class="diff-panel after"><divclass="panel-header"style="display: flex; justify-content: space-between">修改后 <span class="total">有 {{ totalChanges }} 处修改</span></div><div class="panel-content"><divv-for="(line, index) in afterLines":key="'after-' + index"class="diff-line"><span class="line-number">{{ line.lineNumber }}</span><span class="line-content" v-html="line.content"></span></div></div></div></div></div></el-dialog>
</template><script>
import { diffChars } from 'diff';export default {name: 'TextDiffDialog',props: {visible: {type: Boolean,default: false,},before: {type: String,default: '',},after: {type: String,default: '',},},data() {return {dialogVisible: false,beforeLines: [],afterLines: [],showDiff: false,totalChanges: 0,};},watch: {visible(val) {this.dialogVisible = val;if (val) {this.$nextTick(() => {this.generateDiff();});}},dialogVisible(val) {if (!val) {this.showDiff = false;this.$emit('update:visible', false);}},showDiff() {this.generateDiff();},},methods: {handleClose() {this.dialogVisible = false;},generateDiff() {const beforeText = this.before || '';const afterText = this.after || '';// 将文本分割成行const beforeLines = beforeText.split('\n');const afterLines = afterText.split('\n');this.beforeLines = beforeLines.map((line, index) => ({lineNumber: index + 1,content: this.escapeHtml(line),}));// 使用diffChars进行字符级别的差异比较const changes = diffChars(beforeText, afterText);let currentLine = '';let lineNumber = 1;this.afterLines = [];this.totalChanges = 0;changes.forEach((change) => {if (change.added) {if (this.showDiff) {currentLine += `<span class="diff-added">${this.escapeHtml(change.value)}</span>`;} else {currentLine += this.escapeHtml(change.value);}this.totalChanges++;} else if (change.removed) {if (this.showDiff) {currentLine += `<span class="diff-deleted">${this.escapeHtml(change.value)}</span>`;}this.totalChanges++;} else {currentLine += this.escapeHtml(change.value);}// 处理换行if (change.value.includes('\n')) {const lines = currentLine.split('\n');lines.forEach((line, index) => {if (index < lines.length - 1) {this.afterLines.push({lineNumber: lineNumber++,content: line,});}});currentLine = lines[lines.length - 1];}});// 添加最后一行if (currentLine) {this.afterLines.push({lineNumber: lineNumber,content: currentLine,});}},escapeHtml(text) {const div = document.createElement('div');div.textContent = text;return div.innerHTML;},},
};
</script><style lang="scss" scoped>
.text-diff-dialog {:deep(.el-dialog__body) {padding: 0;}
}.diff-container {height: 600px;display: flex;flex-direction: column;width: 100%;
}.diff-header {padding: 0 6px 6px 6px;border-bottom: 1px solid #ebeef5;display: flex;justify-content: space-between;align-items: center;
}.diff-stats {display: flex;align-items: center;gap: 6px;margin-right: 20px;
}.total {color: #6b778c !important;font-size: 13px;
}
.diff-content {flex: 1;display: flex;overflow: hidden;
}.diff-panel {flex: 1;display: flex;flex-direction: column;border-right: 1px solid #ebeef5;&:last-child {border-right: none;}.panel-header {padding: 12px 16px;background-color: #f5f7fa;border-bottom: 1px solid #ebeef5;font-weight: 500;color: #172b4d;font-size: 16px;}.panel-content {flex: 1;overflow-y: auto;padding: 16px;font-family: monospace;white-space: pre-wrap;word-break: break-all;}
}.diff-line {display: flex;line-height: 1.5;.line-number {color: #909399;text-align: right;padding-right: 8px;user-select: none;}.line-content {color: #172b4d;font-size: 14px;flex: 1;:deep(.diff-added) {background-color: #52bd94;border-radius: 2px;padding: 2px;margin-left: 2px;}:deep(.diff-deleted) {background-color: #f4b6b6;text-decoration: line-through;border-radius: 2px;padding: 2px;margin-left: 2px;}}
}
.diff-title {color: #172b4d;font-size: 16px;font-weight: 500;line-height: 24px; /* 150% */
}
</style>
相关文章:

vue展示修改前后对比,并显示修改标注diff
动态父组件 <template><el-buttontype"primary"size"small"plainclick"showDiffDialog(subItem)">查看修改内容</el-button><TextDiffDialogv-model:visible"diffDialogVisible":before"currentDiffItem?.…...

LiveWallpaperMacOS:让你的 Mac 桌面动起来
随着桌面美化需求的不断提升,用户对于桌面壁纸的要求已经不再局限于静态图片。越来越多的 Mac 用户希望桌面能像 Windows 一样,拥有动态壁纸,展现个性、提升体验。LiveWallpaperMacOS 正是这样一款让你的 Mac 桌面焕发活力的开源项目。 本文将详细介绍 LiveWallpaperMacOS …...
[预训练]Encoder-only架构的预训练任务核心机制
原创文章1FFN前馈网络与激活函数技术解析:Transformer模型中的关键模块2Transformer掩码技术全解析:分类、原理与应用场景3【大模型技术】Attention注意力机制详解一4Transformer核心技术解析LCPO方法:精准控制推理长度的新突破5Transformer模…...

07-后端Web实战(部门管理)
5. 修改部门 对于任何业务的修改功能来说,一般都会分为两步进行:查询回显、修改数据。 5.1 查询回显 5.1.1 需求 当我们点击 "编辑" 的时候,需要根据ID查询部门数据,然后用于页面回显展示。 5.1.2 接口描述 参照参照…...

mysql ACID 原理
序言:ACID 是一组数据库设计原则,他是业务数据和关键业务程序的可靠性保障。 1、atomicity(原子性) 依赖如下能力 autocommit commit rollback2、一致性 2.1 double write buffer 1、定义:double write buffer 是…...

[Rust_1] 环境配置 | vs golang | 程序运行 | 包管理
目录 Rust 环境安装 GoLang和Rust 关于Go 关于Rust Rust vs. Go,优缺点 GoLang的优点 GoLang的缺点 Rust的优点 Rust的缺点 数据告诉我们什么? Rust和Go的主要区别 (1) 性能 (2) 并发性 (3) 内存安全性 (4) 开发速度 (5) 开发者体验 Ru…...

二十五、面向对象底层逻辑-SpringMVC九大组件之HandlerMapping接口设计
一、引言:MVC架构的交通枢纽 在Spring MVC框架中,HandlerMapping接口扮演着"请求导航仪"的关键角色,它决定了HTTP请求如何被路由到对应的Controller处理器。作为MVC模式的核心组件之一,HandlerMapping在请求处理的生命…...
构建安全高效的邮件网关ngx_mail_ssl_module
一、快速上手:最小配置示例 worker_processes auto;mail {server {# 监听 IMAP over TLSlisten 993 ssl;protocol imap;# TLS 协议与密码套件ssl_protocols TLSv1.2 TLSv1.3;ssl_ciphers HIGH:!aNULL:!MD5;# 证书与私钥ssl_…...

HUAWEI交换机配置镜像口验证(eNSP)
技术术语: 流量观察口:就是我们常说的镜像口,被观察的流量的引流目的端口 流量源端口:企业生产端口,作为观察口观察对象。 命令介绍: [核心交换机]observe-port [观察端口ID或编号(数字&am…...

前端vue3实现图片懒加载
场景和指令用法 场景:电商网站的首页通常会很长,用户不一定能访问到页面靠下面的图片,这类图片通过懒加载优化手段可以做到只有进入视口区域才发送图片请求 核心原理:图片进入视口才发送资源请求 首先:我们需要定义一个全局的指令&#x…...
网站每天几点更新,更新频率是否影响网站收录
1. 每天几点更新网站最合适?总怕时间选错影响收录? 刚开始搞网站的时候,是不是老纠结啥时候更新合适?早上刚上班?半夜没人的时候?选不对时间,总担心搜索引擎爬虫来了没抓到新内容,影…...
主流Markdown编辑器的综合评测与推荐
根据2025年最新资料,结合功能特性、用户体验和技术适配性,以下是对主流Markdown编辑器的综合评测与推荐: 一、核心对比维度与评估方法 功能完整性:支持数学公式、流程图、代码高亮等复杂格式。跨平台兼容性:Windows/m…...

计算机网络-MPLS VPN应用场景与组网
上一篇文章我们通过一个基础实验实现了企业分支间的MPLS VPN互联,如果还不理解的可以多看几遍前面的文章或者多敲下实验。今天来学习几种常见的MPLS VPN应用场景与这些场景下MPLS VPN的部署方法。 一、MPLS VPN典型应用 目前,MPLS VPN的主要应用包括企…...
AugmentFree:解除 AugmentCode 限制的终极方案 如何快速清理vscode和AugmentCode缓存—windows端
AugmentFree1.0工具包:解除 AugmentCode 免费试用限制的终极方案 Augment VIP 是一个专为 VS Code 用户设计的实用工具包,旨在帮助用户管理和清理 VS Code 数据库,解除 AugmentCode 免费试用账户的限制。 augment从根源上解决免费额度限制问…...
WPF【11_7】WPF实战-重构与美化(ViewModel的嵌套与分解、海量数据不要Join)
11-12 【重构】ViewModel的嵌套与分解 目前我们的代码中有一个不易发现的致命问题,如果工作中这样写代码大概率会被打回去重做。那么这个问题是什么呢? --\ViewModels\MainViewModel.cs 视图模型中的 LoadCustomers() 方法,考虑一下在这里我…...

Linux 的编辑器--vim
1.Linux编辑器-vim使⽤ vi/vim的区别简单点来说,它们都是多模式编辑器,不同的是vim是vi的升级版本,它不仅兼容vi的所有指令,⽽且还有⼀些新的特性在⾥⾯。例如语法加亮,可视化操作不仅可以在终端运⾏,也可以…...
Oracle 慢sql排查
Oracle慢sql排查步骤 1.1. 前言 Oracle 慢查询的排查方向包括以下几个方向 : 基准测试 (吞吐量): 包括 Oracle 本身吞吐量和磁盘 I/O 吞吐量硬件分析 (资源情况): 包括查看服务器 CPU , 硬盘的使用情况SQL分析:分析 SQL 中是否存在慢查询 , 是否命中索引配置优化…...

[Protobuf] 快速上手:安全高效的序列化指南
标题:[Protobuf] (1)快速上手 水墨不写bug 文章目录 一、什么是protobuf?二、protobuf的特点三、使用protobuf的过程?1、定义消息格式(.proto文件)(1)指定语法版本(2)package 声明符 2、使用protoc编译器生成代码&…...
uniapp开发企业微信小程序时 wx.qy.login 在uniapp中使用的时候,需要导包吗?
在 UniApp 中使用 “wx.qy.login” 不需要手动导包,但需要满足以下条件: 一、环境要求与配置 1� 企业微信环境判断 必须确保当前运行环境是企业微信客户端,通过 “uni.getSystemInfoSync().environment” 判断是否为 “wxwork”…...

如何将通话记录从Android传输到Android
“如何将通话记录从 Android 转移到 Android?我换了一部新的 Android 手机,想要将通话记录复制到其中。”您需要将通话记录从 Android 传输到 Android 是一种常见的情况,因为通话记录是手机上最重要的数据之一。幸运的是,如果您从…...
Word 目录自动换行后错位与页码对齐问题解决教程
📘 Word 目录自动换行错位与页码对齐问题解决教程 🎯 目标效果 目录条目过长自动换行后,第二行左对齐整齐;页码始终靠右对齐,前方带有“……”引导符;解决页码错位、制表符消失或格式混乱问题。 …...

数据结构第4章 栈、队列和数组 (竟成)
目录 第 4 章 栈、队列和数组 4.1 栈 4.1.1 栈的基本概念 4.1.2 栈的基本操作 4.1.3 栈的实现 1.顺序栈 2.链式栈 3.共享栈 4.1.4 顺序栈的基本操作实现 1.初始化栈 2.判空 3.判满 4.元素进栈 5.元素出栈 6.获取栈顶元素 4.1.5 链栈的基本操作实现 1.元素进栈 2.元素出栈 4.1.6…...
removeIf() 方法,结合 Lambda 表达式
在 Java 8 中,removeIf() 方法是 Collection 接口新增的一个默认方法,用于根据条件批量删除集合中的元素。结合 Lambda 表达式,可以以极简的语法实现复杂的过滤逻辑。以下是详细说明: 1. 方法定义与语法 // java.util.Collection 接口中的定义 default boolean removeIf(P…...
汽车售后诊断数据流详细分析
一、引言 随着汽车电子化程度的不断提升,电控系统已成为车辆运行的核心支撑。据罗兰贝格 2025 年智能汽车白皮书数据显示,中央计算 区域控制架构(Zonal EEA)的普及率已突破 58%,推动整车线束成本下降 41%12。与此同时…...

2025年渗透测试面试题总结-匿名[校招]安全研究员(SAST方向)(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 匿名[校招]安全研究员(SAST方向) 一面问题回答框架 1. 自我介绍 2. 简历深挖(漏洞挖掘&#x…...

Unity 游戏优化(持续更新中...)
垃圾回收 是什么? 垃圾回收(Garbage Collection)GC 工作机制 1、Unity 为用户生成的代码和脚本采用了自动内存管理。 2、小块数据(如值类型的局部变量)分配在栈上。大块数据和长期存储分配在托管堆上。 3、垃圾收集…...
LlamaFactory——如何使用魔改后的模型
需求来源:有时我们可能想在llamafactory框架支持的模型上进行一些改动,例如修改forward()方法等,修改方法我们可以通过继承Transformers库中相应的class并重写相应的方法即可,那我们如何使用自己的模型呢? 首先&#…...
【前端】【css预处理器】Sass与Less全面对比与构建对应知识体系
第一章 概述 1.1 Sass和Less简介 1.1.1 Sass简介 Sass(Syntactically Awesome Stylesheets)是一种 CSS 预处理器,它为 CSS 赋予了更多强大的功能和更灵活的语法结构😎。 语法特点:Sass 有两种语法格式。一种是 .sa…...
【请关注】关于VC++实现使用Redis不同方法,有效达到 Redis 性能优化、防击穿
麻烦先关注方便了解最新分享。 关于VC实现使用Redis不同方法,有效达到 Redis 性能优化、防击穿。 一、性能优化核心方法 1. 使用连接池复用连接 // 连接池结构体 struct RedisPool { hiredisContext** connections; int size; sem_t sem; // 信号量控制并发 }; //…...
【加密算法】
计算机网络加密算法详解 在计算机网络中,加密算法是保障数据安全的核心技术,用于防止数据在传输过程中被窃听、篡改或伪造。本文将详细介绍常见的加密算法分类、工作原理及其在网络中的应用。 1. 加密算法分类 加密算法主要分为以下三类: 类型特点典型算法对称加密加密和解…...