使JavaScript事件处理程序依赖于AJAX响应

时间:2014-09-30 22:56:54

标签: javascript ajax canvas addeventlistener

这里的JavaScript初学者:) 摘要:如何使事件监听器依赖于AJAX调用的结果?如果在调用之后添加了侦听器,则会在每次调用之后添加侦听器,从而累积侦听器。如果我在通话前这样做,我怎样才能将通话结果传递给它?听众似乎不会接受用户定义的论点。

详细信息:我正在尝试编写一个Web照片查看器,其中将在照片上标记面部。要在照片之间切换,我想使用AJAX。我的PHP脚本以JSON字符串的形式返回图片文件的名称和faces(x,y,radius)的坐标,例如

{"filename":"im1.jpg","faces":[{"x":129,"y":260,"radius":40},{"x":232,"y":297,"radius":40}]} 

一旦鼠标悬停在照片上,我想基于faces在画布上绘制圆圈。因此,我为mouseover事件创建了一个监听器。问题是如果我在AJAX调用之后添加侦听器,画布将获得多个侦听器并继续从先前的照片中绘制圆圈。因此看起来需要事先定义处理程序。但后来我很难将AJAX响应传递给它。我怎么能实现它?

到目前为止,我的HTML代码如下所示:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<canvas id="canvas" width="100" height="600"
    style="background-size: 100% 100%; border: 1px solid #FF0000;"></canvas>
<script>
    var image = new Image();
    var canvas = document.getElementById("canvas");
    var context = canvas.getContext("2d");

    canvas.addEventListener('mouseout', function(evt) {
        context.clearRect(0, 0, canvas.width, canvas.height);
        console.log("Canvas cleared");
    }, false);

    function loadXMLDoc() {
        var xmlhttp;
        if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
            xmlhttp = new XMLHttpRequest();
        }
        xmlhttp.onreadystatechange = function() {
            if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                var ajaxData = JSON.parse(xmlhttp.responseText);
                image.src = ajaxData.filename;
                image.onload = function() {
                    canvas.width = Math.round(canvas.height / image.height * image.width);
                    canvas.style.backgroundImage = "url('" + image.src + "')";
                }
                var faces = ajaxData.faces;

                canvas.addEventListener('mouseover', function(evt) {
                    console.log("Canvas entered");
                    console.log("Faces to mark: " + faces.length);

                    for (i = 0; i < faces.length; i++) {
                        context.beginPath();
                        context.arc(faces[i].x, faces[i].y, 
                            faces[i].radius, 0, 2 * Math.PI);
                        context.strokeStyle = "#00BBBB";
                        context.lineWidth = 1;
                        context.stroke();
                    }
                }, false);

            }
        }
        xmlhttp.open("GET", "get_data.php", true);
        xmlhttp.send();
    }
</script>

<button type="button" onclick="loadXMLDoc()">Change Content</button>
</body>
</html>

1 个答案:

答案 0 :(得分:1)

在添加新的{{}}之前,您可以remove the old listener。但更好的方法是将数据保存到事件侦听器之外的变量中,该变量在每次AJAX响应之后都会更新。然后,听众调用的函数根本不需要改变,它只是用你的面部数据引用变量。

修改

您可以在脚本顶部添加另一个变量:var faces;。您的其余脚本将可以访问它,就像您的其他变量一样。您最初不需要为其分配值。现在将您的mouseover侦听器置于与mouseout侦听器相同的级别。当您从服务器获取数据时,只需将其分配给面孔:faces = ajaxData.faces;(此处不要使用var,否则它会将面部定义为回调中的局部变量)。现在上面定义的faces变量将具有该数据,并且侦听器将具有对它的访问权。每次进行AJAX调用时,它都会用new覆盖旧面。您可能希望在mouseover侦听器中添加一个检查,以确保该变量包含数据。你可以这样检查:

if (typeof faces == 'object'){
    // your for loop can go here
}

在AJAX回调设置面值之前,typeof faces将等于'undefined'

在你掌握语言如何处理范围之前,JavaScript会让人感到困惑。 Check this out是一个很好的起点。