在 Vue 3 中,用 watchEffect 监听窗口宽度需先用 ref 包装 window.innerWidth 并手动绑定 resize 事件更新该 ref,再在 watchEffect 中读取 width.value 实现响应式列数计算,如 Math.max(1, Math.floor(width.value / 320)),最后 onUnmounted 清理事件监听。

在 Vue 3 中,用 watchEffect 监听窗口宽度并动态计算列表列数,核心是把 window.innerWidth 包装成响应式依赖,并在副作用中实时更新列数。它比手动监听 resize 事件 + onMounted/onUnmounted 更简洁,且自动追踪依赖、自动清理。
把窗口宽度转为响应式信号
Vue 本身不直接响应原生 DOM 属性,所以不能直接 watchEffect(() => window.innerWidth) —— 这不会触发重运行(缺少响应式依赖)。需要借助 ref 或 computed 拆解出可追踪的响应式值:
- 定义一个
ref存储当前宽度,比如const width = ref(window.innerWidth) - 在
watchEffect外部用window.addEventListener('resize', ...)手动更新该ref -
watchEffect内读取width.value,就能自动追踪变化
在 watchEffect 中计算列数逻辑
列数通常由容器宽度和单列最小宽度决定(例如卡片宽度 + 间距),常见策略是「向下取整」或「根据断点区间映射」:
- 简单线性计算:
Math.max(1, Math.floor(width.value / 320))(假设每列最小占 320px) - 响应式断点判断:
width.value - 结果建议也用
ref或computed暴露,方便模板中使用
记得清理 resize 监听器
watchEffect 本身不处理副作用清理,但 addEventListener 必须配对 removeEventListener,否则内存泄漏。推荐在 onUnmounted 中移除:
Vue 3 组合式 API 与 最佳实践,涵盖代码组织、useXxx 模式、组合式函数设计、Store 集成、响应式优化及功能抽取。
立即学习“前端免费学习笔记(深入)”;
- 声明一个监听函数变量,如
const handleResize = () => { width.value = window.innerWidth } - 挂载时添加:
window.addEventListener('resize', handleResize) - 卸载时移除:
onUnmounted(() => window.removeEventListener('resize', handleResize))
完整示例代码
组合式 API 中典型写法:
import { ref, watchEffect, onUnmounted } from 'vue'
export default {
setup() {
const width = ref(window.innerWidth)
const columnCount = ref(3)
const handleResize = () => {
width.value = window.innerWidth
}
window.addEventListener('resize', handleResize)
watchEffect(() => {
if (width.value < 768) columnCount.value = 1
else if (width.value < 1024) columnCount.value = 2
else columnCount.value = 3
})
onUnmounted(() => {
window.removeEventListener('resize', handleResize)
})
return { columnCount }
}
}
模板中即可直接用 {{ columnCount }} 或 v-for="i in columnCount" 渲染列结构。

















