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

How to set an event listener callback to a member function

本文关键字:设置 成员 函数 回调 侦听器 事件      更新时间:2023-09-26

我正在为画布对象编写一个小的面向对象的包装器,并且我想将一些按钮回调设置为实际的函数成员,而不是全局作用域的函数(这样我就可以将上下文对象引用为成员)。

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回调中,"This"不是指CanvasManager实例,而是指imageLoader实例,这使我非常困惑。

我在这里做错了什么?

抱歉的评论-实际上,如果问题是在第二个方法内,我已经误解了你所描述的问题。

正如其他人所暗示的那样,事件侦听器将以window作为this对象调用该函数。别担心,即使作为JS专家,我也同意这没有多大意义。

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

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

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

try this

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
    }
}

看起来你的函数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,可以始终访问它的类实例,因为this将默认引用触发它的事件的对象。