在Vue、React 和 UniApp 中实现版本比对及更新提示

一、Vue 项目中的实现

1. 创建版本检测工具

javascript 复制代码
// src/utils/versionChecker.js
const VERSION = '1.0.0'; // 与package.json中版本一致
const CHECK_INTERVAL = 30 * 60 * 1000; // 30分钟检查一次

export default {
  async checkVersion() {
    try {
      const res = await fetch(`/version.json?t=${Date.now()}`);
      const { version, updateContent } = await res.json();
      
      if (this.compareVersions(VERSION, version) === -1) {
        this.showUpdateDialog(version, updateContent);
        return true;
      }
      return false;
    } catch (error) {
      console.error('版本检查失败:', error);
      return false;
    }
  },

  compareVersions(v1, v2) {
    const parts1 = v1.split('.').map(Number);
    const parts2 = v2.split('.').map(Number);
    
    for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
      const p1 = parts1[i] || 0;
      const p2 = parts2[i] || 0;
      if (p1 < p2) return -1;
      if (p1 > p2) return 1;
    }
    return 0;
  },

  showUpdateDialog(newVersion, updateContent) {
    // 使用Vue的动态组件创建弹窗
    const UpdateDialog = {
      template: `
        <div class="update-dialog">
          <h3>发现新版本 v${newVersion}</h3>
          <p>更新内容: ${updateContent || '优化体验,修复已知问题'}</p>
          <div class="actions">
            <button @click="updateNow">立即更新</button>
            <button @click="closeDialog" v-if="!isForceUpdate">稍后提醒</button>
          </div>
        </div>
      `,
      data() {
        return {
          isForceUpdate: localStorage.getItem('ignoreUpdateCount') >= 3
        };
      },
      methods: {
        updateNow() {
          window.location.reload(true);
        },
        closeDialog() {
          const count = parseInt(localStorage.getItem('ignoreUpdateCount') || 0) + 1;
          localStorage.setItem('ignoreUpdateCount', count);
          this.$destroy();
          document.body.removeChild(this.$el);
        }
      }
    };

    const ComponentClass = Vue.extend(UpdateDialog);
    const instance = new ComponentClass().$mount();
    document.body.appendChild(instance.$el);
  },

  init() {
    // 页面加载时检查
    this.checkVersion();
    
    // 定时检查
    setInterval(() => this.checkVersion(), CHECK_INTERVAL);
    
    // 当页面从后台切回时检查
    document.addEventListener('visibilitychange', () => {
      if (document.visibilityState === 'visible') {
        this.checkVersion();
      }
    });
  }
};

2. 在 main.js 中初始化

javascript 复制代码
// src/main.js
import Vue from 'vue';
import App from './App.vue';
import versionChecker from './utils/versionChecker';

Vue.config.productionTip = false;

new Vue({
  render: h => h(App),
  created() {
    versionChecker.init();
  }
}).$mount('#app');

3. 创建版本文件

json 复制代码
// public/version.json
{
  "version": "1.0.1",
  "updateContent": "修复了登录页面的安全问题"
}

二、React 项目中的实现

1. 创建版本检测组件

ini 复制代码
// src/components/VersionChecker.js
import React, { useEffect, useState } from 'react';
import { Modal, Button, message } from 'antd';

const VERSION = '1.0.0';
const CHECK_INTERVAL = 30 * 60 * 1000;

const VersionChecker = () => {
  const [visible, setVisible] = useState(false);
  const [updateInfo, setUpdateInfo] = useState({});
  const [ignoreCount, setIgnoreCount] = useState(
    parseInt(localStorage.getItem('ignoreUpdateCount') || 0)
  );

  const compareVersions = (v1, v2) => {
    const parts1 = v1.split('.').map(Number);
    const parts2 = v2.split('.').map(Number);
    
    for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
      const p1 = parts1[i] || 0;
      const p2 = parts2[i] || 0;
      if (p1 < p2) return -1;
      if (p1 > p2) return 1;
    }
    return 0;
  };

  const checkVersion = async () => {
    try {
      const res = await fetch(`/version.json?t=${Date.now()}`);
      const data = await res.json();
      
      if (compareVersions(VERSION, data.version) === -1) {
        setUpdateInfo(data);
        setVisible(true);
        return true;
      }
      return false;
    } catch (error) {
      console.error('版本检查失败:', error);
      return false;
    }
  };

  const handleUpdate = () => {
    window.location.reload(true);
  };

  const handleLater = () => {
    const newCount = ignoreCount + 1;
    setIgnoreCount(newCount);
    localStorage.setItem('ignoreUpdateCount', newCount);
    setVisible(false);
    
    if (newCount >= 3) {
      message.warning('此版本即将不再支持,请尽快更新');
    }
  };

  useEffect(() => {
    // 初始化检查
    checkVersion();
    
    // 定时检查
    const timer = setInterval(checkVersion, CHECK_INTERVAL);
    
    // 页面可见性变化检查
    const handleVisibilityChange = () => {
      if (document.visibilityState === 'visible') {
        checkVersion();
      }
    };
    
    document.addEventListener('visibilitychange', handleVisibilityChange);
    
    return () => {
      clearInterval(timer);
      document.removeEventListener('visibilitychange', handleVisibilityChange);
    };
  }, []);

  return (
    <Modal
      title={`发现新版本 v${updateInfo.version}`}
      visible={visible}
      onCancel={ignoreCount < 3 ? handleLater : null}
      footer={[
        ignoreCount < 3 && (
          <Button key="later" onClick={handleLater}>
            稍后提醒
          </Button>
        ),
        <Button key="update" type="primary" onClick={handleUpdate}>
          立即更新
        </Button>
      ]}
    >
      <p>当前版本: v{VERSION}</p>
      <p>更新内容: {updateInfo.updateContent || '优化体验,修复已知问题'}</p>
      {ignoreCount >= 3 && (
        <p style={{ color: 'red' }}>此为强制更新,无法跳过</p>
      )}
    </Modal>
  );
};

