在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"
}
相关推荐
遂心_1 分钟前
#React Router Dom 入门:构建现代单页面应用的前端路由方案
前端·javascript·react.js
真夜1 分钟前
记录van-rate组件输入图片打包后无效问题
前端·vue.js·typescript
幽你一默2 分钟前
Android高效列表更新:DiffUtils深度解析
前端
雲墨款哥2 分钟前
Vue3 图片放大镜组件优化实践:用 transform 替代 relative 定位 & watchThrottled 优化性能
前端·vue.js
爱编程的喵5 分钟前
React Hooks + 自定义Hooks 打造现代化 Todo 应用:记事本
前端·react.js
咔咔一顿操作8 分钟前
5、Vue中使用Cesium实现交互式折线绘制详解
前端·javascript·vue.js·3d
JosieBook20 分钟前
【web应用】若依框架中,使用Echarts导出报表为PDF文件
前端·pdf·echarts
袁煦丞1 小时前
Photopea云端修图不求人!cpolar内网穿透实验室第641个成功挑战
前端·程序员·远程工作
yk-ddm1 小时前
JavaScript实现文件下载完整方案
前端·javascript·html
万少1 小时前
04-自然壁纸实战教程-搭建基本工程
前端·harmonyos·客户端