分析 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 类;
