Javascript:在拖动事件期间类属性变得未定义

Aci*_*ake 2 javascript class draggable addeventlistener

我对 Javascript 中的类很陌生,我已经被困了几天试图理解为什么我的属性在我的所有方法中都变得未定义......

我试图复制这一成一类,但因为我的属性未定义的每次调用一个方法是不成功的。

我在 stackoverflow 上找不到类似的问题,但如果有的话请联系我,因为我可能没有搜索正确的问题。

<div class="row" style="height: 800px;">
    <div class="col" id="container">
        <div class="card" style="width: 300px; border-top: solid 20px black;" id="dragcard">
            <div class="card-body">
                <p>Text</p>
            </div>
        </div>
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)
class DragEvents {

    dragCard = document.querySelector("#dragcard");
    container = document.querySelector("#container");

    currentX = 0;
    currentY = 0;
    initialX;
    initialY;

    constructor() {

        this.container.addEventListener("mousedown", this.dragStart, false);
        this.container.addEventListener("mouseup", this.dragEnd, false);
        this.container.addEventListener("mousemove", this.drag, false);

        console.log(this.currentX);//works, but I need this to work in my methods.
    }

    drag() {
        console.log("Drag");//fires
        console.log(this.currentX);//undefined
        console.log(this.currentY);//undefined
        console.log(this.initialX);//undefined
        console.log(this.initialY);//undefined
    }

    dragStart() {
        console.log("DragStart");//fires
    }

    dragEnd() {
        console.log("DragEnd");//fires
    }

}//End Class
var DragEvent = new DragEvents();
Run Code Online (Sandbox Code Playgroud)

Dan*_*umb 7

这是 webapp 开发中的一个常见问题,尤其是当您尝试使用实例方法作为事件处理程序时。

通常,当您调用类似

instance.method(foo);
Run Code Online (Sandbox Code Playgroud)

函数method被调用,this指向instancefoo作为唯一的参数。这是大多数人期望此代码的行为方式。

但是,instance.method(没有调用)只是对函数的引用。如果你这样做:

const bar = instance.method;
bar(foo);
Run Code Online (Sandbox Code Playgroud)

你会看到不同的行为。在这种情况下,bar调用时不this指向任何内容并foo作为唯一参数。这是因为该函数不再以instance您调用时的方式绑定instance.method(foo)

这正是你打电话时发生的事情

this.container.addEventListener("mousedown", this.dragStart, false);
Run Code Online (Sandbox Code Playgroud)

您传入对指向的函数的引用this.dragStart,但与您的类的连接丢失了。

有很多方法可以解决这个问题。它们都有效地执行相同的操作,即将事件处理程序绑定到您的类的实例:

箭头函数表达式 您可以使用箭头函数表达式将 的值绑定this到您的类:

constructor() {
  this.container.addEventListener("mousedown", (e) => this.dragStart(e), false);
  this.container.addEventListener("mouseup", (e) => this.dragEnd(e), false);
  this.container.addEventListener("mousemove", (e) => this.drag(e), false);
}
Run Code Online (Sandbox Code Playgroud)

bind 方法 您还可以使用该bind方法显式绑定this到函数引用

constructor() {
  this.container.addEventListener("mousedown", this.dragStart.bind(this), false);
  this.container.addEventListener("mouseup", this.dragEnd.bind(this), false);
  this.container.addEventListener("mousemove", this.drag.bind(this), false);
}
Run Code Online (Sandbox Code Playgroud)

ES6 方法定义 您还可以更改定义类方法的方式,以便将函数绑定到类的实例:

class DragEvents {

    /* ... */

    drag = () => { /* ... */ }

    dragStart = () => { /* ... */ }

    dragEnd = () => { /* ... */ }

}//End Class
Run Code Online (Sandbox Code Playgroud)