在Vuex中存储观察者?Vue项目P5.js画布销毁触发问题咨询
在Vuex中管理P5.js画布销毁的观察者模式实现方案
嘿,很高兴看到你在Vue+Vuex的项目里整合P5.js!我来分享几个实用的方案,结合你提到的观察者思路来管理P5画布的销毁逻辑:
核心思路
我们可以在Vuex中维护P5实例的存储池和销毁观察者队列:
- 用
Map存储P5实例,方便按唯一标识(比如元素ID)快速查找和操作 - 用数组存储销毁回调(观察者),当触发销毁动作时,自动通知所有观察者执行后续逻辑
1. Vuex Store 配置
首先在你的Vuex store里定义对应的state、mutations和actions:
// store/index.js import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { // 存储P5实例,key为元素ID/唯一标识,value为p5对象 p5Instances: new Map(), // 存储销毁观察者:当画布销毁时触发的回调函数 destroyObservers: [] }, mutations: { // 添加P5实例到存储池 ADD_P5_INSTANCE(state, { id, instance }) { state.p5Instances.set(id, instance) }, // 移除指定P5实例 REMOVE_P5_INSTANCE(state, id) { state.p5Instances.delete(id) }, // 注册销毁观察者 REGISTER_DESTROY_OBSERVER(state, callback) { if (typeof callback === 'function' && !state.destroyObservers.includes(callback)) { state.destroyObservers.push(callback) } }, // 移除指定观察者 UNREGISTER_DESTROY_OBSERVER(state, callback) { state.destroyObservers = state.destroyObservers.filter(cb => cb !== callback) }, // 触发画布销毁(支持指定ID或销毁全部) TRIGGER_DESTROY(state, targetId) { // 处理销毁逻辑 if (targetId) { // 销毁指定实例 const instance = state.p5Instances.get(targetId) if (instance) { instance.destroy() state.p5Instances.delete(targetId) } } else { // 销毁所有实例 state.p5Instances.forEach(instance => instance.destroy()) state.p5Instances.clear() } // 通知所有观察者销毁完成 state.destroyObservers.forEach(callback => callback(targetId)) } }, actions: { // 创建P5实例并自动注册到Vuex async createP5Canvas({ commit }, { id, sketch }) { const p5Canvas = new p5(sketch, id) commit('ADD_P5_INSTANCE', { id, instance: p5Canvas }) return p5Canvas }, // 触发销毁动作(对外暴露的方法) destroyP5Canvas({ commit }, targetId) { commit('TRIGGER_DESTROY', targetId) } }, getters: { // 获取指定ID的P5实例 getP5Instance: (state) => (id) => { return state.p5Instances.get(id) } } })
2. 组件中使用示例
在你的P5画布组件里,结合Vuex的actions和mutations来完成实例创建、销毁监听:
<template> <div> <div id="my-p5-canvas"></div> <button @click="handleDestroyCanvas">销毁当前画布</button> </div> </template> <script> import { mapActions, mapMutations } from 'vuex' export default { name: 'P5Canvas', mounted() { // 创建P5实例并注册到Vuex this.createP5Canvas({ id: 'my-p5-canvas', sketch: (p) => { p.setup = () => { p.createCanvas(400, 400) p.background(240) } p.draw = () => { p.circle(p.mouseX, p.mouseY, 60) } // 也可以在sketch内部触发销毁(比如按空格键) p.keyPressed = () => { if (p.key === ' ') { this.destroyP5Canvas('my-p5-canvas') } } } }) // 注册一个销毁观察者:画布销毁后执行清理逻辑 const destroyCallback = (destroyedId) => { if (destroyedId === 'my-p5-canvas') { console.log('画布已销毁,执行清理操作') // 这里可以添加组件内的额外清理:比如解绑事件、重置数据等 } } this.REGISTER_DESTROY_OBSERVER(destroyCallback) // 把回调存到组件实例,方便卸载时移除 this._destroyObserver = destroyCallback }, methods: { ...mapActions(['createP5Canvas', 'destroyP5Canvas']), ...mapMutations(['REGISTER_DESTROY_OBSERVER', 'UNREGISTER_DESTROY_OBSERVER']), handleDestroyCanvas() { // 触发指定画布的销毁 this.destroyP5Canvas('my-p5-canvas') } }, beforeUnmount() { // 组件卸载时,移除观察者并销毁实例,防止内存泄漏 this.UNREGISTER_DESTROY_OBSERVER(this._destroyObserver) this.destroyP5Canvas('my-p5-canvas') } } </script>
3. 关键注意事项
- 内存泄漏防护:一定要在组件卸载时移除观察者并销毁P5实例,避免残留的回调或DOM元素占用内存
- 多画布场景适配:用
Map存储实例比数组更灵活,支持同时管理多个不同ID的P5画布 - 两种销毁方式兼容:如果需要在P5 sketch内部调用
remove(),记得同步触发Vuex的REMOVE_P5_INSTANCEmutation,保持store状态和实际DOM一致 - 观察者按需使用:如果你的项目不需要全局监听销毁事件,可以简化逻辑,只保留Vuex中实例的存储和销毁触发,去掉观察者队列即可
内容的提问来源于stack exchange,提问作者Chris Overgaauw
相关产品推荐
相关产品推荐

