Vue组件实现Canvas自适应容器 解决mounted阶段容器宽高为0问题
Vue Canvas自适应父容器尺寸解决方案
问题根因
你在mounted中获取offsetWidth为0主要有三个原因:
- 你给
.container设置了宽高为100%,如果它的父级元素没有显式设置固定宽高,百分比宽高无法计算出实际像素值,offsetWidth自然为0 - mounted钩子仅保证组件DOM挂载到文档树,但此时浏览器尚未完成最终的布局重绘,部分场景下会出现尺寸获取异常
- 你提供的代码中
data选项和methods选项之间缺少逗号,会导致语法报错
实现方案
建议使用ResizeObserver替代window.resize监听容器尺寸变化,它可以监听任意DOM元素的尺寸变化,比窗口resize覆盖场景更全,侧边栏收起、父元素布局变化导致的容器尺寸变更都能正常监听到。
修改后完整代码
<template lang="html"> <div class="container" ref="container"> <canvas ref="canvas" :width="width" :height="height"></canvas> </div> </template> <script> export default { name: "monster", data () { return { width: 512, height: 512, resizeObserver: null } }, methods: { resizeCanvas(){ const containerWidth = this.$refs.container.offsetWidth const containerHeight = this.$refs.container.offsetHeight // 防止容器尺寸为0导致画布异常 if (!containerWidth || !containerHeight) return // 如果需要适配高清屏,可以乘以 devicePixelRatio,不需要可直接删除dpr相关逻辑 const dpr = window.devicePixelRatio || 1 this.width = containerWidth * dpr this.height = containerHeight * dpr // 高清屏适配需要同步缩放canvas上下文,不需要可直接删除 const ctx = this.$refs.canvas.getContext('2d') ctx.scale(dpr, dpr) } }, mounted () { // 等待浏览器完成布局后再获取尺寸 this.$nextTick(() => { // 初始化ResizeObserver监听容器尺寸变化 this.resizeObserver = new ResizeObserver(this.resizeCanvas) this.resizeObserver.observe(this.$refs.container) // 首次调用初始化尺寸 this.resizeCanvas() }) }, unmounted() { // 销毁监听避免内存泄漏 if (this.resizeObserver) { this.resizeObserver.disconnect() } }, } </script> <style lang="css" scoped> .container { width: 100%; height: 100%; /* 可以根据业务需求设置最小宽高,避免容器尺寸为0 */ min-width: 300px; min-height: 300px; } canvas { /* 画布的CSS尺寸和容器保持一致,保证显示正常 */ width: 100%; height: 100%; } </style>
额外注意事项
需要确保.container的所有父级元素都有确定的宽高值,否则100%宽高无法计算出实际像素。
内容的提问来源于stack exchange,提问作者Valentin Regnault
相关产品推荐
相关产品推荐

