分析 scrollReveal.js 源码
scrollReveal.js 动画实现是基于CSS3 transition 和 transform 属性实现的。
动画: requestAnimationFrame,兼容 setTimeout 定时每秒60帧 刷新
requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
})();
滚动监听: window.addEventListener('scroll', scrollHandler, false);
更新DOM: 遍历 DOM 树中所有带有 data-scroll-reveal 属性的元素,执行 updata(); 实现动画
updata 实现:初始化、在视区外( 判断动画次数 reset:true 即循环无线执行,重新初始化并清除动画延时)、在视区内(1. 执行动画;2. 判断动画次数 reset:false 即只执行一次,执行清除动画效果即清除style 中 由动画增加的样式);
TypeSctipt 实现 scrollReveal
core 核心类需要实现功能:
- 动画渲染方式: requestAnimationFrame;
- 滚动监听;
- 更新DOM: updata(), 只提供更新DOM框架,具体实现由其他类去实现
其他类实现 init(), ananimated(), reset(), clear(), animatedTimes();
使用 类 重构 scrollReveal
核心类 ScrollRevealCore,
抽象类 ScrollReveal,
具体实现:(默认类-实现原scrollReveal功能)ScrollRevealDefault,
(插件类-用户可以自由实现滚动动画)ScrollRevealPlugin,
ScrollReveal-core 核心类实现
使用单例模式: 只提供一个核心类的实例, 定义私有的静态实例,通过存取器来访问实例;
private static _instance = new ScrollRevealCore();
public static get getInstance (): ScrollRevealCore {
return ScrollRevealCore._instance;
}
静态的动画渲染方法: requestAnimaFrame;
实现是多实例的,使用Map集合 _pluginFunMap
来存储各个实例的动画,使用 Set _optionsSet
集合来存储实例配置;
实现 updata 方法;
private updateDom(el: HTMLElement): void {
let _options: scrollRevealOptions | null = this.getElemQueryCond(el);
if (_options === null) return;
_options = <scrollRevealOptions>_options;
let _pluginInter: pluginInterface = <pluginInterface>ScrollRevealCore._pluginFunMap.get(_options.queryCondition as string);
let _pluginFunObject = _pluginInter._pluginFunObject;
let __this = _pluginInter._this;
if (!el.getAttribute(`${_options.queryCondition}-initialized`)) {
_pluginFunObject.init.call(__this, el);
el.setAttribute(`${_options.queryCondition}-initialized`, "true");
}
if (!this.isElementInViewport(el, _options.viewportFactor)) {
if (_options.reset) {
if(_pluginFunObject.reset) _pluginFunObject.reset.call(__this, el);
}
return;
}
if (el.getAttribute(`${_options.queryCondition}-complete`)) return;
if (this.isElementInViewport(el, _options.viewportFactor)) {
_pluginFunObject.animated.call(__this, el);
// Without reset enabled, we can safely remove the style tag
// to prevent CSS specificy wars with authored CSS.
// 在不启用重置的情况下,我们可以安全地删除样式标签
// 防止CSS与编辑过的CSS发生冲突。
if (!_options.reset) {
let time = _pluginFunObject.animatedTimes.call(__this, el);
let setTimeFun = (el: HTMLElement, _opt: scrollRevealOptions) => {
if(_pluginFunObject.clear) _pluginFunObject.clear.call(__this, el);
el.setAttribute(`${_opt.queryCondition}-complete`,"true");
if("complete" in _opt) (_options as {complete: (el?: HTMLElement) => void}).complete(el);
}
setTimeout(setTimeFun, time, el, _options);
}
return;
}
}
抽象类 ScrollReveal 的实现(所有的动画实现类的基类/父类)
abstract class ScrollReveal{
private scrollreveal = ScrollRevealCore.getInstance;
constructor() {
}
// 子类构造器中调用
protected setCore() {
this.scrollreveal.scrollRevealOptions(this.getOptions(), this.getPluginFunObject, this);
}
protected getInstance() {
return this.scrollreveal;
}
abstract getOptions(): scrollRevealOptions;
abstract getPluginFunObject(el?: HTMLElement): pluginFunObject;
}
setCore 方法,实现类中使用 core 类的构造器来添加配置以及动画;
两个抽取方法,子类必须实现 配置 和 动画
原scrollReveal功能在默认类 ScrollReveal-default 中实现
继承类ScrollReveal,实现配置和动画方法,在构造器 最后调用父类 setCore 方法,让 core 类去渲染动画;
动画实现同 scrollReveal.js
插件接口实现类 ScrollReveal-plugin
继承类ScrollReveal,实现配置和动画方法,在构造器 最后调用父类 setCore 方法,让 core 类去渲染动画;
constructor(pluginFunObject: pluginFunObject, options?: scrollRevealOptions) {
super();
this.coreInstance = super.getInstance();
this.options = options ? this.coreInstance.extend(this.defaultOptions, options) : this.defaultOptions;
this.pluginFunObject = pluginFunObject;
super.setCore();
}
getOptions(): scrollRevealOptions {
return this.options;
}
getPluginFunObject(el?: HTMLElement): pluginFunObject {
return this.pluginFunObject;
}
用户 new 一个实例必传参数 动画pluginFunObject 以及 选传参数 配置options;
具体的动画实现交由 core 类;