Vue.js项目中基于Mitt模式的缓存管理、事件通知与排行榜功能实现

本文介绍了如何在Vue3应用中使用响应式APIonMounted和ref实现状态管理,涉及缓存、本地排名、延迟消息、签到打卡、排行榜功能以及限流控制。通过详细代码展示了这些功能模块的创建、操作和使用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 状态管理初始化

  • 导入Vue3的响应式API onMounted 和 ref
  • 定义了五个ref变量,分别代表缓存仓库(cacheStore)、本地排名(ranking)、延迟队列(delayMsg)、用户签到打卡记录(sign)以及限流计数器(limiting)。

2. 缓存管理

  • putCache方法用于将属性对象存储到缓存中。
  • takeCache方法根据key从缓存中获取对应的属性值,同时利用类型断言返回指定类型的数据。
  • lockgetLockunLock方法实现了对特定资源的加锁、查询锁状态和解锁操作,通过检查缓存中是否存在对应key来判断资源是否被锁定。

3. 消息延迟发送

  • putDelayMsg方法将带有过期时间戳的消息放入延迟队列中,每条消息具有唯一标识tag
  • 使用定时器轮询检查延迟队列中消息是否过期,过期后通过事件总线emitter发送该消息并移除已处理的消息。

4. 用户签到打卡系统

  • punchSetting方法设置用户的签到打卡数据。
  • startSign方法处理用户签到逻辑,更新签到状态为已签到。
  • continuousClocking方法计算用户连续签到的天数。

5. 排行榜功能

  • putRanking方法向排行榜添加或更新项及其得分。
  • takeRanking方法按得分排序并获取前total个排名项,支持降序或升序排列。

6. 辅助工具函数

  • limit方法用于限流控制,增加指定键的请求次数计数。
  • takeLimit方法获取当前键的请求次数。
  • delLimit方法清除指定键的请求次数记录。
  • getUUID方法生成全局唯一的UUID字符串。

7. 组件生命周期钩子

  • onMounted钩子中初始化所有ref变量为新的Map实例,并设置定时器清理过期缓存及发送过期消息。

通过这个代码示例,我们可以深入理解如何在Vue.js应用中组织复杂的状态管理逻辑,并实现多个相互关联的功能模块。

8. 具体代码

import { onMounted, ref } from "vue";
import emitter from '@/utils/mitt'

interface Prop {
    exp: number;
    key: string;
    data: any;
    tag?: any;
}



