从没改过的页面为什么突然坏了?

作者:技术拾光

时间:2026-07-15

浏览:135

那个从没改过的页面,为什么突然坏了? 背景 项目很久没有动过。走航任务面板中的任务名称,通过 v-show="isRunning" 控制显示,旁边配有 style="display: flex",这一写法持续了多年,始终运行正常。 然而,今天突然出现问题。 测试人员发来截图:任务已经结束,isRun

文章目录

那个从没改过的页面,为什么突然坏了?


从没改过的页面为什么突然坏了?

背景

项目很久没有动过。走航任务面板中的任务名称,通过 v-show="isRunning" 控制显示,旁边配有 style="display: flex",这一写法持续了多年,始终运行正常。

然而,今天突然出现问题。

测试人员发来截图:任务已经结束,isRunning 为 false,但任务名称仍旧显示在面板上。

问:这块代码改动过吗?
答:没有。
再问:那为什么突然失效了?

这个问题听起来令人困扰,但确实需要排查。


排查

首先怀疑自身代码。

打开 StartTask.vue:

 复制代码

检查数据:isRunning 在结束任务后确实为 false。
检查更新:组件已重新渲染。
检查样式:其他位置没有额外定义 display 属性。

尝试清理缓存、删除 node_modules、重启服务,问题依然存在。

进一步跟踪业务逻辑:结束任务的状态流转也没有异常。

这让人感到奇怪。v-show 条件为假时,理应给元素添加 display: none,如此基础的功能怎么会突然失效?


缩小范围

制作最小复现样例:

 复制代码
内容

点击按钮,元素本应隐藏却未隐藏。

移除 style,仅保留 v-show,功能正常。
移除 v-show,仅保留 style,样式正常。
两者同时存在,异常出现。

结论明确:并非业务逻辑出错,而是同一标签上 v-show 和 style 发生了冲突。

但这仍无法解释为何过去一直正常运行,直到今天才暴露。相同的写法在项目中已存在很久。


真正的原因

代码未变,需确认运行环境是否变化。

package.json 中的配置为:

 复制代码"vue": "^2.7.14"

注意这里的 ^ 符号。它允许在兼容范围内自动安装更新版本。对于 2.7.x 系列,^2.7.14 可解析到 2.7.15、2.7.16 等版本。

查看实际安装的版本:

 复制代码vue@^2.7.14:
  version "2.7.16"

至此,原因浮出水面。

项目长时间未更新。旧电脑上的 node_modules 仍是当时安装的版本,极可能是 2.7.14 或 2.7.15。每日运行,页面正常。

今天更换了新电脑,拉取代码后重新安装依赖。package.json 仍为 ^2.7.14,包管理器按照规则安装了该范围内的最新正式版 2.7.16。

一行代码未改,Vue 的小版本跳升一级,行为却发生了变化。


2.7.16 改了什么

Vue 2.7.16 代号 Swan Song,是 Vue 2 的最终正式版。该版本未引入新功能,主要用于收尾 bug 修复并与 Vue 3 对齐部分类型定义。

其中一项变更值得关注:

为解决样式合并问题(例如 border 与 border-bottom 相互覆盖),2.7.16 移除了新旧值相同时的跳过判断,每次更新都会将 style 对象中的属性重新写入。

实际影响如下:

  1. v-show=false 先设置 display: none
  2. 在同一更新周期内,style 模块再次执行
  3. 内联 style 中包含 display: flex
  4. 执行 setProp(el, 'display', 'flex') 将 none 覆盖

最终导致 v-show 失效,元素再次显示。

官方 issue 见:vuejs/vue#13140。曾有人提交修复 PR,但 Vue 2 已停止维护,不会再发布补丁。

因此,问题并非指令编写错误,而是上游为修复 A 引入的回归恰好影响了 B。我们今天才发现,是因为新环境首次实际运行到了 2.7.16。


关于 lock 文件

复盘之后,比修改模板更值得铭记的是以下要点:

package.json 定义的是版本范围,实际安装的版本取决于 lock 文件。

若 lock 文件被认真提交并严格使用:

  • 旧电脑与新电脑将安装相同的 vue 版本
  • 本地正常而他人环境异常之类的推诿会大幅减少
  • 版本升级会变为一次明确的变更,而不是重装依赖时意外附带

此次问题的真正隐藏原因仅一句:并非页面突然损坏,而是换电脑后首次安装到了 2.7.16。

因此,lock 文件务必提交,不应视为可有可无。


解决办法

1. 降级到 2.7.15

最直接的方案。在 2.7.15 上,v-show 不会被 style 覆盖。

代价是放弃 2.7.16 中的其他修复(如 keep-alive 泄漏、部分响应式边界、类型对齐等)。适合临时止血,不建议长期停留于此版本。

2. 将 v-show 替换为 v-if

 复制代码

改动量小,立即可用。元素会销毁重建,普通 UI 通常无影响;但地图、图表、内部状态较多的组件需谨慎处理。

3. 将静态 style 改为 class

 复制代码
 复制代码.task-name-row {
  display: flex;
  justify-content: center;
}

v-show 设置的是内联 display: none,优先级高于样式表中的 display: flex,不会被覆盖。同时布局更清晰。

实际项目中,任务面板采用了方案 2,方案管理弹窗将 display: flex 提取为 class,使用了方案 3。可根据实际场景灵活选择。


小结

排查工作至此结束,代码改动不大。

今后再遇到从未动过却突然失效的页面,可以先问一句:你安装的,还是同一个版本吗?


相关链接

  • Issue:Using v-show and :style simultaneously does not yield expected results in 2.7.16
  • 根因 commit:fix(style): always set new styles
  • 未合入的修复尝试:PR #13198
  • Vue 2 EOL 说明:Vue 2 End of Life

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章