跪拜 Guibai
← Back to the summary

Vue 2.7.16's Final Patch Broke v-show When Combined With Inline Styles

That Page That Was Never Changed — Why Did It Suddenly Break?

Vue 2.7.16 / v-show and style / lock files


image.png

Background

The project hadn't been touched in a long time. The task name in the navigation task panel was controlled with v-show="isRunning", with a style="display: flex" next to it. It had been written that way for years and always worked fine.

Today it suddenly broke.

Testing sent a screenshot: the task had ended, isRunning was false, but the task name was still hanging on the panel.

Q: Was this part changed? A: No. Q: Then why did it suddenly break?

That question is annoying to hear, but it really had to be investigated.


Investigation

First, suspect yourself.

Open StartTask.vue:

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

Check the data: isRunning is indeed false after the task ends. Check updates: the component re-renders. Check styles: no extra display is written elsewhere.

Clear cache, clear node_modules, restart the service — still reproducible.

Check the business logic again: the state flow for ending tasks is also fine.

A bit strange. When the v-show condition is false, it simply adds display: none to the element. How could something so fundamental suddenly fail?


Narrowing It Down

Create a minimal reproduction:

<div v-show="visible" style="display: flex">Content</div>
<button @click="visible = !visible">toggle</button>

Click it, and it doesn't hide when it should.

Remove style, keep only v-show — works fine. Remove v-show, keep only style — works fine. Both together — broken.

The conclusion is clear: it's not the business logic that's broken; it's a conflict between v-show and style on the same tag.

But this still doesn't explain why it worked fine before and only exploded today. The same pattern had lived in the project for a long time.


The Real Reason

The code didn't change, so check if the runtime environment changed.

In package.json:

"vue": "^2.7.14"

Note the ^. It allows installing updates within the compatible range. For 2.7.x, ^2.7.14 can resolve to 2.7.15, 2.7.16.

Now check the actually installed version:

vue@^2.7.14:
  version "2.7.16"

Things start to make sense.

The project hadn't been touched for a long time. The node_modules on the old computer was still the version installed back then, most likely 2.7.14 or 2.7.15. Running locally every day, the page was fine.

Today, a new computer was set up, the code was pulled, and dependencies were reinstalled. package.json still says ^2.7.14, but the package manager, following the rules, installed the latest official version within range: 2.7.16.

Not a single line of code changed. Vue jumped a minor version, and the behavior changed.


What Changed in 2.7.16

Vue 2.7.16, codenamed Swan Song, is the final official release of Vue 2. No new features, mainly closing bug fixes and aligning some types with Vue 3.

One of them:

style: always set new styles

To fix style merging issues (like border and border-bottom overwriting each other), 2.7.16 removed the check that skipped setting when the new and old values were the same. Now, every update rewrites all properties in the style object.

The actual effect is:

  1. v-show=false first writes display: none
  2. In the same update cycle, the style module runs again
  3. The inline style has display: flex
  4. setProp(el, 'display', 'flex') overwrites the none

Thus, v-show fails, and the element is displayed again.

Official issue: vuejs/vue#13140. Someone submitted a fix PR, but Vue 2 is already EOL and will not receive any more patches.

So it's not that the directive was written wrong; it's a regression introduced upstream to fix A, which happened to hit B. We only saw it today because the new environment ran 2.7.16 for the first time.


About Lock Files

Looking back, what's more worth remembering than changing the template is this:

package.json specifies a version range. Which version is actually installed depends on the lock file.

If the lock file is committed and used seriously:

The real hidden reason this time boils down to one sentence: the page didn't suddenly break; it was the first time 2.7.16 was installed after switching computers.

So, commit the lock file. Don't treat it as optional.


Solutions

1. Downgrade to 2.7.15

The most direct. On 2.7.15, v-show won't be overwritten by style.

The cost is losing other fixes in 2.7.16 (keep-alive leaks, some reactivity edge cases, type alignment, etc.). Suitable for a temporary stopgap, not ideal for staying here long-term.

2. Replace v-show with v-if

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

A small change, takes effect immediately. The element will be destroyed and recreated. Generally fine for normal UI; be a bit careful with maps, charts, or components with lots of internal state.

3. Change static style to a class

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

v-show writes an inline display: none, which has higher priority than the display: flex in the stylesheet and won't be overwritten. The layout is also cleaner.

We used solution 2 for the task panel and extracted display: flex into a class for the plan management dialog, using solution 3. Just choose based on the scenario.


Summary

The investigation is over, and the code changes aren't large.

Next time you encounter something that was never changed but suddenly broke, you can first ask: is the version you installed still the same one?


Related Links


This article is based on real project experience, with the outline drafted manually and AI-assisted polishing, on 2026-07-13

Comments

Top 2 of 3 from juejin.cn, machine-translated. The original thread is authoritative.

THERE_ARE_YOU 1 likes

lock files must be included

zhedream

Yes.

王三岁_

Good article, thanks for sharing.