AJAX返回页面时Canvas无法绘制的问题求助
问题描述
我正在开发一个通过AJAX返回搜索结果的网站,其他功能均正常,但每个搜索结果里的Canvas完全无法绘制。硬编码Canvas及绘图脚本时可正常工作,但移至处理查询的PHP文件后,仅显示空白Canvas。
相关代码
AJAX调用代码
function funSearch(val) { var xmlhttp; if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari xmlhttp=new XMLHttpRequest(); } else {// code for IE6, IE5 xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); } xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4 && xmlhttp.status==200) { document.getElementById('results').innerHTML=xmlhttp.responseText; } } url = "search.php?search=" + val; xmlhttp.open("GET",url,true); xmlhttp.send(); }
PHP输出的Canvas及调用代码(#为数据库动态值)
<canvas id='statsID#'></canvas> <script>funStats(statsID#, HP#, ATT#, SPA#, DEF#, SPD#, SPE#);</script>
绘图JavaScript函数
function funStats(id, hp, att, spa, def, spd, spe) { var canvas = document.getElementById(id); var hpContext = canvas.getContext('2d'); var attContext = canvas.getContext('2d'); var spaContext = canvas.getContext('2d'); var defContext = canvas.getContext('2d'); var spdContext = canvas.getContext('2d'); var speContext = canvas.getContext('2d'); canvas.width = 60; canvas.height = 60; var x = canvas.width / 2; var y = canvas.height / 2; var hpRadius = 28; var attRadius = 24; var spaRadius = 20; var defRadius = 16; var spdRadius = 12; var speRadius = 8; var startAngle = 1.5 * Math.PI; var hpEndAngle = ((hp / (256 / 2)) + 1.5) * Math.PI; var attEndAngle = ((att / (256 / 2)) + 1.5) * Math.PI; var spaEndAngle = ((spa / (256 / 2)) + 1.5) * Math.PI; var defEndAngle = ((def / (256 / 2)) + 1.5) * Math.PI; var spdEndAngle = ((spd / (256 / 2)) + 1.5) * Math.PI; var speEndAngle = ((spe / (256 / 2)) + 1.5) * Math.PI; hpContext.beginPath(); hpContext.arc(x, y, hpRadius, startAngle, hpEndAngle, false); hpContext.lineWidth = 2; hpContext.strokeStyle = '#42af4f'; hpContext.stroke(); attContext.beginPath(); attContext.arc(x, y, attRadius, startAngle, attEndAngle, false); attContext.lineWidth = 2; attContext.strokeStyle = '#d4bb49'; attContext.stroke(); spaContext.beginPath(); spaContext.arc(x, y, spaRadius, startAngle, spaEndAngle, false); spaContext.lineWidth = 2; spaContext.strokeStyle = '#4a95ca'; spaContext.stroke(); defContext.beginPath(); defContext.arc(x, y, defRadius, startAngle, defEndAngle, false); defContext.lineWidth = 2; defContext.strokeStyle = '#cc6a14'; defContext.stroke(); spdContext.beginPath(); spdContext.arc(x, y, spdRadius, startAngle, spdEndAngle, false); spdContext.lineWidth = 2; spdContext.strokeStyle = '#8e55d3'; spdContext.stroke(); speContext.beginPath(); speContext.arc(x, y, speRadius, startAngle, speEndAngle, false); speContext.lineWidth = 2; speContext.strokeStyle = '#ce58b0'; speContext.stroke(); }
问题原因及修复方案
核心问题
硬编码能工作是因为你给Canvas的ID加了引号(比如'statsID1'),但AJAX返回的代码里,funStats的第一个参数statsID#是无引号的,会被JS当作未定义的变量,导致document.getElementById(id)返回null,后续绘图逻辑全部失效。
修复步骤
1. 修正PHP输出的调用参数
给Canvas的ID参数加上单引号,确保JS识别为字符串:
<canvas id='statsID<?php echo $id; ?>'></canvas> <script>funStats('statsID<?php echo $id; ?>', <?php echo $HP; ?>, <?php echo $ATT; ?>, <?php echo $SPA; ?>, <?php echo $DEF; ?>, <?php echo $SPD; ?>, <?php echo $SPE; ?>);</script>
2. 优化绘图函数(可选,提升代码健壮性)
不需要重复获取Canvas上下文,复用一个即可,同时增加元素存在性检查:
function funStats(id, hp, att, spa, def, spd, spe) { var canvas = document.getElementById(id); if (!canvas) return; // 防止找不到元素报错 // 先设置尺寸,避免重置上下文丢失配置 canvas.width = 60; canvas.height = 60; var ctx = canvas.getContext('2d'); var x = canvas.width / 2; var y = canvas.height / 2; // 用数组简化重复逻辑 var configs = [ {radius:28, color:'#42af4f', value:hp}, {radius:24, color:'#d4bb49', value:att}, {radius:20, color:'#4a95ca', value:spa}, {radius:16, color:'#cc6a14', value:def}, {radius:12, color:'#8e55d3', value:spd}, {radius:8, color:'#ce58b0', value:spe} ]; var startAngle = 1.5 * Math.PI; configs.forEach(item => { var endAngle = ((item.value / 128) + 1.5) * Math.PI; // 简化256/2=128的计算 ctx.beginPath(); ctx.arc(x, y, item.radius, startAngle, endAngle, false); ctx.lineWidth = 2; ctx.strokeStyle = item.color; ctx.stroke(); }); }
3. 更可靠的AJAX交互方式(可选)
放弃返回HTML+脚本的方式,改为让PHP返回JSON数据,在AJAX回调里动态创建Canvas并调用绘图函数,避免脚本执行的潜在问题:
function funSearch(val) { var xmlhttp = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"); xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { var results = JSON.parse(xmlhttp.responseText); var container = document.getElementById('results'); container.innerHTML = ''; results.forEach(item => { // 创建Canvas var canvas = document.createElement('canvas'); canvas.id = 'statsID' + item.id; canvas.width = 60; canvas.height = 60; container.appendChild(canvas); // 调用绘图 funStats(canvas.id, item.hp, item.att, item.spa, item.def, item.spd, item.spe); // 添加其他结果内容,比如名称 var name = document.createElement('div'); name.textContent = item.name; container.appendChild(name); }); } } // 编码参数避免特殊字符问题 var url = "search.php?search=" + encodeURIComponent(val); xmlhttp.open("GET", url, true); xmlhttp.send(); }
对应的PHP返回JSON:
<?php // 数据库查询逻辑,假设得到$rows结果集 $results = []; foreach ($rows as $row) { $results[] = [ 'id' => $row['id'], 'hp' => $row['HP'], 'att' => $row['ATT'], 'spa' => $row['SPA'], 'def' => $row['DEF'], 'spd' => $row['SPD'], 'spe' => $row['SPE'], 'name' => $row['name'] ]; } header('Content-Type: application/json'); echo json_encode($results); ?>
内容的提问来源于stack exchange,提问作者Andrew Aguirre
相关产品推荐
相关产品推荐

