Blazor Server应用中使用Canvas并在组件加载时触发初始化函数问题问询
问题原因
你遇到的报错是因为Blazor组件是动态渲染的,你把获取canvas节点的代码写在JS全局作用域直接执行时,Blazor组件还没完成渲染,id="canvas"的DOM节点还不存在,document.getElementById("canvas")返回null,调用getContext自然报错。纯前端静态页面的脚本在body末尾/onload阶段执行时DOM已经加载完成,所以没有这个问题。
解决步骤
1. 调整JS脚本逻辑
把全局变量赋值、初始化逻辑都封装到自定义函数内,不要在全局作用域直接执行DOM操作:
// 先声明全局变量,不要直接赋值 let canvas; let context; let circleData = []; // 你的circleList数据源保留原有定义即可 // 把原有onload逻辑封装为TestMe函数 window.TestMe = function() { // 函数调用时再获取DOM节点,此时Blazor组件已经渲染完成 canvas = document.getElementById("canvas"); context = canvas.getContext('2d'); var initX = canvas.width / 2; var initY = 0; circleList.forEach(function (element) { initY = initY + parseInt(element.score) + 10; var circleObject = { centerX: initX, centerY: initY, radius: parseInt(element.score), draging: false, overlapMark: false, subject: element.subject, } initY = initY + parseInt(element.score) + 20; circleData.push(circleObject); }); drawAll(); } // 原有drawAll、拖拽相关的函数保留不变
2. 调整Blazor组件逻辑
在组件渲染完成的生命周期钩子中调用JS初始化函数,仅第一次渲染完成后执行一次即可:
@page "/MyPage" @inject IJSRuntime JSRuntime; @implements IAsyncDisposable <button class="btn btn-primary" @onclick="CallJsMethod">Call Js Method</button> <div class="text-center py-5"> <canvas id="canvas" class="border" width="500px" ondrop="drop(event, element)" ondragover="allowDrop(event)"></canvas> </div> @code { // 标记是否已完成初始化,避免重复调用 private bool _isInitialized; protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender && !_isInitialized) { // 组件第一次渲染完成,canvas已挂载到DOM,调用JS初始化 await JSRuntime.InvokeVoidAsync("TestMe"); _isInitialized = true; } await base.OnAfterRenderAsync(firstRender); } private async Task CallJsMethod() { // 此处填写你需要调用的其他JS方法即可 // await JSRuntime.InvokeVoidAsync("你的其他JS方法名"); } // 组件销毁时可选清理Canvas相关资源,避免内存泄漏 public async ValueTask DisposeAsync() { // 如果有清理逻辑,此处调用对应的JS方法即可 // await JSRuntime.InvokeVoidAsync("你的清理逻辑函数名"); } }
优化建议
如果组件会被多次加载卸载,推荐用ElementReference传递canvas元素,避免固定id冲突,用法如下:
- 给canvas标签加ref属性:
<canvas @ref="CanvasRef" ...></canvas> - 组件代码中定义变量:
private ElementReference CanvasRef; - 调用JS时传递参数:
await JSRuntime.InvokeVoidAsync("TestMe", CanvasRef); - JS函数直接接收元素使用:
window.TestMe = function(canvas) { context = canvas.getContext('2d'); ... }
内容的提问来源于stack exchange,提问作者Baba
相关产品推荐
相关产品推荐

