J'ai un écouteur d'événements qui ressemble à ceci:

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

Et j'ai une classe qui ressemble à ceci:

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

Je n'aime pas passer l'état, le wrapper, les enfants et le défilement en tant que variables. Je préférerais les stocker en classe lors de leur instanciation. Je comprends que le problème est que "ceci" ne sera pas transmis correctement et qu'il pourra être lié. Mais parce que la fonction d'accélérateur, je ne comprends pas comment passer cela.

0
Himmators 13 avril 2018 à 16:41

3 réponses

Meilleure réponse

Je recommanderais de séparer la limitation du défilement.

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

Vous feriez alors

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

Remarquez la fonction de flèche transmise à throttle.get qui appelle triggered sur l'instance scroll, au lieu de passer la méthode sans contexte.


Si vous voulez les mélanger tous les deux dans la même classe, je ne vois pas pourquoi throttle prendrait fn et v comme paramètres. Vous ne l'utilisez que pour appeler triggered de toute façon:

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

Avec

const scroll = new ThrottledScroll(state, wrapper, children);
window.addEventListener('scroll', scroll.get(50));
0
Bergi 13 avril 2018 à 15:46

L'ajout de la liaison au constructeur a fonctionné pour la classe, qui gère le problème de liaison lorsqu'il est appelé hors contexte:

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

L'auditeur d'événements devait avoir scroll.triggered contre triggered à moins que vous ne le déconstruisiez (const { triggered } = scroll) avant lui et nous n'avons pas vu cela:

window.addEventListener('scroll', scroll.throttle(
    scroll.triggered, 
    {state: state, wrapper: wrapper, children: children, scroll: scroll},
    50
))
0
ReyHaynes 13 avril 2018 à 15:07

Dans votre constructeur de classe, vous pouvez lier le contexte de vos méthodes de classe à la classe avec this.methodName = this.methodName.bind(this). ReyHaynes a raison, cela peut également être accompli en définissant les méthodes de classe en tant que fonctions fléchées, mais je pense que c'est toujours une fonctionnalité ES7 non confirmée, donc vous ne voudrez peut-être pas l'utiliser.

Si cela n’est pas clair ou n’aide pas, vous trouverez peut-être un contexte utile ici. C'est une ressource React, mais, si je comprends bien, votre problème est traité dans React tout le temps.

0
wassona 13 avril 2018 à 14:37