Web组件尺寸变化时如何更新其shadow DOM并重新渲染canvas?
实现方案说明
首先可以明确:ResizeObserver 是当前实现这个需求的最优选择,它可以精准监听任意元素的尺寸变化,不受视口变化、父元素布局调整、CSS属性切换等场景的限制,相比传统的window.resize监听、定时轮询等方案性能和准确率都高很多,完全适配Web组件的使用场景。
具体实现步骤
- 在自定义元素的类中提前声明
ResizeObserver实例、canvas元素的引用,方便后续调用和销毁 - 在组件的
connectedCallback生命周期中初始化观察者,监听自定义元素本身的尺寸变化 - 尺寸变化触发回调时,同步更新canvas的两个尺寸:CSS显示尺寸、画布实际像素尺寸(需要结合
window.devicePixelRatio处理,避免渲染内容模糊),再执行你的重绘逻辑 - 在组件的
disconnectedCallback生命周期中断开观察者监听,避免内存泄漏
代码示例
class CanvasComponent extends HTMLElement { constructor() { super(); this.attachShadow({ mode: 'open' }); this.shadowRoot.innerHTML = `<canvas></canvas>`; this.canvas = this.shadowRoot.querySelector('canvas'); this.ctx = this.canvas.getContext('2d'); // 初始化ResizeObserver this.resizeObserver = new ResizeObserver(entries => { const entry = entries[0]; const dpr = window.devicePixelRatio || 1; // 同步canvas画布实际像素尺寸 this.canvas.width = Math.round(entry.contentRect.width * dpr); this.canvas.height = Math.round(entry.contentRect.height * dpr); // 缩放上下文适配dpr,避免绘制内容模糊 this.ctx.scale(dpr, dpr); // 调用你的重绘方法 this.redraw(); }); } connectedCallback() { // 组件挂载后开始监听自身尺寸变化 this.resizeObserver.observe(this); } disconnectedCallback() { // 组件卸载后停止监听,清理内存 this.resizeObserver.disconnect(); } redraw() { // 这里写你自己的canvas绘制逻辑 const ctx = this.ctx; const displayWidth = this.canvas.width / window.devicePixelRatio; const displayHeight = this.canvas.height / window.devicePixelRatio; ctx.clearRect(0, 0, displayWidth, displayHeight); ctx.fillStyle = '#2196F3'; ctx.fillRect(10, 10, Math.min(displayWidth - 20, displayHeight -20), Math.min(displayWidth - 20, displayHeight -20)); } } // 注册自定义元素 customElements.define('canvas-component', CanvasComponent);
注意事项
- 如果你的重绘逻辑非常复杂,担心高频触发的性能问题,可以给
ResizeObserver的回调加一层防抖处理,控制重绘频率 - 不要直接修改canvas的style宽高作为画布尺寸,必须单独给
canvas.width和canvas.height赋值,不然会出现绘制内容拉伸模糊的问题
内容的提问来源于stack exchange,提问作者Steren
相关产品推荐
相关产品推荐

