You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 16:47:08