// 滚动触发动效插件 // 依赖 jquery、tweenmax、throttle-debounce // attr: x y scale rotation skewx skewy xpercent ypercent autoalpha delay repeat repeatdelay yoyo force3d transformorigin perspective *cycle *overwrite // linear, back, bounce, circ, cubic, ease, easelookup, elastic, expo, power0, power1, power2, power3, power4, quad, quart, quint, sine, strong, slowmo, stepped // ease.easein, ease.easeout, ease.easeinout ;(function($){ $.fn.xroll = function(opt){ var def = { xclass: 'xtween', // 到达触发点class throttle: 250, // 节流频率,默认250毫秒 debounce: 250, // 去抖频率,默认250毫秒 mobile: false, // 是否支持移动端 ie8: 1, // 是否支持ie8 0-完全不支持 1-不支持插件动画(支持触发xclass及回调函数) 2-不支持插件动画及触发xclass(仅支持回调函数) 3-不支持插件动画及回调函数(仅支持触发xclass) 4-完全支持 offset: 0, // 触发点偏移(px) ratio: 0.3, // 触发于视口高度的比例位置,默认视口垂直中点(如果滚动到页面底部仍无法触发此值,内部会计算一个临界值覆盖此值,以保证元素最终会移动到指定位置) stepmode: false, // 设定运动模式,默认到达触发点自行运动,true-步进模式运动 duration: 1, // 设定动画持续时间,默认1秒 stagger: -1, // target: true 时作用于子元素运动间隔时间,默认 序列运动 target: false, // 以父级位置触发子级动画 true-所有子元素,false-自身,css选择器-选中的子集 trans: {}, // 设定动画动作 onroll: function(elm,rate){}, // 回调函数 onin: function(elm){}, // 回调函数 onout: function(elm){} // 回调函数 }; var opt = $.extend(def, opt); var wheight = $(window).height(); var bheight = $('body').height(); var wstop = $(window).scrolltop(); this.each(function(i){ var _this = $(this); if(typeof(_this.data('xr-progress')) !== "undefined"){ console.log('[xroll] 重复调用!'); return; }else{ _this.data('xr-progress', 0); } var _attr = { idx: i, height: _this.outerheight(), top: _this.offset().top, progress: 0, // 获取自定义属性值 mobile: _this.data('xr-mobile') || opt.mobile, ie8: typeof(_this.data('xr-ie8')) !== "undefined" ? _this.data('xr-ie8') : opt.ie8, offset: _this.data('xr-offset') || opt.offset, ratio: _this.data('xr-ratio') || opt.ratio, stepmode: _this.data('xr-stepmode') || opt.stepmode, duration: _this.data('xr-duration') || opt.duration, stagger: _this.data('xr-stagger') >= 0 ? _this.data('xr-stagger') : opt.stagger, target: _this.data('xr-target') || opt.target, trans: !!_this.data('xr-trans') ? eval('(' + _this.data('xr-trans') + ')') : {} }; if(!$.support.leadingwhitespace && !_attr.ie8) return; if(!_attr.mobile && device().ismobile) return; if(_attr.ratio > (bheight - _attr.top + _attr.offset)/wheight){ _attr.ratio = (bheight - _attr.top + _attr.offset)/wheight; } if(_attr.stagger < 0){ _attr.stagger = _attr.trans.delay ? _attr.duration + _attr.trans.delay : _attr.stagger = _attr.duration; } _attr.trans = _attr.trans.autoalpha ? $.extend({}, true, opt.trans, _attr.trans) : $.extend({autoalpha: 0}, true, opt.trans, _attr.trans); if(!$.support.leadingwhitespace && _attr.ie8 < 4){ _attr.trans = $.extend({}, _attr.trans, {autoalpha: 1}); console.log(_attr.trans); } $(window).on('load', function(){ var _tm = new timelinemax(); if(_attr.stepmode){ opt.throttle = 0; } init(_tm); var throttled = null, debounced = null; if(opt.throttle > 0){ throttled = $.throttle(opt.throttle, function(){ scrollfn(_this, _attr, _tm); }); }else{ throttled = function(){ scrollfn(_this, _attr, _tm); }; } if(opt.debounce > 0){ debounced = $.debounce(opt.debounce, function(){ wheight = $(window).height(); bheight = $('body').height(); wstop = $(window).scrolltop(); scrollfn(_this, _attr, _tm); }); }else{ debounced = function(){ wheight = $(window).height(); bheight = $('body').height(); wstop = $(window).scrolltop(); scrollfn(_this, _attr, _tm); }; } $(window).on('scroll', throttled); $(window).on('resize orientationchange', debounced); }); function init(tm){ wheight = $(window).height(); bheight = $('body').height(); wstop = $(window).scrolltop(); _attr.height = _this.outerheight(); _attr.top = _this.offset().top; if(_attr.ratio > (bheight - _attr.top + _attr.offset)/wheight){ _attr.ratio = (bheight - _attr.top + _attr.offset)/wheight; } // 判断如果是父级就运动其子集或指定后代,否则运动元素自身 if(_attr.target){ if(typeof _attr.target == 'boolean'){ tm.staggerfrom(_this.children(), _attr.duration, _attr.trans, _attr.stagger); }else if(typeof _attr.target == 'string'){ tm.staggerfrom(_this.find(_attr.target), _attr.duration, _attr.trans, _attr.stagger); } }else{ tm.from(_this, _attr.duration, _attr.trans); } tm.stop(); scrollfn(_this, _attr, tm); } }); function scrollfn(ele, attr, tm){ wstop = $(window).scrolltop(); attr.progress = (wstop + wheight - attr.top + attr.offset) / (wheight * attr.ratio); ele.data('xr-progress', attr.progress); opt.onroll(ele, attr.progress); if(attr.stepmode){ if(attr.progress < 0){ if(ele.hasclass(opt.xclass)){ if(!$.support.leadingwhitespace){ switch(attr.ie8){ case 2: opt.onout(ele); break; case 3: ele.removeclass(opt.xclass); break; default: ele.removeclass(opt.xclass); opt.onout(ele); } }else{ ele.removeclass(opt.xclass); opt.onout(ele); } } if(!$.support.leadingwhitespace){ if(attr.ie8 > 3){ tm.progress(0); } }else{ tm.progress(0); } }else{ if(attr.progress > 1){ if(!ele.hasclass(opt.xclass)){ if(!$.support.leadingwhitespace){ switch(attr.ie8){ case 2: opt.onin(ele); break; case 3: ele.addclass(opt.xclass); break; default: ele.addclass(opt.xclass); opt.onin(ele); } }else{ ele.addclass(opt.xclass); opt.onin(ele); } } if(!$.support.leadingwhitespace){ if(attr.ie8 > 3){ tm.progress(1); } }else{ tm.progress(1); } }else{ if(!$.support.leadingwhitespace){ if(attr.ie8 > 3){ tm.progress(attr.progress); } }else{ tm.progress(attr.progress); } } } }else{ if(!ele.hasclass(opt.xclass)){ if(attr.progress >= 1){ if(!$.support.leadingwhitespace){ switch(attr.ie8){ case 1: ele.addclass(opt.xclass); opt.onin(ele); break; case 2: opt.onin(ele); break; case 3: ele.addclass(opt.xclass); break; default: ele.addclass(opt.xclass); tm.play(); opt.onin(ele); } }else{ ele.addclass(opt.xclass); tm.play(); opt.onin(ele); } } }else{ if(attr.progress < 0.1){ if(!$.support.leadingwhitespace){ switch(attr.ie8){ case 1: ele.removeclass(opt.xclass); opt.onout(ele); break; case 2: opt.onout(ele); break; case 3: ele.removeclass(opt.xclass); break; default: ele.removeclass(opt.xclass); tm.reverse(); opt.onout(ele); } }else{ ele.removeclass(opt.xclass); tm.reverse(); opt.onout(ele); } } } } } return this; }; })(jquery);