说真话很难吗 發表於 2026-4-10 10:19:00

Vue<前端页面版本检测>

<h1 data-id="heading-0">🧑‍💻 写在开头</h1>
<p>点赞 + 收藏 === 学会🤣🤣🤣</p>
<div>
<div>
<h2 data-id="heading-0">为什么需要版本检测</h2>
<h3 data-id="heading-1">1. 解决浏览器缓存问题</h3>
<ul>
<li><strong>静态资源缓存</strong>:浏览器会缓存 JS、CSS 等静态资源,用户可能继续使用旧版本</li>
<li><strong>用户体验影响</strong>:用户无法及时获取新功能,导致功能缺失或操作异常</li>
</ul>
<h3 data-id="heading-2">2. 保障功能一致性</h3>
<ul>
<li><strong>功能同步</strong>:确保所有用户都能使用最新的功能和修复</li>
<li><strong>数据一致性</strong>:避免因版本差异导致的数据不一致问题</li>
</ul>
<h3 data-id="heading-3">3. 提升用户体验</h3>
<ul>
<li><strong>主动提醒</strong>:在新版本发布后主动通知用户更新</li>
<li><strong>无缝升级</strong>:减少用户手动刷新页面的需求</li>
</ul>
<h2 data-id="heading-4">版本检测核心思路</h2>
</div>
<p><img src="https://img2024.cnblogs.com/blog/2149129/202604/2149129-20260410101753209-1533444785.png" alt="ScreenShot_2026-04-10_101700_706" loading="lazy"></p>
<div>
<div>
<h3 data-id="heading-5">整体架构</h3>
<blockquote>
<p>构建阶段 → 版本文件生成 → 运行时检测 → 版本对比 → 用户提醒</p>
</blockquote>
<h3 data-id="heading-6">技术实现要点</h3>
<h4 data-id="heading-7">1. 版本标识生成</h4>
<ul>
<li><strong>构建时生成</strong>:每次打包时生成唯一的版本标识</li>
<li><strong>时间戳方案</strong>:使用时间戳确保每次构建版本号唯一</li>
</ul>
<h4 data-id="heading-8">2. 版本文件部署</h4>
<ul>
<li><strong>JSON 格式</strong>:将版本信息保存为&nbsp;<code>version.json</code>&nbsp;文件</li>
<li><strong>静态访问</strong>:通过 HTTP 请求可直接访问版本文件</li>
</ul>
<h4 data-id="heading-9">3. 客户端检测机制</h4>
<ul>
<li><strong>定时轮询</strong>:定期检查服务器版本文件</li>
<li><strong>版本对比</strong>:比较本地缓存版本与服务器版本</li>
<li><strong>智能提醒</strong>:仅在版本不一致时提醒用户</li>
</ul>
<h2 data-id="heading-10">版本检测实现步骤</h2>
<h3 data-id="heading-11">步骤一:构建版本文件生成脚本</h3>
<p>创建&nbsp;<code>build-version.js</code>&nbsp;文件:</p>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">// build-version.js (自动生成版本文件脚本)
const fs = require('fs')
const path = require('path')

// 方案A:使用时间戳作为版本标识(最简单,确保每次打包唯一)
const version = new Date().getTime().toString()

// 版本文件内容
const versionJson = {
version: version,
updateTime: new Date().toLocaleString() // 可选:添加更新时间,便于排查
}

// 写入version.json文件(项目根目录)
const versionPath = path.resolve(__dirname, 'public', 'version.json')
fs.writeFileSync(versionPath, JSON.stringify(versionJson, null, 2), 'utf-8')

console.log(`✅ 自动生成版本文件成功,版本号:${version}`)</pre>
</div>
<h3 data-id="heading-12">步骤二:修改构建命令</h3>
<p>在&nbsp;<code>package.json</code>&nbsp;中修改构建命令:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">{
"scripts": {
    "build:prod": "node build-version.js &amp;&amp; vue-cli-service build"
}
}</pre>
</div>
<h3 data-id="heading-13">步骤三:配置 Vue 构建过程</h3>
<p>在&nbsp;<code>vue.config.js</code>&nbsp;中添加版本文件复制配置:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">chainWebpack(config) {
// ... 其他配置