export default function(){

    // 缓存的仓库
    let cacheStore  = ref( {} as Map< string, Prop >);

    // 用于本地排名
    let ranking = ref( {} as Map< string, any[] > );

    // 延迟队列
    let delayMsg = ref( {} as Map< string, any[] > );

    // 用户签到打卡
    let sign = ref( {} as Map< string, any[] > );

    // 限流
    let limiting = ref( {} as Map< string, number> );


    function limit( key : string ) {
        if (limiting.value.has(key)) {
            let temp = limiting.value.get(key) as number;
            limiting.value.set(key,temp + 1);
        }else {
            limiting.value.set(key,1);
        }
    }

    function takeLimit( key : string ) : number {
        return limiting.value.get(key) as number;
    }

    function delLimit( key : string ) {
        limiting.value.delete(key);
    }

    // 放入打卡的数据
    function punchSetting( key : string , signInData : number[]) {
        sign.value.set(key,signInData);
    }


    // 打卡
    function startSign( key : string ,  day : number ): boolean {
        let signInData = sign.value.get(key) as any[];
        if (signInData) {
            signInData.splice(day - 1,1,1);
            return true;
        }
        return false;
    }

    // 返回连续打卡的天数
    function continuousClocking( key : string ) : number {
       if(sign.value.size > 0) {
           let signInData = sign.value.get(key) as any[];
           if (signInData) {
               let day = 1;
               let continuous : any[] = [];
               signInData.forEach( (value, index) => {
                   if(signInData[index] === signInData[index+1] && value ==1) {
                       day++;
                   }else {
                       continuous.push(day);
                       day = 1;
                   }
               });
               return Math.max.apply(null,continuous);
           }
       }
       return 0;
    }

    function putDelayMsg( prop : Prop ) {
        prop.tag = getUUID();
        if (delayMsg.value.has(prop.key)) {
           let delayMsgs = delayMsg.value.get(prop.key) as any[];
           delayMsgs.push(prop);
           delayMsg.value.set(prop.key,delayMsgs);
        }else {
            let temp = [];
            temp.push(prop);
            delayMsg.value.set(prop.key,temp);
        }
    }

    onMounted(() => {
       cacheStore.value = new Map();
       ranking.value = new Map();
       delayMsg.value = new Map();
       sign.value = new Map();
       // 轮询清除过期的缓存
       setInterval(() => {
            if(cacheStore.value.size > 0) {
                Array.from(cacheStore.value.keys()).forEach( key => {
                    let data = cacheStore.value.get(key);
                    if (data) {
                        let nowDate = new Date().valueOf();
                        if (data.exp < nowDate && data.exp != -1) {
                            cacheStore.value.delete(key);
                        }
                    }
                });
            }
       },100);
        // 发送过期消息让Mitt进行通知 emitter.on('xxx', e => {  console.log(e) } )
        setInterval(() => {
            if(delayMsg.value.size > 0) {
                Array.from(delayMsg.value.keys()).forEach( key => {
                    let temp = delayMsg.value.get(key) as any[];
                    temp.forEach( item => {
                        let nowDate = new Date().valueOf();
                        if( item.exp < nowDate - 100 ) {
                            emitter.emit(item.key, item.data);
                            temp = temp.filter( dispose  => dispose .tag != item.tag);
                            delayMsg.value.set(item.key,temp);
                        }
                    });
                })
            }
        },100);
    });


    function putRanking( key : string , data : any) {
        if(ranking.value.has(key)) {
           let rank  = ranking.value.get(key) as any[];
           let temp = rank.find(item => item.data === data);
           if(temp) {
               let newVal =  rank.filter(item => item.data !== data );
               newVal.push({ data: data.toString() , score : temp.score + 1 });
               ranking.value.set(key,newVal);
           }else {
               rank.push({ data: data.toString() , score : 1 });
               ranking.value.set(key,rank);
           }
        }else {
           let temp = [] as any[];
           temp.push({ data: data.toString() , score: 1 });
           ranking.value.set(key,temp);
        }
    }

    function takeRanking( key : string , total : number , desc : boolean): any[] {
        let rank = ranking.value.get(key) as any[];
        if(desc) {
            rank.sort( ( a , b ) => b.score - a.score );
        }else {
            rank.sort( ( a , b ) => a.score - b.score );
        }
        return rank.slice(0, total != 1 ? total - 1 : total);
    }

    // 放入缓存
    function putCache( prop : Prop ) {
        cacheStore.value.set(prop.key,prop);
    }


    // 获取缓存
    function takeCache<T>( key : string ) : any {
        return cacheStore.value.get(key) as T;
    }

    // 加锁
    function lock( prop : Prop ) : boolean {
        if (getLock(prop.key)) {
            return false;
        }
        cacheStore.value.set(prop.key,prop);
        return true;
    }


    // 获取锁
    function getLock( key : string ) : boolean {
        return cacheStore.value.has(key);
    }

    // 解锁
    function unLock( key : string , id : any) {
        let lock = cacheStore.value.get(key);
        if( lock ) {
            if( lock.data == id ) {
                cacheStore.value.delete(key);
            }
        }
    }


    // 全局id
    function getUUID () {
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
            const r = Math.random() * 16 | 0
            const v = c === 'x' ? r : (r & 0x3 | 0x8)
            return v.toString(16)
        });
    }

    return { takeCache , putCache , unLock , lock , getLock , putRanking , takeRanking , getUUID , putDelayMsg , startSign , punchSetting , continuousClocking }
}

下面将针对每个主要功能模块提供使用场景及调用方式:

1. 缓存管理

// 创建一个Prop对象实例
const propExample = {
  exp: Date.now() + 60 * 1000, // 过期时间为1分钟后
  key: 'exampleKey',
  data: { someData: 'exampleValue' },
};

// 将数据放入缓存
putCache(propExample);

// 从缓存获取数据
const cacheData = takeCache<typeof propExample>('exampleKey');
console.log(cacheData.data.someData); // 输出:exampleValue

2. 消息延迟发送 

// 创建一个带有过期时间的Prop对象
const delayMsgExample = {
  exp: Date.now() + 5000, // 5秒后过期
  key: 'delayEvent',
  data: { message: 'Hello, delayed message!' },
};

// 将消息放入延迟队列
putDelayMsg(delayMsgExample);

// 假设在事件总线emitter中有监听'delayEvent'的处理函数
// emitter.on('delayEvent', (data) => console.log(data.message));

3. 用户签到打卡

// 设置用户的签到数据(假设一个月30天)
const signInData = new Array(30).fill(0);
punchSetting('user1', signInData);

// 用户进行签到
const isSigned = startSign('user1', 5); // 第5天签到
console.log(isSigned); // 输出:true

// 获取连续签到天数
const continuousDays = continuousClocking('user1');
console.log(continuousDays); // 输出:根据实际情况计算的连续签到天数

 4. 排行榜功能

// 添加或更新排行榜项
putRanking('gameScore', 'playerA', 100);
putRanking('gameScore', 'playerB', 200);
putRanking('gameScore', 'playerC', 150);

// 获取前3名,按降序排列
const topThree = takeRanking('gameScore', 3, true);
console.log(topThree);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值