123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276 |
- /**
- * 存储localStorage
- */
- export const setStore = (name, content) => {
- if (!name) return;
- if (typeof content !== 'string') {
- content = JSON.stringify(content);
- }
- window.localStorage.setItem(name, content);
- }
- /**
- * 获取localStorage
- */
- export const getStore = name => {
- if (!name) return;
- return window.localStorage.getItem(name);
- }
- /**
- * 删除localStorage
- */
- export const removeStore = name => {
- if (!name) return;
- window.localStorage.removeItem(name);
- }
- /**
- * 获取style样式
- */
- export const getStyle = (element, attr, NumberMode = 'int') => {
- let target;
- // scrollTop 获取方式不同,没有它不属于style,而且只有document.body才能用
- if (attr === 'scrollTop') {
- target = element.scrollTop;
- }else if(element.currentStyle){
- target = element.currentStyle[attr];
- }else{
- target = document.defaultView.getComputedStyle(element,null)[attr];
- }
- //在获取 opactiy 时需要获取小数 parseFloat
- return NumberMode == 'float'? parseFloat(target) : parseInt(target);
- }
- /**
- * 页面到达底部,加载更多
- */
- export const loadMore = (element, callback) => {
- let windowHeight = window.screen.height;
- let height;
- let setTop;
- let paddingBottom;
- let marginBottom;
- let requestFram;
- let oldScrollTop;
- document.body.addEventListener('scroll',() => {
- loadMore();
- }, false)
- //运动开始时获取元素 高度 和 offseTop, pading, margin
- element.addEventListener('touchstart',() => {
- height = element.offsetHeight;
- setTop = element.offsetTop;
- paddingBottom = getStyle(element,'paddingBottom');
- marginBottom = getStyle(element,'marginBottom');
- },{passive: true})
- //运动过程中保持监听 scrollTop 的值判断是否到达底部
- element.addEventListener('touchmove',() => {
- loadMore();
- },{passive: true})
- //运动结束时判断是否有惯性运动,惯性运动结束判断是非到达底部
- element.addEventListener('touchend',() => {
- oldScrollTop = document.body.scrollTop;
- moveEnd();
- },{passive: true})
-
- const moveEnd = () => {
- requestFram = requestAnimationFrame(() => {
- if (document.body.scrollTop != oldScrollTop) {
- oldScrollTop = document.body.scrollTop;
- loadMore();
- moveEnd();
- }else{
- cancelAnimationFrame(requestFram);
- //为了防止鼠标抬起时已经渲染好数据从而导致重获取数据,应该重新获取dom高度
- height = element.offsetHeight;
- loadMore();
- }
- })
- }
- const loadMore = () => {
- if (document.body.scrollTop + windowHeight >= height + setTop + paddingBottom + marginBottom) {
- callback();
- }
- }
- }
- /**
- * 显示返回顶部按钮,开始、结束、运动 三个过程中调用函数判断是否达到目标点
- */
- export const showBack = callback => {
- let requestFram;
- let oldScrollTop;
- document.addEventListener('scroll',() => {
- showBackFun();
- }, false)
- document.addEventListener('touchstart',() => {
- showBackFun();
- },{passive: true})
- document.addEventListener('touchmove',() => {
- showBackFun();
- },{passive: true})
- document.addEventListener('touchend',() => {
- oldScrollTop = document.body.scrollTop;
- moveEnd();
- },{passive: true})
-
- const moveEnd = () => {
- requestFram = requestAnimationFrame(() => {
- if (document.body.scrollTop != oldScrollTop) {
- oldScrollTop = document.body.scrollTop;
- moveEnd();
- }else{
- cancelAnimationFrame(requestFram);
- }
- showBackFun();
- })
- }
- //判断是否达到目标点
- const showBackFun = () => {
- if (document.body.scrollTop > 500) {
- callback(true);
- }else{
- callback(false);
- }
- }
- }
- /**
- * 运动效果
- * @param {HTMLElement} element 运动对象,必选
- * @param {JSON} target 属性:目标值,必选
- * @param {number} duration 运动时间,可选
- * @param {string} mode 运动模式,可选
- * @param {function} callback 可选,回调函数,链式动画
- */
- export const animate = (element, target, duration = 400, mode = 'ease-out', callback) => {
- clearInterval(element.timer);
- //判断不同参数的情况
- if (duration instanceof Function) {
- callback = duration;
- duration = 400;
- }else if(duration instanceof String){
- mode = duration;
- duration = 400;
- }
- //判断不同参数的情况
- if (mode instanceof Function) {
- callback = mode;
- mode = 'ease-out';
- }
- //获取dom样式
- const attrStyle = attr => {
- if (attr === "opacity") {
- return Math.round(getStyle(element, attr, 'float') * 100);
- } else {
- return getStyle(element, attr);
- }
- }
- //根字体大小,需要从此将 rem 改成 px 进行运算
- const rootSize = parseFloat(document.documentElement.style.fontSize);
- const unit = {};
- const initState = {};
- //获取目标属性单位和初始样式值
- Object.keys(target).forEach(attr => {
- if (/[^\d^\.]+/gi.test(target[attr])) {
- unit[attr] = target[attr].match(/[^\d^\.]+/gi)[0] || 'px';
- }else{
- unit[attr] = 'px';
- }
- initState[attr] = attrStyle(attr);
- });
- //去掉传入的后缀单位
- Object.keys(target).forEach(attr => {
- if (unit[attr] == 'rem') {
- target[attr] = Math.ceil(parseInt(target[attr])*rootSize);
- }else{
- target[attr] = parseInt(target[attr]);
- }
- });
- let flag = true; //假设所有运动到达终点
- const remberSpeed = {};//记录上一个速度值,在ease-in模式下需要用到
- element.timer = setInterval(() => {
- Object.keys(target).forEach(attr => {
- let iSpeed = 0; //步长
- let status = false; //是否仍需运动
- let iCurrent = attrStyle(attr) || 0; //当前元素属性址
- let speedBase = 0; //目标点需要减去的基础值,三种运动状态的值都不同
- let intervalTime; //将目标值分为多少步执行,数值越大,步长越小,运动时间越长
- switch(mode){
- case 'ease-out':
- speedBase = iCurrent;
- intervalTime = duration*5/400;
- break;
- case 'linear':
- speedBase = initState[attr];
- intervalTime = duration*20/400;
- break;
- case 'ease-in':
- let oldspeed = remberSpeed[attr] || 0;
- iSpeed = oldspeed + (target[attr] - initState[attr])/duration;
- remberSpeed[attr] = iSpeed
- break;
- default:
- speedBase = iCurrent;
- intervalTime = duration*5/400;
- }
- if (mode !== 'ease-in') {
- iSpeed = (target[attr] - speedBase) / intervalTime;
- iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed);
- }
- //判断是否达步长之内的误差距离,如果到达说明到达目标点
- switch(mode){
- case 'ease-out':
- status = iCurrent != target[attr];
- break;
- case 'linear':
- status = Math.abs(Math.abs(iCurrent) - Math.abs(target[attr])) > Math.abs(iSpeed);
- break;
- case 'ease-in':
- status = Math.abs(Math.abs(iCurrent) - Math.abs(target[attr])) > Math.abs(iSpeed);
- break;
- default:
- status = iCurrent != target[attr];
- }
- if (status) {
- flag = false;
- //opacity 和 scrollTop 需要特殊处理
- if (attr === "opacity") {
- element.style.filter = "alpha(opacity:" + (iCurrent + iSpeed) + ")";
- element.style.opacity = (iCurrent + iSpeed) / 100;
- } else if (attr === 'scrollTop') {
- element.scrollTop = iCurrent + iSpeed;
- }else{
- element.style[attr] = iCurrent + iSpeed + 'px';
- }
- } else {
- flag = true;
- }
- if (flag) {
- clearInterval(element.timer);
- if (callback) {
- callback();
- }
- }
- })
- }, 20);
- }
|