function translateFun(translateArr){
//判断鼠标滚动方向
var str=window.navigator.userAgent.toLowerCase();//获取用户浏览器识别码,并转成小写
var mouseDire=1;
if(str.indexOf('firefox')!=-1){ //火狐浏览器
document.addEventListener('DOMMouseScorll',function(e){
//前推 -3 后拉 3
mouseDire=e.detail>0?1:-1;
})
}else{
document.onmousewheel=function(ev){ //谷歌 IE
var e=ev||window.event;
//前推 120 后拉-120
mouseDire=e.wheelDelta>0?-1:1;
}
}
// 初始化各需要做动画元素相关状态
var stateObj={};
$.each(translateArr,function(index){
var _this=this;
var target=$(this.target),
translateBox=target.parents(".translate-box"),
transformList=["scaleX","scaleY","translateX","translateY"],
animateType={init:Object.keys(this.animate.start)},
beChange=willChangePro(animateType.init),
animate={init:{start:Object.assign({},this.animate.start),end:Object.assign({},this.animate.end)}},
adapter=!!this.animate.adapter&&Object.keys(this.animate.adapter),
adapterObj={};
function willChangePro(type){
var hasTrans=type.filter(function(v){ return transformList.indexOf(v) > -1 });
return (hasTrans?"transform":"")+(type.indexOf("opacity")>0?",opacity":"");
}
function beAdapter(){
stateObj[index].siteStart=translateBox.offset().top+translateBox.height()*(parseFloat(_this.site.start)/100);
stateObj[index].siteEnd=translateBox.offset().top+translateBox.height()*(parseFloat(_this.site.end)/100);
var isInit=true;
if(!!adapter.length){ // 适配
adapter.sort(function(a, b){return b - a}); // 设备大小从大至小排序
$.each(adapter,function(i,k){
if($(window).width()<=k && (!!adapter[i+1] ? !($(window).width()< adapter[i+1]) : true)){ //小于自己并不小于自己后面那个
if(!stateObj[index].on[k]){ //只有到了已配置适配大小才执行函数,避免屏幕缩放反复执行
stateObj[index].beChange=willChangePro(animateType[k]);
mainScroll(stateObj[index],k);
}
isInit=false;
}
})
}
if(!!stateObj[index].on.init){
isInit=false;
}
isInit&&mainScroll(stateObj[index],"init");
}
$.each(adapter,function(i,k){
adapterObj[k]={
start:Object.assign({},animate.init.start,_this.animate.adapter[k].start),
end:Object.assign({},animate.init.end,_this.animate.adapter[k].end)
}
animateType[k]=[];
$.each(adapterObj[k].start,function(y,v){
if(v!==adapterObj[k].end[y]){
animateType[k].push(y);
}
});
});
Object.assign(animate,adapterObj);
stateObj[index]={
target:target,
translateBox:translateBox,
isbefore:true,isafter:false,
animateType:animateType, //
animate:animate, // 整理过的animate对象
thisState:{}, // 存放当前元素当前状态
willChange:'',
beChange:beChange,
on:{}
};
beAdapter();
$(window).resize(function(){
beAdapter();
})
function mainScroll(S,sizeType){
$.each(S.on,function(k,v){
// console.log(k);
console.log(sizeType);
if(k!==sizeType){
$(window).off("scroll",v);
delete S.on[k];
}
})
S.on[sizeType]=function(){
var sTop=$(window).scrollTop();
var anim=S.animate[sizeType];
var animtype=S.animateType[sizeType];
if(sTop<S.siteStart){ // 该元素动画开始前
$.each(animtype,function(i,key){
S.thisState[key]=parseFloat(anim.start[key]);
})
if(!S.isbefore && !!this.beforeCb){
this.beforeCb();
S.isbefore=true;
S.isafter=false;
}
if(mouseDire==1){
if(sTop-S.siteStart<100){
S.willChange=S.beChange;
}
}else{
if(S.siteStart-sTop<100){
S.willChange="auto"
}
}
}
if(sTop>=S.siteStart&&sTop<=S.siteEnd){ // 该元素动画进行时
var step=(sTop-S.siteStart)/(S.siteEnd-S.siteStart); // 当前已滚动到距离 / 总距离 (动画进行进度)
$.each(animtype,function(i,key){
S.thisState[key]=(parseFloat(anim.end[key])-parseFloat(anim.start[key]))*step + parseFloat(anim.start[key]);
})
S.isbefore=S.isafter=false;
}
if(sTop>S.siteEnd){ // 该元素动画完成后
$.each(animtype,function(i,key){
S.thisState[key]=parseFloat(anim.end[key]);
})
if(!S.isafter && !!this.afterCb){
this.afterCb();
S.isbefore=false;
S.isafter=true;
}
if(mouseDire==1){
if(sTop-S.siteEnd<100){
S.willChange="auto"
}
}else{
if(S.siteEnd-sTop<100){
S.willChange=S.beChange;
}
}
}
// console.log("matrix( "+scaleX+", 0, 0, "+scaleY+", "+transX+", "+transY+" )")
// console.log(S.willChange);
// console.log(S.thisState.scaleX);
// console.log(stateObj[1].thisState.translateY?stateObj[1].thisState.translateY:0);
S.target.css({ // 统一修改css
"transform":"matrix( "+((S.thisState.scaleX!=undefined)?S.thisState.scaleX:1)+", 0, 0, \
"+((S.thisState.scaleY!=undefined)?S.thisState.scaleY:1)+",\
"+(S.thisState.translateX?S.thisState.translateX:0)+", \
"+(S.thisState.translateY?S.thisState.translateY:0)+" )",
"opacity":(S.thisState.opacity!=undefined)?S.thisState.opacity:1,
"will-change":S.willChange?S.willChange:"auto"
})
}
$(window).on("scroll", S.on[sizeType]);
}
});
}
在这里插入代码片
示例:
demo.html
<div class="translate-box">
<div class="translate-wrap">
<div class="cat" id="cat"></div>
<div class="dog" id="dog"></div>
</div>
</div>
demo.css
body{height: 3000px;}
.translate-box{height: 300vh;}
.cat,.dog{width: 50px;height: 50px;background: rosybrown;}
.translate-wrap{position: -webkit-sticky;position: sticky;top:50px;}
demo.js
var translateArr=[
{
target:"#cat", // 需要执行动画的元素
animate:{ // 执行动画
start:{
scaleX:1,
translateX:"0",
opacity:1
},
end:{
scaleX:7,
translateX:"600px",
opacity:0
},
adapter:{ //适配 (可选,会继承初始配置)
768:{
start:{
scaleX:1,
translateX:"0",
opacity:1
},
end:{
scaleX:7,
translateX:"400px",
opacity:1
},
},
1200:{
start:{
scaleX:1,
scaleY:1,
translateX:"0",
opacity:1
},
end:{
scaleX:10,
scaleY:10,
translateX:"200px",
opacity:0.8
},
}
}
},
site:{ // 动画开始/结束位置 相对于父translate-box 的位置百分比 (必填)
start:50,
end:70
},
beforeCb:function(){ //执行前回调 (可选)
console.log("before");
$(this.target).addClass('before');
},
afterCb:function(){ //执行完后回调 (可选)
console.log("after")
$(this.target).addClass("after");
}
},
{
target:"#dog",
animate:{
start:{
scaleY:1,
translateY:"0",
translateX:"0"
},
end:{
scaleY:5,
translateY:"100px",
translateX:"400px",
}
},
site:{
start:10,
end:80
}
}
]
translateFun(translateArr);