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

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

Vue 2.7.16 / v-show 与 style / lock 文件


背景

项目很久没动过了。走航任务面板里那段任务名称,用 v-show="isRunning" 控制显示,旁边挂着 style="display: flex",写了好几年,一直正常。

今天突然出问题。

测试发来截图:任务已经结束,isRunningfalse,任务名称却还挂在面板上。

问:这块改过吗?

答:没有。

再问:那为啥突然坏了?

这句听着就烦,但确实得查。


排查

先怀疑自己。

打开 StartTask.vue

vue 复制代码
<div
  v-show="isRunning"
  class="gcs-radius"
  style="display: flex; justify-content: center"
>

查数据:isRunning 结束任务后确实是 false

查更新:组件 re-render 了。

查样式:别处没有额外写 display

清缓存、清 node_modules、重启服务,还是复现。

再跟业务:结束任务的状态流转也没问题。

有点怪。v-show 条件为假时就是给元素加 display: none,这么基础的东西怎么会突然不行?


缩小范围

做成最小复现:

vue 复制代码
<div v-show="visible" style="display: flex">内容</div>
<button @click="visible = !visible">toggle</button>

点一下,该藏不藏。

去掉 style,只留 v-show,正常。

去掉 v-show,只留 style,正常。

两个一起,坏。

结论很明确:不是业务坏了,是同一个标签上的 v-showstyle 冲突了。

但这还解释不了为什么以前好好的,今天才炸。同样的写法在项目里活了很久。


真正的原因

代码没变,那就看运行环境有没有变。

package.json 里是:

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

注意这个 ^。它允许安装兼容范围内的更新。对 2.7.x 来说,^2.7.14 可以解析到 2.7.152.7.16

再看实际装上的版本:

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

事情就对上了。

项目很久没动。旧电脑上的 node_modules 还是当时装出来的版本,多半是 2.7.142.7.15。本地天天跑,页面没事。

今天换了新电脑,拉代码重新装依赖。package.json 还是 ^2.7.14,包管理器按规则装了范围内最新正式版:2.7.16

代码一行没改,Vue 小版本跳了一格,行为就不一样了。


2.7.16 改了什么

Vue 2.7.16 代号 Swan Song,Vue 2 的最终正式版。没有新功能,主要是收尾 bugfix,以及跟 Vue 3 对齐一些类型。

其中有一条:

style: always set new styles

为了修 style 合并问题(比如 borderborder-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 已经 EOL,不会再发补丁了。

所以不是指令写错了,而是上游为修 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

vue 复制代码
<div
  v-if="isRunning"
  class="gcs-radius"
  style="display: flex; justify-content: center"
>

改动小,立刻生效。元素会销毁重建,普通 UI 一般没问题;地图、图表、内部状态多的组件要小心一点。

3. 静态 style 改成 class

vue 复制代码
<div v-show="isRunning" class="gcs-radius task-name-row">
css 复制代码
.task-name-row {
  display: flex;
  justify-content: center;
}

v-show 写的是内联 display: none,优先级高于样式表里的 display: flex,不会被盖掉。布局也更干净。

我们这边任务面板用了方案 2,方案管理弹窗把 display: flex 抽到 class,用了方案 3。看场景选就行。


小结

排查结束,代码改动不大。

以后再遇到从没改过却突然坏了,可以先问一句:你装到的,还是同一个版本吗?


相关链接


本文基于真实项目经验整理,手工起草文章大纲,AI 辅助润色,于 2026-07-13

相关推荐
工业HMI实战笔记1 小时前
HMI性能优化技巧:告别卡顿,打造流畅体验
前端·ui·性能优化·自动化·交互
QN1幻化引擎2 小时前
Gravity-Anchored Cognitive Field Architecture: The DalinX V8/V10 Implementation
java·前端·算法
光影少年2 小时前
react的View/Text/Image/ScrollView 常用组件注意事项
开发语言·前端·javascript·react.js·前端框架
程序员黎剑2 小时前
我把算卦变成了一段if-else
java·vue.js·spring boot·后端·ai编程
yangmu32032 小时前
前端性能优化实战:我是如何将首屏加载时间缩短 40% 的?
前端·性能优化
IT_陈寒2 小时前
JavaScript的隐式类型转换又双叒坑了我一次!
前端·人工智能·后端
JarvanMo2 小时前
HTTP的DELET方法能不能有Body?
前端
天蓝色的鱼鱼2 小时前
扔掉 ESLint + Prettier:Biome 全家桶实战
前端
533_2 小时前
[element-plus] el-tabs和el-menu联动
前端·javascript·vue.js