分析 scrollReveal.js 源码

scrollReveal.js 动画实现是基于CSS3 transitiontransform 属性实现的。
动画: requestAnimationFrame,兼容 setTimeout 定时每秒60帧 刷新

  1. requestAnimFrame = (function(){
  2. return window.requestAnimationFrame ||
  3. window.webkitRequestAnimationFrame ||
  4. window.mozRequestAnimationFrame ||
  5. function( callback ){
  6. window.setTimeout(callback, 1000 / 60);
  7. };
  8. })();

滚动监听: 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 核心类实现

使用单例模式: 只提供一个核心类的实例, 定义私有的静态实例,通过存取器来访问实例;

  1. private static _instance = new ScrollRevealCore();
  2. public static get getInstance (): ScrollRevealCore {
  3. return ScrollRevealCore._instance;
  4. }

静态的动画渲染方法: requestAnimaFrame;
实现是多实例的,使用Map集合 _pluginFunMap 来存储各个实例的动画,使用 Set _optionsSet 集合来存储实例配置;

实现 updata 方法;

  1. private updateDom(el: HTMLElement): void {
  2. let _options: scrollRevealOptions | null = this.getElemQueryCond(el);
  3. if (_options === null) return;
  4. _options = <scrollRevealOptions>_options;
  5. let _pluginInter: pluginInterface = <pluginInterface>ScrollRevealCore._pluginFunMap.get(_options.queryCondition as string);
  6. let _pluginFunObject = _pluginInter._pluginFunObject;
  7. let __this = _pluginInter._this;
  8. if (!el.getAttribute(`${_options.queryCondition}-initialized`)) {
  9. _pluginFunObject.init.call(__this, el);
  10. el.setAttribute(`${_options.queryCondition}-initialized`, "true");
  11. }
  12. if (!this.isElementInViewport(el, _options.viewportFactor)) {
  13. if (_options.reset) {
  14. if(_pluginFunObject.reset) _pluginFunObject.reset.call(__this, el);
  15. }
  16. return;
  17. }
  18. if (el.getAttribute(`${_options.queryCondition}-complete`)) return;
  19. if (this.isElementInViewport(el, _options.viewportFactor)) {
  20. _pluginFunObject.animated.call(__this, el);
  21. // Without reset enabled, we can safely remove the style tag
  22. // to prevent CSS specificy wars with authored CSS.
  23. // 在不启用重置的情况下,我们可以安全地删除样式标签
  24. // 防止CSS与编辑过的CSS发生冲突。
  25. if (!_options.reset) {
  26. let time = _pluginFunObject.animatedTimes.call(__this, el);
  27. let setTimeFun = (el: HTMLElement, _opt: scrollRevealOptions) => {
  28. if(_pluginFunObject.clear) _pluginFunObject.clear.call(__this, el);
  29. el.setAttribute(`${_opt.queryCondition}-complete`,"true");
  30. if("complete" in _opt) (_options as {complete: (el?: HTMLElement) => void}).complete(el);
  31. }
  32. setTimeout(setTimeFun, time, el, _options);
  33. }
  34. return;
  35. }
  36. }

抽象类 ScrollReveal 的实现(所有的动画实现类的基类/父类)

  1. abstract class ScrollReveal{
  2. private scrollreveal = ScrollRevealCore.getInstance;
  3. constructor() {
  4. }
  5. // 子类构造器中调用
  6. protected setCore() {
  7. this.scrollreveal.scrollRevealOptions(this.getOptions(), this.getPluginFunObject, this);
  8. }
  9. protected getInstance() {
  10. return this.scrollreveal;
  11. }
  12. abstract getOptions(): scrollRevealOptions;
  13. abstract getPluginFunObject(el?: HTMLElement): pluginFunObject;
  14. }

setCore 方法,实现类中使用 core 类的构造器来添加配置以及动画;
两个抽取方法,子类必须实现 配置动画

原scrollReveal功能在默认类 ScrollReveal-default 中实现

继承类ScrollReveal,实现配置和动画方法,在构造器 最后调用父类 setCore 方法,让 core 类去渲染动画;
动画实现同 scrollReveal.js

插件接口实现类 ScrollReveal-plugin

继承类ScrollReveal,实现配置和动画方法,在构造器 最后调用父类 setCore 方法,让 core 类去渲染动画;

  1. constructor(pluginFunObject: pluginFunObject, options?: scrollRevealOptions) {
  2. super();
  3. this.coreInstance = super.getInstance();
  4. this.options = options ? this.coreInstance.extend(this.defaultOptions, options) : this.defaultOptions;
  5. this.pluginFunObject = pluginFunObject;
  6. super.setCore();
  7. }
  8. getOptions(): scrollRevealOptions {
  9. return this.options;
  10. }
  11. getPluginFunObject(el?: HTMLElement): pluginFunObject {
  12. return this.pluginFunObject;
  13. }

用户 new 一个实例必传参数 动画pluginFunObject 以及 选传参数 配置options;
具体的动画实现交由 core 类;