export default VersionChecker;

2. 在应用根组件中使用

javascript 复制代码
// src/App.js
import React from 'react';
import VersionChecker from './components/VersionChecker';

function App() {
  return (
    <div className="App">
      {/* 其他应用内容 */}
      <VersionChecker />
    </div>
  );
}

export default App;

三、UniApp 项目中的实现

1. 创建版本检测工具

javascript 复制代码
// utils/versionChecker.js
const VERSION = '1.0.0';
const CHECK_INTERVAL = 30 * 60 * 1000;

export default {
  compareVersions(v1, v2) {
    const parts1 = v1.split('.').map(Number);
    const parts2 = v2.split('.').map(Number);
    
    for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
      const p1 = parts1[i] || 0;
      const p2 = parts2[i] || 0;
      if (p1 < p2) return -1;
      if (p1 > p2) return 1;
    }
    return 0;
  },

  async checkVersion() {
    try {
      const res = await uni.request({
        url: '/static/version.json',
        data: { t: Date.now() }
      });
      
      const [error, data] = res;
      if (error) throw error;
      
      if (this.compareVersions(VERSION, data.version) === -1) {
        this.showUpdateModal(data.version, data.updateContent);
        return true;
      }
      return false;
    } catch (error) {
      console.error('版本检查失败:', error);
      return false;
    }
  },

  showUpdateModal(newVersion, updateContent) {
    const ignoreCount = uni.getStorageSync('ignoreUpdateCount') || 0;
    const isForceUpdate = ignoreCount >= 3;
    
    uni.showModal({
      title: `发现新版本 v${newVersion}`,
      content: `当前版本: v${VERSION}\n更新内容: ${updateContent || '优化体验,修复已知问题'}` +
               (isForceUpdate ? '\n\n此为强制更新,无法跳过' : ''),
      confirmText: '立即更新',
      cancelText: isForceUpdate ? '' : '稍后提醒',
      showCancel: !isForceUpdate,
      success: (res) => {
        if (res.confirm) {
          // 小程序中使用更新API
          if (uni.getUpdateManager) {
            const updateManager = uni.getUpdateManager();
            updateManager.onUpdateReady(() => {
              uni.showModal({
                title: '更新提示',
                content: '新版本已经准备好,是否重启应用?',
                success: (res) => {
                  if (res.confirm) {
                    updateManager.applyUpdate();
                  }
                }
              });
            });
          } else {
            // H5端直接刷新
            window.location.reload(true);
          }
        } else if (res.cancel) {
          const newCount = parseInt(ignoreCount) + 1;
          uni.setStorageSync('ignoreUpdateCount', newCount);
          
          if (newCount >= 3) {
            uni.showToast({
              title: '此版本即将不再支持,请尽快更新',
              icon: 'none'
            });
          }
        }
      }
    });
  },

  init() {
    // 应用启动时检查
    this.checkVersion();
    
    // 定时检查
    setInterval(() => this.checkVersion(), CHECK_INTERVAL);
    
    // 应用从后台切回前台时检查
    uni.onAppShow(() => {
      this.checkVersion();
    });
  }
};

2. 在 App.vue 中初始化

xml 复制代码
// App.vue
<script>
import versionChecker from '@/utils/versionChecker';

export default {
  onLaunch() {
    versionChecker.init();
  }
}
</script>

3. 创建版本文件

json 复制代码
// static/version.json
{
  "version": "1.0.1",
  "updateContent": "修复了支付流程的bug"
}
相关推荐
Ashley的成长之路10 分钟前
前端性能优化实战手册·第2篇:资源加载策略全解
前端·性能优化·资源加载·http/3·性能优化实战·资源加载优化
浅水壁虎14 分钟前
vue基础(第二章 )
前端·javascript·vue.js
界面开发小八哥15 分钟前
界面控件DevExtreme v26.1新版亮点——支持Angular 22
前端·javascript·angular.js·devexpress·ui开发·devextreme
Getflare19 分钟前
前端 + UI 设计 + AI:这不是三个工种,是一个新三角能力模型(附自检清单)
前端·人工智能·ui
oil欧哟26 分钟前
我做了一个 Vibe Coding 术语学习站:VibeHub
前端·ai·agent·独立开发·vibe coding
审小匠OpenCPAi1 小时前
银行流水核查怎么自动化?单边匹配、双向勾稽与图聚类异常检测的工程对比
java·前端·人工智能·python·审计
Revolution611 小时前
一个公共表格组件,是怎么一步步失控的
前端·前端工程化
腻害兔2 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:CRM 客户关系模块深度解析——从线索到回款,一套完整的 B2B 销售闭环是怎么搭的?
java·前端·javascript·vue.js·产品经理·ai编程
whyfail2 小时前
前端学 Spring Boot(2):一次点击,如何穿过整个后端?
前端·spring boot·后端