将纯脚本转换为 js class 以允许有多个实例无法读取道具(存在)

Converting plain script to js class to allow having multiple instances fails reading props (that exist)

假设我们有这个(有效的)脚本,但由于它使用 querySelector 仅适用于第一个实例:

if ( $( '.marquee' ).length ) {
    const marquee = document.querySelector( '.marquee__content' );
    let lerpScroll = 0;
    let lastScrollPos = 0;
    const maxSpeed = 20;

    function getScrollPercent() {
        let h = document.documentElement, 
            b = document.body,
            st = 'scrollTop',
            sh = 'scrollHeight';
        return (h[st]||b[st]) / ((h[sh]||b[sh]) - h.clientHeight) * 100;
    }

    function isInViewport() {
        const rect = marquee.getBoundingClientRect();
        const vOffset = marquee.offsetHeight;

        const percent = getScrollPercent() * -1;
        lerpScroll += (percent - lerpScroll) * 0.06;
        marquee.style.transform = `translateX(${lerpScroll * 4}%)`;

        // skew
        let scrollPos = window.scrollY;
        const container = marquee.querySelector( '.marquee__inner' );
        getDirection = scrollPos - lastScrollPos;
        lastScrollPos = scrollPos;

        if (getDirection > maxSpeed) {
            getDirection = maxSpeed;
        }
        if (getDirection < -maxSpeed) {
            getDirection = -maxSpeed;
        }

        container.style.transform = getDirection;

        window.requestAnimationFrame(isInViewport);
    }

    isInViewport();
}

所以我尝试将其转换为 class(并转储 jquery 代码):

class Marquee {
    constructor(el) {
      this.marquee = el;
      this.maxSpeed = 20;
      this.lerpScroll = 0;
      this.lastScrollPos = 0;
    }

    getScrollPercent() {
        let h = document.documentElement, 
            b = document.body,
            st = 'scrollTop',
            sh = 'scrollHeight';
        return (h[st]||b[st]) / ((h[sh]||b[sh]) - h.clientHeight) * 100;
    }

    isInViewport() {
        if (this.marquee) { /* <----- this is line 24 */
            console.log(this.marquee.offsetHeight);
            const vOffset = this.marquee.offsetHeight;

            const percent = this.getScrollPercent() * -1;
            this.lerpScroll += (percent - this.lerpScroll) * 0.06;
            this.marquee.style.transform = `translateX(${this.lerpScroll * 4}%)`;

            // skew
            let scrollPos = window.scrollY;
            const container = this.marquee.querySelector( '.marquee__inner' );
            let getDirection = scrollPos - this.lastScrollPos;
            this.lastScrollPos = scrollPos;

            if (getDirection > this.maxSpeed) {
                getDirection = this.maxSpeed;
            }
            if (getDirection < -this.maxSpeed) {
                getDirection = -this.maxSpeed;
            }

            container.style.transform = getDirection;

            window.requestAnimationFrame(this.isInViewport);
        }
    }

    init () {
        this.isInViewport();
    }
};

并像这样使用它:

if ( document.querySelectorAll( '.marquee' ).length ) {
    document.querySelectorAll( '.marquee__content' ).forEach((element) => {
        const m = new Marquee(element);
        m.init();
    })  
}

但是它引发了这个错误:

即使它打印了值

知道我做错了什么吗? 这是 fiddle https://jsfiddle.net/bkj3ry74/2/

所以问题是它抱怨它无法读取我可以看到 console.log

的道具
scripts.js?ver=1.0.0:24 Uncaught TypeError: Cannot read properties of undefined (reading 'marquee')
    at isInViewport

这条线

window.requestAnimationFrame(this.isInViewport);

您将来自 class 的函数作为 .requestAnimationFrame 的回调函数传递,这很好而且很花哨,但是因为您将它作为函数传递,在这种情况下它会得到一个函数内的新this。也许使用匿名箭头函数会保留 this 的上下文,即

window.requestAnimationFrame(() => this.isInViewport());