mirror of
https://github.com/ZeroCatDev/Classworks.git
synced 2025-12-08 22:03:09 +00:00
241 lines
5.1 KiB
JavaScript
241 lines
5.1 KiB
JavaScript
/**
|
|
* Vue 组件安全事件处理工具
|
|
* 防止组件卸载时的事件处理错误
|
|
*/
|
|
|
|
/**
|
|
* 创建安全的 Vue 组件混入,用于管理事件监听器
|
|
* @returns {Object} Vue mixin 对象
|
|
*/
|
|
export function createSafeEventMixin() {
|
|
return {
|
|
data() {
|
|
return {
|
|
_isDestroying: false,
|
|
_eventCleanupFunctions: []
|
|
}
|
|
},
|
|
|
|
methods: {
|
|
/**
|
|
* 安全地注册事件监听器
|
|
* @param {Function} registerFn - 注册事件的函数,返回清理函数
|
|
* @returns {Function} 清理函数
|
|
*/
|
|
$safeOn(registerFn) {
|
|
if (this._isDestroying) return () => {}
|
|
|
|
try {
|
|
const cleanup = registerFn()
|
|
if (typeof cleanup === 'function') {
|
|
this._eventCleanupFunctions.push(cleanup)
|
|
return cleanup
|
|
}
|
|
} catch (error) {
|
|
console.error('事件注册失败:', error)
|
|
}
|
|
|
|
return () => {}
|
|
},
|
|
|
|
/**
|
|
* 创建安全的事件处理器
|
|
* @param {Function} handler - 原始事件处理器
|
|
* @returns {Function} 安全的事件处理器
|
|
*/
|
|
$safeHandler(handler) {
|
|
return (...args) => {
|
|
if (this._isDestroying || !this.$el) return
|
|
|
|
try {
|
|
return handler.apply(this, args)
|
|
} catch (error) {
|
|
console.error('事件处理失败:', error)
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 安全地执行 DOM 操作
|
|
* @param {Function} domOperation - DOM 操作函数
|
|
*/
|
|
$safeDom(domOperation) {
|
|
if (this._isDestroying || !this.$el) return
|
|
|
|
try {
|
|
requestAnimationFrame(() => {
|
|
if (!this._isDestroying && this.$el) {
|
|
domOperation()
|
|
}
|
|
})
|
|
} catch (error) {
|
|
console.error('DOM 操作失败:', error)
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 清理所有事件监听器
|
|
*/
|
|
$cleanupEvents() {
|
|
this._isDestroying = true
|
|
|
|
this._eventCleanupFunctions.forEach(cleanup => {
|
|
try {
|
|
if (typeof cleanup === 'function') {
|
|
cleanup()
|
|
}
|
|
} catch (error) {
|
|
console.warn('事件清理失败:', error)
|
|
}
|
|
})
|
|
|
|
this._eventCleanupFunctions = []
|
|
}
|
|
},
|
|
|
|
beforeUnmount() {
|
|
this.$cleanupEvents()
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Socket 事件安全处理混入
|
|
*/
|
|
export const socketEventMixin = {
|
|
...createSafeEventMixin(),
|
|
|
|
methods: {
|
|
/**
|
|
* 安全地注册 socket 事件监听器
|
|
* @param {string} event - 事件名
|
|
* @param {Function} handler - 事件处理器
|
|
* @returns {Function} 清理函数
|
|
*/
|
|
$socketOn(event, handler) {
|
|
return this.$safeOn(() => {
|
|
const { on } = require('@/utils/socketClient')
|
|
return on(event, this.$safeHandler(handler))
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 为现有组件添加安全事件处理
|
|
* @param {Object} component - Vue 组件选项
|
|
* @returns {Object} 增强后的组件选项
|
|
*/
|
|
export function withSafeEvents(component) {
|
|
const safeMixin = createSafeEventMixin()
|
|
|
|
return {
|
|
...component,
|
|
mixins: [...(component.mixins || []), safeMixin],
|
|
|
|
// 增强现有的 beforeUnmount
|
|
beforeUnmount() {
|
|
// 调用原有的 beforeUnmount
|
|
if (component.beforeUnmount) {
|
|
try {
|
|
component.beforeUnmount.call(this)
|
|
} catch (error) {
|
|
console.error('原 beforeUnmount 执行失败:', error)
|
|
}
|
|
}
|
|
|
|
// 调用安全清理
|
|
if (this.$cleanupEvents) {
|
|
this.$cleanupEvents()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Composition API 版本的安全事件处理
|
|
*/
|
|
export function useSafeEvents() {
|
|
const { ref, onBeforeUnmount } = require('vue')
|
|
|
|
const isDestroying = ref(false)
|
|
const cleanupFunctions = ref([])
|
|
|
|
const safeOn = (registerFn) => {
|
|
if (isDestroying.value) return () => {}
|
|
|
|
try {
|
|
const cleanup = registerFn()
|
|
if (typeof cleanup === 'function') {
|
|
cleanupFunctions.value.push(cleanup)
|
|
return cleanup
|
|
}
|
|
} catch (error) {
|
|
console.error('事件注册失败:', error)
|
|
}
|
|
|
|
return () => {}
|
|
}
|
|
|
|
const safeHandler = (handler) => {
|
|
return (...args) => {
|
|
if (isDestroying.value) return
|
|
|
|
try {
|
|
return handler(...args)
|
|
} catch (error) {
|
|
console.error('事件处理失败:', error)
|
|
}
|
|
}
|
|
}
|
|
|
|
const safeDom = (domOperation) => {
|
|
if (isDestroying.value) return
|
|
|
|
try {
|
|
requestAnimationFrame(() => {
|
|
if (!isDestroying.value) {
|
|
domOperation()
|
|
}
|
|
})
|
|
} catch (error) {
|
|
console.error('DOM 操作失败:', error)
|
|
}
|
|
}
|
|
|
|
const cleanup = () => {
|
|
isDestroying.value = true
|
|
|
|
cleanupFunctions.value.forEach(fn => {
|
|
try {
|
|
if (typeof fn === 'function') {
|
|
fn()
|
|
}
|
|
} catch (error) {
|
|
console.warn('事件清理失败:', error)
|
|
}
|
|
})
|
|
|
|
cleanupFunctions.value = []
|
|
}
|
|
|
|
onBeforeUnmount(() => {
|
|
cleanup()
|
|
})
|
|
|
|
return {
|
|
isDestroying: isDestroying.value,
|
|
safeOn,
|
|
safeHandler,
|
|
safeDom,
|
|
cleanup
|
|
}
|
|
}
|
|
|
|
export default {
|
|
createSafeEventMixin,
|
|
socketEventMixin,
|
|
withSafeEvents,
|
|
useSafeEvents
|
|
}
|