全屏幕滚动
同事A:全屏幕滚动很难吗?不是有手就行?
对于这个问题,我有些不知如何回答。
我纯纯的认为 fullPage.js 月收一万五千美元的JavaScript组件不是没有原因的。
大概是大数据先前没见过搜索过全屏滚动组件库,搜索到的都不好用。无奈之下我就纯手写了一下。
纯手写历程:
- 先写一个节流,避免滑动距离过多,屏幕乱串。
节流:n秒内,频繁触发,只有第一次执行
const throttle = useCallback(function (func: any, delay: number) {
let timer: any = null;
return function (this: any, ...args: any[]) {
if (!timer) {
timer = setTimeout(() => {
func.apply(this, args);
timer = null;
}, delay);
}
};
}, []);
- 滚轮向上滚/向下滚的时候改变页码
//全局变量
let currentPage = 1;
let scrolling = false;
function scrollUp(){
//你的函数体
}
function scrollDown(){
//我的部分函数体
if(scrolling) return;
//获取父容器
const wrapper: any = wrapperRef?.current;
wrapper.style.transition = `all 800ms cubic-bezier(.34,.86,.71,.95) 0s`;
if (currentPage === 1) {
wrapper.style.transform = `translate3d(0px, -${height}px, 0px)`;
setTimeout(() => {
currentPage = 2;
scrolling = false;
}, 800);
return;
}
if (currentPage === 2) {
wrapper.style.transform = `translate3d(0px, -${2 * height}px, 0px)`;
setTimeout(() => {
currentPage = 3;
scrolling = false;
}, 800);
return;
}
}
- pc端监听滚轮的动向
function scrollFunc(e: any) {
let el = e || window.event;
el.stopPropagation();
if (el.wheelDelta) {
if (el.wheelDelta > 0) {
//当鼠标滚轮向上滚动时
throttle(scrollUp(), 300);
}
if (el.wheelDelta < 0) {
//当鼠标滚轮向下滚动时
throttle(scrollDown(), 300);
}
} else if (e.detail) {
if (el.detail < 0) {
//当鼠标滚轮向上滚动时
throttle(scrollUp(), 300);
}
if (el.detail > 0) {
//当鼠标滚轮向下滚动时
throttle(scrollDown(), 300);
}
}
}
// 给页面绑定鼠标滚轮事件,针对火狐的非标准事件
window.addEventListener("DOMMouseScroll", scrollFunc); // 给页面绑定鼠标滚轮事件,针对Google,mousewheel非标准事件已被弃用,请使用 wheel事件代替
window.addEventListener("wheel", scrollFunc); // ie不支持wheel事件,若一定要兼容,可使用mousewheel
window.addEventListener("mousewheel", scrollFunc);
let startY = 0; // 触摸起始位置的 y 坐标
let endY = 0; // 触摸结束位置的 y 坐标
// 监听 touchstart 事件
document.addEventListener("touchstart", function (e) {
startY = e.touches[0].pageY;
});
// 监听 touchend 事件
document.addEventListener("touchend", function (e) {
endY = e.changedTouches[0].pageY;
const deltaY = endY - startY; // 计算 y 坐标的差值
if (deltaY > 0) {
throttle(scrollUp(), 300);
} else if (deltaY < 0) {
throttle(scrollDown(), 300);
}
});
总结:感觉没什么问题,但是page 和节流,和时间 的问题一直有偏差。
你会发现其实稍微滚一下鼠标滚轮mousewheel事件实际上会触发N多次。所以添加了节流并设一个setTimeout来让用户感觉"只是滚了-次滚轮"时mousewheel事件只触发一次,否则就会发生"好像我只滚了一下,但是页面却一连跳了好几页"的现象。
但是,笔记本的触摸板上有一个诡异的现象,似乎系统为了实现平滑滚动的效果还是其他原因(未考证),当你手指离开触摸板后mouserwheel依然还会执行一段时间,而且这段时间甚至会持续1-2秒,所以就会造成"貌似我只滚了一次,但是页面却跳了好几页"。同样的道理,假如你的手指一直在滚动,或者说PC上的滚轮一直在滚动(这个貌似比较难,鼠标的滚轮形状貌似决定了你不能一直拨动很久),当持续的时间超过这个setTimeout之后,就会触发第2次甚至第
3次mousewheel事件,页面就会跳。
解决的办法:
1.加大这个setTimeout的值。
2.加入一个控制变量scrolling,当开始滚动滚轮后scrolling=true.
将当每一屏的动画执行完毕后,这个信号量才置为false,这样就能极大减少用户误操作的次数了原理都是让一段时间内,mousewheel不能执行太多次。
但缺点是也可能会让某些用户觉得够不流畅
另外,手机端高度还不等于100vh哦!。
我是个追究细节的人。很多细节我处于无奈的地步。好吧!我承认自己平庸。
这种造轮子的事情还是留给大佬们吧!我还是适合站在巨人的肩膀上享受成果~
@fullpage/react-fullpage
npm i @fullpage/react-fullpage
安装和使用 @fullpage/react-fullpage 时遇到的疑难杂症
- Failed to parse
source map
from xxxx file
You can remove the warning by adding GENERATE_SOURCEMAP=false to your .env file
- TypeError: Cannot read property ‘destroy’ of undefined
意思就是说,ReactFullpage.Wrapper 的子元素必须有一个类名为section的元素。
是啊!我有。但是我是xxx.module.scss 写法。它检测不到
错误写法:也是我的写法-_-!!!
<ReactFullpage.Wrapper>
<div className={styles.section}>第一个页面</div>
<div className={styles.section}>第二个页面</div>
<div className={styles.section}>第三个页面</div>
<div className={styles.section}>第四个页面</div>
</ReactFullpage.Wrapper>
正确写法:
import ReactFullpage from "@fullpage/react-fullpage";
import { useKeyPress, useSize } from "ahooks";
import "./demo.css";
export function Demo() {
const size = useSize(document.querySelector("body"));
const [page, setPage] = useState(0);
const FullpageRef = useRef<any>(null);
useKeyPress("uparrow", () => {
//onKeyup();
// 如果.section 页面中有input输入框的话,在手机浏览器调起软键盘,键盘收起来时会导致height的时间差,导致页面乱串
// 哈哈哈,在移动端我就不调用向上的箭头 和 向下的箭头事件了
if (size) {
if (size?.width > 768) {
onKeyup();
}
}
});
useKeyPress("downarrow", () => {
// 如果.section 页面中有input输入框的话,在手机浏览器调起软键盘,键盘收起来时会导致height的时间差,导致页面乱串
// 哈哈哈,在移动端我就不调用向上的箭头 和 向下的箭头事件了
if (size) {
if (size?.width > 768) {
onKeydown();
}
}
//onKeydown();
});
useKeyPress("enter", () => {
onKeydown();
});
function onKeydown() {
if (nextRef) {
FullpageRef.current.moveSectionDown();
}
}
function onKeyup() {
if (nextRef) {
FullpageRef.current.moveSectionUp();
}
}
return (
<div>
<ReactFullpage
//上面的参数设置都写在这里,不用再写在构造函数里面
credits={{}}
// navigation={true}
scrollingSpeed={1000}
scrollOverflow={true}
scrollBar={true}
onLeave={(origin, destination) => {
setPage(destination.index);
}}
// afterLoad={(origin, destination) => {
// setPage(destination.index);
// }}
render={({ fullpageApi }) => {
if (fullpageApi) {
FullpageRef.current = fullpageApi;
}
return (
<ReactFullpage.Wrapper>
<div className="section">第一个页面</div>
<div className="section">第二个页面</div>
<div className="section">第三个页面</div>
<div className="section">第四个页面</div>
</ReactFullpage.Wrapper>
);
}}
/>
</div>
);
}
- 如何解决fullpage.js使用中滑轮上下滚动过快导致屏幕乱窜的问题?
fullpage可以通过设背参数来调节治轮的灵敏度,从而能决屏慕乱蜜的问题。
具体来说、在fullpage配置项中设置scrolOverlow:tue
、同时设置scrolBartrue
和scroingSpeed: 1000
、可以让滑轮滚动的速度变慢、并添加滚动条,更好地控制页面内容的滚动。此外,可以在.section
的css样式中添加overflow: hidden和height:100%来避免.section页面出现垂直滚动条。
- Remove “Made with Fullpage.js” from website
- fullpage.js的licenseKey不填写licenseKey,会涉及到侵权问题吗?
呃!我想是会的。知识付费无可厚非,何况他免费提供了3年多
我们来看作者 Alvaro Trigo 的表述
因为我的产品是一个开源的 Javascript 组件,我遇到的最大问题就是不得不与开发人员"争吵",他们认为每个客户端产品都应该对所有人免费。这就是为什么当我开始销售扩展时,我必须明确表示它们不是开源的。
生而为人,我还是有点自觉性的。于是我在npm上挖呀挖!
react-page-scroller
import ReactPageScroller from "react-page-scroller";
import { useKeyPress, useSize } from "ahooks";
const [page, setPage] = useState(0);
const size = useSize(document.querySelector("body"));
useKeyPress("uparrow", () => {
//onKeyup();
// 如果.section 页面中有input输入框的话,在手机浏览器调起软键盘,键盘收起来时会导致height的时间差,导致页面乱串
// 哈哈哈,在移动端我就不调用向上的箭头 和 向下的箭头事件了
if (size) {
if (size?.width > 768) {
onKeyup();
}
}
});
useKeyPress("downarrow", () => {
//onKeydown();
// 如果.section 页面中有input输入框的话,在手机浏览器调起软键盘,键盘收起来时会导致height的时间差,导致页面乱串
// 哈哈哈,在移动端我就不调用向上的箭头 和 向下的箭头事件了
if (size) {
if (size?.width > 768) {
onKeydown();
}
}
});
useKeyPress("enter", () => {
onKeydown();
});
function onKeydown() {
setPage((x) => {
if (x === 12) {
return 12;
}
return x + 1;
});
}
function onKeyup() {
setPage((x) => {
if (x === 0) {
return 0;
}
return x - 1;
});
}
<ReactPageScroller
pageOnChange={(page: number) => {
setPage(page);
}}
customPageNumber={page}
>
<div className="section">第一个页面</div>
<div className="section">第二个页面</div>
<div className="section">第三个页面</div>
<div className="section">第四个页面</div>
</ReactPageScroller>
非常棒!移动端的height!==100vh 它都处理了。给我省了不少麻烦
如果你有更好使的库也可以分享给我呀!让我们一起少走弯路!