【问题标题】:How can I access a class as "this" when adding event listeners, using bind?使用绑定添加事件侦听器时,如何将类作为“this”访问?
【发布时间】:2018-04-13 13:41:34
【问题描述】:

我有一个如下所示的事件监听器:

window.addEventListener('scroll', scroll.throttle(
    triggered, 
    {state: state, wrapper: wrapper, children: children, scroll: scroll},
    50
));

我有一个看起来像这样的类:

Scroll = class{
    constructor(){
        this.on = true; 
    }
    throttle(fn, v, wait){
        var time = Date.now();
        return () => {
            if ((time + wait - Date.now()) < 0 && this.on) {
                fn(v);
                time = Date.now();
            }
        }
    }
    triggered(o){
        if(o.state.check  !== 0){
            o.scroll.on = false;
            o.wrapper.classList.toggle('flic-down', o.state.check === 1)
            o.wrapper.classList.toggle('flic-up', o.state.check === -1)
            o.state.update();

            o.wrapper.classList.add('flic-transition')
            setTimeout(()=>{this.changeDone(o)}, 1200);
        }
    }
    changeDone(o) {
        o.wrapper.classList.remove('flic-transition', 'flic-up', 'flic-down');
        o.children.setClasses(o.state.state);
        o.wrapper.getElementsByClassName('flic-active')[0].scrollIntoView(true);
        o.scroll.on = true;
    }
},

我不喜欢将 state、wrapper、children 和 scroll 作为变量传递。在实例化它们时,我更愿意将它们存储在类中。我知道问题是“this”不会正确传递并且可以绑定。但是因为节流功能我不明白如何通过这个。

【问题讨论】:

  • 只是一个问题:这是有效的 JavaScript 吗?如果是这样,我全神贯注!我没有意识到你可以使用这种语法
  • @ControlAltDel 是什么让你认为它不是?
  • 我没有看到 this 有任何问题 - 你已经在到处使用箭头函数了。您是否刚刚尝试将它们设为实例属性?
  • 将您的方法类(如throttle(fn, v, wait){})更改为箭头方法类函数有帮助吗? throttle = (fn, v, wait) =&gt; {}。如果将所有方法类更改为箭头,可能会保留 this 的上下文。
  • @ReyHaynes 你不能在课堂上这样做。此外,问题不是油门(),而是触发()。也许我必须在几个实例中绑定,我尝试绑定到事件侦听器和节流响应的函数等。

标签: javascript


【解决方案1】:

我建议将节流与滚动分开。

class Throttle {
    constructor() {
        this.on = true; 
    }
    get(fn, wait) {
        var time = Date.now();
        return (...args) => {
            if ((time + wait - Date.now()) < 0 && this.on) {
                fn(...args);
                time = Date.now();
            }
        }
    }
}

class Scroll {
    constructor(state, wrapper, children) {
        this.state = state;
        this.wrapper = wrapper;
        this.children = children;
        this.throttle = new Throttle();
    }
    triggered() {
        if (this.state.check !== 0) {
            this.throttle.on = false;
            this.wrapper.classList.toggle('flic-down', this.state.check === 1)
            this.wrapper.classList.toggle('flic-up', this.state.check === -1)
            this.state.update();

            this.wrapper.classList.add('flic-transition')
            setTimeout(()=>{this.changeDone()}, 1200);
        }
    }
    changeDone() {
        this.wrapper.classList.remove('flic-transition', 'flic-up', 'flic-down');
        this.children.setClasses(this.state.state);
        this.wrapper.getElementsByClassName('flic-active')[0].scrollIntoView(true);
        this.throttle.on = true;
    }
}

你会这样做

const scroll = new Scroll(state, wrapper, children);
window.addEventListener('scroll', scroll.throttle.get(() => scroll.triggered(), 50));

注意传递给throttle.get 的箭头函数在scroll 实例上调用triggered,而不是在没有上下文的情况下传递方法。


如果你想将它们混合在同一个类中,我不明白为什么throttle 会采用fnv 作为参数。反正你只是用它来调用triggered

class ThrottledScroll {
    constructor(state, wrapper, children) {
        this.state = state;
        this.wrapper = wrapper;
        this.children = children;
        this.throttle = new Throttle();
        this.on = true; 
    }
    get(wait) {
        var time = Date.now();
        return () => {
            if ((time + wait - Date.now()) < 0 && this.on) {
                this.triggered();
                time = Date.now();
            }
        }
    }
    triggered() {
        if (this.state.check !== 0) {
            this.on = false;
            this.wrapper.classList.toggle('flic-down', this.state.check === 1)
            this.wrapper.classList.toggle('flic-up', this.state.check === -1)
            this.state.update();

            this.wrapper.classList.add('flic-transition')
            setTimeout(()=>{this.changeDone()}, 1200);
        }
    }
    changeDone() {
        this.wrapper.classList.remove('flic-transition', 'flic-up', 'flic-down');
        this.children.setClasses(this.state.state);
        this.wrapper.getElementsByClassName('flic-active')[0].scrollIntoView(true);
        this.on = true;
    }
}

const scroll = new ThrottledScroll(state, wrapper, children);
window.addEventListener('scroll', scroll.get(50));

【讨论】:

  • 问题是在回调中,changeDone把throttle.on再次设置为true
  • @Himmators 当然,这有什么问题?
  • 啊,好的,我知道你现在做了什么,有道理,会试试!
【解决方案2】:

在您的类构造函数中,您可以使用this.methodName = this.methodName.bind(this) 将类方法的上下文绑定到类。 ReyHaynes 是对的,这也可以通过将类方法定义为箭头函数来实现,但我相信这仍然是一个未经证实的 ES7 特性,所以你可能不想使用它。

如果不清楚或没有帮助,您可能会发现一些有用的上下文 here。这是一个 React 资源,但是,如果我理解正确的话,你的问题是 React 一直在处理的问题。

【讨论】:

    【解决方案3】:

    将绑定添加到适用于该类的构造函数,该类在脱离上下文调用时处理绑定问题:

    Scroll = class{
        constructor(){
            this.on = true; 
            this.triggered = this.triggered.bind(this)
            this.changeDone = this.changeDone.bind(this)
        }
        throttle(fn, v, wait){
            var time = Date.now();
            return () => {
                if ((time + wait - Date.now()) < 0 && this.on) {
                    fn(v);
                    time = Date.now();
                }
            }
        }
        triggered(o){
            if(o.state.check  !== 0){
                o.scroll.on = false;
                o.wrapper.classList.toggle('flic-down', o.state.check === 1)
                o.wrapper.classList.toggle('flic-up', o.state.check === -1)
                o.state.update();
    
                o.wrapper.classList.add('flic-transition')
                setTimeout(()=>{this.changeDone(o)}, 1200);
            }
        }
        changeDone(o) {
            o.wrapper.classList.remove('flic-transition', 'flic-up', 'flic-down');
            o.children.setClasses(o.state.state);
            o.wrapper.getElementsByClassName('flic-active')[0].scrollIntoView(true);
            o.scroll.on = true;
        }
    }
    

    事件侦听器需要有scroll.triggered vs triggered,除非你在它之前解构 (const { triggered } = scroll) 而我们没有看到:

    window.addEventListener('scroll', scroll.throttle(
        scroll.triggered, 
        {state: state, wrapper: wrapper, children: children, scroll: scroll},
        50
    ))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-04-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多