// 复制 version.json 到 dist 目录
config.plugin('copy')
    .tap(args =&gt; {
      const hasVersionJson = args.some(item =&gt; item.from === 'version.json')
      if (!hasVersionJson) {
      args.push({
          from: path.resolve(__dirname, 'public/version.json'),
          to: path.resolve(__dirname, 'dist/version.json')
      })
      }
      return args
    })
}</pre>
</div>
<h3 data-id="heading-14">步骤四:实现版本检测工具类</h3>
<p>创建&nbsp;<code>src/utils/versionUpdate.js</code>:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">// src/utils/versionUpdate.js
import { Notification } from 'element-ui'
/**
* 版本更新检测工具类(仅生产环境启用轮询,内置环境判断)
*/
class VersionUpdate {
constructor(options = {}) {
    this.config = {
      versionFileUrl: '/version.json', // 版本文件地址
      localVersionKey: 'cmpVersion', // 本地存储的版本号key
      disableFetchCache: true, // 禁用Fetch缓存
      pollInterval: 5 * 60 * 1000, // 5分钟轮询一次
      hasNotified: false // 是否已提醒过用户有新版本
    }
    Object.assign(this.config, options)
    // 定时轮询定时器
    this.pollTimer = null
    // 识别当前环境(Vue CLI 4 自动注入的环境变量)
    this.isProduction = process.env.NODE_ENV === 'production'
}

/**
   * 核心方法:执行版本检测
   */
async checkVersion(isInit = false) {
    try {
      if (this.config.hasNotified) return false

      const localVersion = localStorage.getItem(this.config.localVersionKey) || ''
      const fetchOptions = {}
      if (this.config.disableFetchCache) {
      fetchOptions.cache = 'no-cache'
      }

      const response = await fetch(this.config.versionFileUrl, fetchOptions)
      if (!response.ok) {
      throw new Error(`版本文件请求失败,状态码:${response.status}`)
      }
      const latestVersionInfo = await response.json()
      const serverVersion = latestVersionInfo.version

      if (isInit) {
      this.cacheLatestVersion(serverVersion)
      return true
      }

      if (serverVersion &amp;&amp; serverVersion !== localVersion) {
      this.config.hasNotified = true
      console.log('有新版本可用', latestVersionInfo)
      Notification({
          title: '🎉 有新版本可用',
          dangerouslyUseHTMLString: true,
          message: `&lt;p style="font-size:12px;"&gt;建议点击刷新页面,以获取最新功能和修复&lt;/p&gt; &lt;p style="color:#cccccc;font-size:12px;"&gt;更新时间:${latestVersionInfo.updateTime}&lt;/p&gt;`,
          duration: 0,
          customClass: 'check-version-notify',
          onClick: () =&gt; {
            this.forceRefreshPage()
          },
          onClose: () =&gt; {
            this.resetNotifyFlag()
          }
      })
      return true
      } else {
      // 版本一致时,重置提醒标记,便于后续轮询检测新版本
      this.config.hasNotified = false
      // console.log('当前已是最新版本,已缓存最新版本号')
      return false
      }
    } catch (error) {
      console.warn('版本检测异常,不影响应用运行:', error.message)
      return false
    }
}
/**
   * 启动定时轮询检测(内置环境判断:仅生产环境生效)
   */
async startPolling() {
    // 核心:非生产环境,直接返回,不启动轮询
    if (!this.isProduction) {
      console.log('当前为非生产环境,不启动版本检测轮询')
      return
    }

    // 生产环境:正常启动轮询
    this.stopPolling() // 先停止已有轮询,避免重复启动
    this.checkVersion(true) // 立即执行一次检测

    this.pollTimer = setInterval(() =&gt; {
      this.checkVersion()
    }, this.config.pollInterval)

    console.log(`生产环境版本轮询检测已启动,每隔${this.config.pollInterval / 1000 / 60}分钟检测一次`)
}

/**
   * 停止定时轮询检测
   */
stopPolling() {
    if (this.pollTimer) {
      clearInterval(this.pollTimer)
      this.pollTimer = null
      console.log('版本轮询检测已停止')
    }
}

/**
   * 重置提醒标记
   */
resetNotifyFlag() {
    this.config.hasNotified = false
}

// 缓存最新版本号
cacheLatestVersion(version) {
    localStorage.setItem(this.config.localVersionKey, version)
    this.resetNotifyFlag()
}

// 强制刷新页面
forceRefreshPage() {
    window.location.reload(true)
}
}

const versionUpdateInstance = new VersionUpdate()
export { VersionUpdate, versionUpdateInstance }
export default versionUpdateInstance</pre>
</div>
<p>创建自定义<code>.check-version-notify</code>的版本检测全局样式:</p>
<p><img src="https://img2024.cnblogs.com/blog/2149129/202604/2149129-20260410101901066-897389150.png" alt="ScreenShot_2026-04-10_101712_780" loading="lazy"></p>
<p>&nbsp;</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">// 版本检测通知样式
.check-version-notify{
border: 3px solid transparent !important;
cursor: pointer;
background-color: rgba(255, 255, 255, 0.6) !important;
backdrop-filter: blur(5px);
&amp;:hover{
    border: 3px solid $--color-primary !important;
}
.el-notification__icon{
    font-size: 18px;
    height: 18px;
}
.el-notification__title{
    font-size: 14px;
    line-height: 18px;
}
.el-notification__group{
    margin-left: 8px;
}
}</pre>
</div>
<h3 data-id="heading-15">步骤五:在应用入口启动版本检测</h3>
<p>在&nbsp;<code>App.vue</code>&nbsp;或合适的入口文件中启动版本检测:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">import versionUpdate from '@/utils/versionUpdate'
...
mounted() {
versionUpdate.startPolling()
},
beforeDestroy() {
versionUpdate.stopPolling()
}</pre>
</div>
<div>
<h3 id="tid-D8HBxE">如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。</h3>
</div>
<p><em><img src="https://img2024.cnblogs.com/blog/2149129/202501/2149129-20250122165814748-630765389.png" alt="" loading="lazy"></em></p>
</div>
</div><br><br>
来源:https://www.cnblogs.com/smileZAZ/p/19845292
頁: [1]
查看完整版本: Vue<前端页面版本检测>