如何设置事件侦听器回调到成员函数

时间:2014-05-09 14:57:58

标签: javascript html5 canvas

我在canvas对象周围编写一个面向对象的小包装器,我想设置一些按钮回调到实际的函数成员,而不是全局范围的函数(这样我可以参考上下文对象作为成员)。

function CanvasManager(canvasId) {
    this.canvas = document.getElementById(canvasId);    
    this.ctx = this.canvas.getContext('2d');    

    var imageLoader = document.getElementById('imageLoader');
    imageLoader.addEventListener('change', this.handleImage, false);

    var lineNumberField  = document.getElementById('linenumber');
    lineNumberField.addEventListener('change', this.onLineNumberChange, false);
}

function handleImage = function(e) {
    var reader = new FileReader();    
    var that = this;

    reader.onload = function(event){
        var img = new Image();

        img.onload = function(){
            that.canvas.width = img.width;
            that.canvas.height = img.height;
            that.ctx.drawImage(img,0,0);
        };

        img.src = event.target.result;
    };

    reader.readAsDataURL(e.target.files[0]);     
};

这在html中的内联脚本中调用:

<div id="canvas-container" style="display:none;">
    <canvas id="imageCanvas"></canvas>
</div>
    ...
<script lang="javascript">new CanvasManager('imageCanvas');</script>

这不起作用,因为在handleImage回调中,&#34;此&#34;我并没有引用CanvasManager实例,而是引用imageLoader实例。

我在这里做错了什么?

3 个答案:

答案 0 :(得分:4)

对不起评论 - 实际上,如果问题出在第二种方法中,我就误解了这个问题。

正如其他人暗示的那样,事件监听器将使用window作为this对象调用该函数。别担心,即使作为一名JS大师,我也同意它没有多大意义。

虽然您可以简单地将所有内容放入闭包中并将this放入常量var(即meself),但我的偏好是自定义调用函数始终具有特定的this引用。你可以这样做:

imageLoader.addEventListener('change', this.handleImage.bind(this), false);

bind()是一个相对较新的JavaScript函数,它为您提供一个新方法,表示原始方法,但使用特定的this上下文调用。一些JavaScript库具有与旧版浏览器兼容的等价物,例如Dojo的“hitch”。但是,由于您的代码无论如何都涉及<canvas>,因此您应该完全可以兼容。

答案 1 :(得分:2)

试试这个

function CanvasManager(canvasId) {
    this.canvas = document.getElementById(canvasId);    
    this.ctx = this.canvas.getContext('2d');    

    var imageLoader = document.getElementById('imageLoader');
    imageLoader.addEventListener('change', this.handleImage, false);

    var lineNumberField  = document.getElementById('linenumber');
    lineNumberField.addEventListener('change', this.onLineNumberChange, false);
    var self = this; // keep CanvasManager instance
    this.onLineNumberChange  = function(){
    };
    this.handleImage  = function(){
       console.log(self); // use CanvasManager instance
    }
}

答案 2 :(得分:1)

看起来您的函数handleImage不在您尝试使用的主函数(或类)之外。我会更新代码如下:

function CanvasManager(canvasId) {
    var me = this;

    me.canvas = document.getElementById(canvasId);    
    me.ctx = me.canvas.getContext('2d');    

    var imageLoader = document.getElementById('imageLoader');
    imageLoader.addEventListener('change', me.handleImage, false);

    var lineNumberField  = document.getElementById('linenumber');
    lineNumberField.addEventListener('change', me.onLineNumberChange, false);

    me.handleImage = function(e) {
        var reader = new FileReader();    

        reader.onload = function(event){
            var img = new Image();

            img.onload = function(){
                me.canvas.width = img.width;
                me.canvas.height = img.height;
                me.ctx.drawImage(img, 0, 0);
            };

            img.src = event.target.result;
        };

        reader.readAsDataURL(e.target.files[0]);     
    }
}

通过在函数内部移动handleImage,它现在在类的范围内。另外通过在方法的开头使用me = this来始终可以访问它的类实例,因为这将默认引用事件触发它的对象。