在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"
}
相关推荐
崔庆才丨静觅3 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60614 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了4 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅4 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅4 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅5 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment5 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅5 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊5 小时前
jwt介绍
前端
爱敲代码的小鱼5 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax