将纯脚本转换为 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());
假设我们有这个(有效的)脚本,但由于它使用 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());