如何避免向<head>添加CSS时的内存泄漏?Vue钩子优化求助
解决Vue全局样式钩子的内存泄漏问题
你的问题核心在于只跟踪了样式是否被注入,没管理使用该样式的组件数量,导致组件卸载后样式标签无法被清理。用引用计数的方式就能解决,而且不会阻碍垃圾回收——因为我们不需要存储组件实例,只记录使用次数即可。
修改后的实现如下:
// 用Map存储样式的引用计数和对应的style元素,key是css字符串 const injectedStyles = new Map<string, { count: number; element: HTMLStyleElement }>() function useGlobalStyles(cssStyles: string) { onBeforeMount(() => { const existingEntry = injectedStyles.get(cssStyles) if (existingEntry) { // 已有组件在用这个样式,计数+1 existingEntry.count++ return } // 第一次注入,创建style元素并添加到head const styleEl = document.createElement('style') styleEl.textContent = cssStyles document.head.appendChild(styleEl) // 存入Map,初始计数为1 injectedStyles.set(cssStyles, { count: 1, element: styleEl }) }) // 组件卸载时处理计数和样式清理 onUnmounted(() => { const entry = injectedStyles.get(cssStyles) if (!entry) return entry.count-- // 当计数为0时,移除style标签并从Map中删除记录 if (entry.count === 0) { document.head.removeChild(entry.element) injectedStyles.delete(cssStyles) } }) }
关键说明:
- 用
Map替代Set,每个样式条目存储引用计数和对应的DOM元素,完全不涉及组件实例的存储,不会干扰GC - 组件挂载时,若样式已存在就增加计数,不存在则创建并初始化计数
- 组件卸载时减少计数,只有当所有使用该样式的组件都卸载后(计数归0),才真正删除style标签并清理Map中的记录
- 这种方式既保证了全局样式不会重复注入,又能在无人使用时自动清理,彻底解决内存泄漏问题
内容的提问来源于stack exchange,提问作者Alex l.
相关产品推荐
相关产品推荐

