如何在编写HTML Canvas代码时避免重复传递context上下文
实现思路与代码示例
方案1:轻量全局封装(最适配小项目需求)
核心逻辑是把canvas上下文、常用状态参数都存在全局作用域,提前封装好所有绘图工具函数,框架自动执行初始化逻辑和render循环,用户只需要实现setup和draw两个函数即可。
首先写通用框架基础代码,只需要写一次就可以在所有同类型小项目中复用:
// 框架基础逻辑,无需用户修改 let ctx; let canvas; // 预设全局常用变量,可直接在业务代码中调用 let mouseX = 0; let mouseY = 0; let width; let height; // 页面加载后自动执行初始化 window.onload = () => { // 自动创建canvas节点,也可以替换为获取页面中已有的canvas canvas = document.createElement('canvas'); document.body.appendChild(canvas); ctx = canvas.getContext('2d'); width = canvas.width = window.innerWidth; height = canvas.height = window.innerHeight; // 监听鼠标事件更新全局坐标 canvas.addEventListener('mousemove', e => { mouseX = e.offsetX; mouseY = e.offsetY; }) // 执行用户编写的初始化函数 if (typeof setup === 'function') setup(); // 启动渲染循环 if (typeof draw === 'function') { function loop() { draw(); requestAnimationFrame(loop); } loop(); } } // 封装绘图函数,自动携带全局上下文,无需用户传参 function drawPoint(pos, radius = 5, color = '#000') { ctx.fillStyle = color; ctx.beginPath(); ctx.arc(pos.x, pos.y, radius, 0, Math.PI * 2); ctx.fill(); } // 可按照同样规则封装其他常用绘图函数,比如drawLine、drawRect、drawText等
编写业务代码时完全符合你期望的调用形式,不需要处理上下文相关逻辑:
// 业务代码,和p5.js用法一致 function setup() { // 写初始化逻辑,比如修改画布尺寸、定义全局业务变量 canvas.width = 800; canvas.height = 600; } function draw() { // 清屏可以直接操作全局ctx,也可以封装成background方法调用 ctx.clearRect(0, 0, width, height); // 调用绘图函数不需要传context drawPoint(new Vector(mouseX, mouseY), 6); drawPoint(new Vector(100, 100), 5, 'red'); }
方案2:闭包封装(避免全局污染,适配中等规模项目)
如果不想过多污染全局作用域,可以把整个框架包在立即执行函数中,只把需要暴露给用户的方法和变量挂载到window上:
(function() { let ctx; let canvas; let mouseX = 0; let mouseY = 0; // 内部封装绘图函数 function drawPoint(pos, radius = 5, color = '#000') { ctx.fillStyle = color; ctx.beginPath(); ctx.arc(pos.x, pos.y, radius, 0, Math.PI * 2); ctx.fill(); } // 只暴露需要给用户调用的内容到全局 window.drawPoint = drawPoint; Object.defineProperties(window, { mouseX: { get: () => mouseX }, mouseY: { get: () => mouseY } }) // 初始化、循环逻辑和方案1一致 window.onload = () => { // 初始化canvas、监听事件逻辑不变 if (window.setup) window.setup(); if (window.draw) { function loop() { draw(); requestAnimationFrame(loop); } loop(); } } })()
可选优化方向
- 封装更多常用工具方法,比如
background(color)清屏、stroke(color)设置描边、fill(color)设置填充,全部内部操作全局上下文,无需用户传参 - 新增
frameCount、deltaTime等常用动画全局变量,方便动画逻辑开发 - 如果需要支持多画布场景,可以扩展为实例化模式,小项目用单全局实例足够满足需求
内容的提问来源于stack exchange,提问作者Himanshu Jangid
相关产品推荐
相关产品推荐

