问题:将TypeScript对象属性指针传递给方法

时间:2020-09-15 20:41:54

标签: javascript typescript d3.js

我是TypeScript的新手,正在尝试使用D3.js创建一个具有两个句柄的简单范围滑块。

我为滑块对象创建了一个基本类:

export class VerticalRangeSlider{
    private sliderContainer:  d3.Selection<SVGGElement, any, HTMLDivElement, any>;
    private scale: d3.ScaleLinear<number, number>;
    
    private sliderTopBound: number;
    private sliderBottomBound: number;

    private handleTopY: number;
    private handleBottomY: number;
    private handleTop: d3.Selection<SVGCircleElement, any, HTMLDivElement, any>;
    private handleBottom: d3.Selection<SVGCircleElement, any, HTMLDivElement, any>;

constructor(slContainer: d3.Selection<SVGGElement, any, HTMLDivElement, any>, scl: d3.ScaleLinear<number, number>){
    this.sliderContainer = slContainer;
    this.scale = scl;

    this.sliderTopBound = 0;
    this.sliderBottomBound = scl.range()[0];
    this.handleTopY = this.sliderTopBound;
    this.handleBottomY = this.sliderBottomBound;

    this.initSlider();
}

这两个句柄是在initSlider方法中创建的。我有一个用于处理拖动事件的匿名函数,该函数调用moveHandle方法来重新渲染圆圈。

因为我发现 this。在匿名函数中具有不同的上下文,所以我在initSlider中声明了一个变量来保存指向父对象的指针:var parentObject = this;

   this.handleTop = this.sliderContainer.insert("circle", ".track-overlay")
    .attr("class", "handle")
    .attr("r", 9)
    .attr("cy", this.handleTopY)
    .attr("desc", this.handleTopY)
    .call(d3.drag()
    .on('drag', function(){
       parentObject.moveHandle(parentObject.handleTop, parentObject.handleTopY, d3.event.dy, parentObject.sliderTopBound, parentObject.handleBottomY);
    }));

    this.handleBottom = this.sliderContainer.insert("circle", ".track-overlay")
    .attr("class", "handle")
    .attr("r", 9)
    .attr("cy", this.handleBottomY)
    .attr("desc", this.handleBottomY)
    .call(d3.drag()
    .on('drag', function(){
       parentObject.moveHandle(parentObject.handleBottom, parentObject.handleBottomY, d3.event.dy, parentObject.handleTopY, parentObject.sliderBottomBound);
    }));

我遇到了moveHandle方法的问题:

private moveHandle(handle: d3.Selection<SVGCircleElement, any, HTMLDivElement, any>, currentPosition: number, increment: number, topBound: number, bottomBound:number): void {
    
        var legalIncrement: number;
        //upward movement
        if(Math.sign(increment) === -1){
            legalIncrement = increment <= (currentPosition - topBound) ? increment : (currentPosition - topBound);
            console.log("allowed increment: "+legalIncrement);
        }
        //downward movement
        else {
            legalIncrement = increment <= (bottomBound - currentPosition) ? increment : (bottomBound - currentPosition);
            console.log("allowed increment: "+legalIncrement);

        }
        
    if(legalIncrement !== 0){
        currentPosition = (currentPosition + legalIncrement)
        handle.attr("transform", "translate(0," + currentPosition + ")");
    }

}

当我尝试拖动圆时,它们会按预期进行短暂渲染,但随后会立即捕捉回到其原始位置。

但是,当我直接将指向父对象的指针传递到moveHandle中时,一切正常:parentObject: VerticalRangeSlider): void {

parentObject.handleBottomY = parentObject.handleBottomY + increment; parentObject.handleBottom.attr("cy", parentObject.handleBottomY);

最初的假设是我将指向父对象属性的指针传递给方法,但事实并非如此。我最好的理论是改为创建新对象。

我非常感谢对此行为的任何见解(以及为更好地构建我的JS / TS代码而提供的任何反馈)。

谢谢!

1 个答案:

答案 0 :(得分:0)

在您的代码中,最终需要引用父级。要变通解决此问题,您可以使用arrow functions。用function () {}格式定义的函数将创建自己的this,因此像您使用this一样,保留对父级parentObject的引用

另一方面,箭头功能(=>形式)不绑定自己的this 。这意味着箭头功能中的this指向父级this,您不需要引用:您可以直接使用this

我们也可以将drag处理程序更改为箭头函数。

这是您的代码,但有一些更改。这可能并不完全正确,因为我可能错过了一些意思:让我知道。

this.handleTop = this.sliderContainer.insert("circle", ".track-overlay")
  .attr("class", "handle")
  .attr("r", 9)
  .attr("cy", this.handleTopY)
  .attr("desc", this.handleTopY)
  .call(d3.drag()
  .on('drag', () =>
     this.moveHandle(this.handleTop, this.handleTopY, d3.event.dy, this.sliderTopBound, this.handleBottomY);
  );

this.handleBottom = this.sliderContainer.insert("circle", ".track-overlay")
.attr("class", "handle")
.attr("r", 9)
.attr("cy", this.handleBottomY)
.attr("desc", this.handleBottomY)
.call(d3.drag()
.on('drag', () => this.moveHandle(this.handleBottomY, this.handleTopY, d3.event.y, this.sliderBottomBound);
);

private moveHandle = (currentPosition: number, topBound: number, increment:number, bottomBound:number): void => {
        var legalIncrement: number;
        //upward movement
        if(Math.sign(increment) === -1){
            legalIncrement = increment <= (currentPosition - topBound) ? increment : (currentPosition - topBound);
            console.log("allowed increment: "+legalIncrement);
        }
        //downward movement
        else {
            legalIncrement = increment <= (bottomBound - currentPosition) ? increment : (bottomBound - currentPosition);
            console.log("allowed increment: "+legalIncrement);

        }
        
    if(legalIncrement !== 0){
        currentPosition = (currentPosition + legalIncrement)
        this.attr("transform", "translate(0," + currentPosition + ")");
    }

}
相关问题