【问题标题】:How to include GreenSock plugin for ScrollMagic in a ReactJS environment?如何在 ReactJS 环境中包含 ScrollMagic 的 GreenSock 插件?
【发布时间】:2018-05-07 23:39:42
【问题描述】:

如何在我的 ReactJS 项目中包含适用于 ScrollMagic 的 Greensock 插件?

ScrollMagic 的作者制作了插件来整合 GreenSock 和 Velocity 等库。当您像这样简单地将它们包含在您的 html 文档的头部时,这些效果很好

<script type="text/javascript" src="js/lib/greensock/TweenMax.min.js"></script>
<script type="text/javascript" src="scrollmagic/uncompressed/ScrollMagic.js"></script>
<script type="text/javascript" src="scrollmagic/uncompressed/plugins/animation.gsap.js"></script>

但是当你在 ReactJS 中时,你不会像这样导入 javascript 资源。你实际上必须通过像 npm 命令这样的进程来导入它们,然后在你的 react 项目中声明它们,比如

import ScrollMagic from "scrollmagic"

虽然我能够将 ScrollMagic 导入反应文件并开始使用 scrollmagic,但我无法导入 greensock 插件。没有关于如何执行此操作的文档。我试图通过将animation.gsap.js中的代码段并将其粘贴到node_modules/scrollmagic/scrollmagic.js文件中来破解事物(编辑这些文件不是一个好主意),但它要么破坏了webpack编译器,要么它破坏了我的项目代码。

如何在 react 环境中使用 greensock 插件进行滚动魔术?

【问题讨论】:

    标签: reactjs scrollmagic


    【解决方案1】:

    我能够构建一个包装器。在高层次上,我所做的是研究plugins/animation.gsap.js 的代码,取出我需要的那些场景扩展属性,更改名称空间,并在导出之前让它在单独的反应类中增强 ScrollMagic 的行为。

    具体来说,我所做的是创建一个名为./ScrollMagic.js 的新文件并粘贴以下内容:

    import ScrollMagic from 'scrollmagic';
    import {TweenLite as Tween,TimelineMax as Timeline} from 'gsap';
    
    ScrollMagic.Scene.addOption("tweenChanges", // name
      false, // default
    
      function (val) { // validation callback
        return !!val;
    });
    
    ScrollMagic.Scene.extend(function () {
        var Scene = this,
          _tween;
    
        var log = function () {
          if (Scene._log) { // not available, when main source minified
            Array.prototype.splice.call(arguments, 1, 0, "(animation.gsap)", "->");
            Scene._log.apply(this, arguments);
          }
        };
    
        // set listeners
        Scene.on("progress.plugin_gsap", function () {
          updateTweenProgress();
        });
        Scene.on("destroy.plugin_gsap", function (e) {
          Scene.removeTween(e.reset);
        });
    
        /**
         * Update the tween progress to current position.
         * @private
         */
        var updateTweenProgress = function () {
          if (_tween) {
            var
            progress = Scene.progress(),
              state = Scene.state();
            if (_tween.repeat && _tween.repeat() === -1) {
              // infinite loop, so not in relation to progress
              if (state === 'DURING' && _tween.paused()) {
                _tween.play();
              } else if (state !== 'DURING' && !_tween.paused()) {
                _tween.pause();
              }
            } else if (progress != _tween.progress()) { // do we even need to update the progress?
              // no infinite loop - so should we just play or go to a specific point in time?
              if (Scene.duration() === 0) {
                // play the animation
                if (progress > 0) { // play from 0 to 1
                  _tween.play();
                } else { // play from 1 to 0
                  _tween.reverse();
                }
              } else {
                // go to a specific point in time
                if (Scene.tweenChanges() && _tween.tweenTo) {
                  // go smooth
                  _tween.tweenTo(progress * _tween.duration());
                } else {
                  // just hard set it
                  _tween.progress(progress).pause();
                }
              }
            }
          }
        };
    
        /**
         * Add a tween to the scene.  
         * If you want to add multiple tweens, add them into a GSAP Timeline object and supply it instead (see example below).  
         * 
         * If the scene has a duration, the tween's duration will be projected to the scroll distance of the scene, meaning its progress will be synced to scrollbar movement.  
         * For a scene with a duration of `0`, the tween will be triggered when scrolling forward past the scene's trigger position and reversed, when scrolling back.  
         * To gain better understanding, check out the [Simple Tweening example](../examples/basic/simple_tweening.html).
         *
         * Instead of supplying a tween this method can also be used as a shorthand for `TweenMax.to()` (see example below).
         * @memberof! animation.GSAP#
         *
         * @example
         * // add a single tween directly
         * scene.setTween(TweenMax.to("obj"), 1, {x: 100});
         *
         * // add a single tween via variable
         * var tween = TweenMax.to("obj"), 1, {x: 100};
         * scene.setTween(tween);
         *
         * // add multiple tweens, wrapped in a timeline.
         * var timeline = new TimelineMax();
         * var tween1 = TweenMax.from("obj1", 1, {x: 100});
         * var tween2 = TweenMax.to("obj2", 1, {y: 100});
         * timeline
         *    .add(tween1)
         *    .add(tween2);
         * scene.addTween(timeline);
         *
         * // short hand to add a TweenMax.to() tween
         * scene.setTween("obj3", 0.5, {y: 100});
         *
         * // short hand to add a TweenMax.to() tween for 1 second
         * // this is useful, when the scene has a duration and the tween duration isn't important anyway
         * scene.setTween("obj3", {y: 100});
         *
         * @param {(object|string)} TweenObject - A TweenMax, TweenLite, TimelineMax or TimelineLite object that should be animated in the scene. Can also be a Dom Element or Selector, when using direct tween definition (see examples).
         * @param {(number|object)} duration - A duration for the tween, or tween parameters. If an object containing parameters are supplied, a default duration of 1 will be used.
         * @param {object} params - The parameters for the tween
         * @returns {Scene} Parent object for chaining.
         */
        Scene.setTween = function (TweenObject, duration, params) {
          var newTween;
          if (arguments.length > 1) {
            if (arguments.length < 3) {
              params = duration;
              duration = 1;
            }
            TweenObject = Tween.to(TweenObject, duration, params);
          }
          try {
            // wrap Tween into a Timeline Object if available to include delay and repeats in the duration and standardize methods.
            if (Timeline) {
              newTween = new Timeline({
                smoothChildTiming: true
              }).add(TweenObject);
            } else {
              newTween = TweenObject;
            }
            newTween.pause();
          } catch (e) {
            log(1, "ERROR calling method 'setTween()': Supplied argument is not a valid TweenObject");
            return Scene;
          }
          if (_tween) { // kill old tween?
            Scene.removeTween();
          }
          _tween = newTween;
    
          // some properties need to be transferred it to the wrapper, otherwise they would get lost.
          if (TweenObject.repeat && TweenObject.repeat() === -1) { // TweenMax or TimelineMax Object?
            _tween.repeat(-1);
            _tween.yoyo(TweenObject.yoyo());
          }
          // Some tween validations and debugging helpers
          if (Scene.tweenChanges() && !_tween.tweenTo) {
            log(2, "WARNING: tweenChanges will only work if the TimelineMax object is available for ScrollMagic.");
          }
    
          // check if there are position tweens defined for the trigger and warn about it :)
          if (_tween && Scene.controller() && Scene.triggerElement() && Scene.loglevel() >= 2) { // controller is needed to know scroll direction.
            var
            triggerTweens = Tween.getTweensOf(Scene.triggerElement()),
              vertical = Scene.controller().info("vertical");
            triggerTweens.forEach(function (value, index) {
              var
              tweenvars = value.vars.css || value.vars,
                condition = vertical ? (tweenvars.top !== undefined || tweenvars.bottom !== undefined) : (tweenvars.left !== undefined || tweenvars.right !== undefined);
              if (condition) {
                log(2, "WARNING: Tweening the position of the trigger element affects the scene timing and should be avoided!");
                return false;
              }
            });
          }
    
          // warn about tween overwrites, when an element is tweened multiple times
          if (parseFloat(TweenLite.version) >= 1.14) { // onOverwrite only present since GSAP v1.14.0
            var
            list = _tween.getChildren ? _tween.getChildren(true, true, false) : [_tween],
              // get all nested tween objects
              newCallback = function () {
                log(2, "WARNING: tween was overwritten by another. To learn how to avoid this issue see here: https://github.com/janpaepke/ScrollMagic/wiki/WARNING:-tween-was-overwritten-by-another");
              };
            for (var i = 0, thisTween, oldCallback; i < list.length; i++) { /*jshint loopfunc: true */
              thisTween = list[i];
              if (oldCallback !== newCallback) { // if tweens is added more than once
                oldCallback = thisTween.vars.onOverwrite;
                thisTween.vars.onOverwrite = function () {
                  if (oldCallback) {
                    oldCallback.apply(this, arguments);
                  }
                  newCallback.apply(this, arguments);
                };
              }
            }
          }
          log(3, "added tween");
    
          updateTweenProgress();
          return Scene;
        };
    
        /**
         * Remove the tween from the scene.  
         * This will terminate the control of the Scene over the tween.
         *
         * Using the reset option you can decide if the tween should remain in the current state or be rewound to set the target elements back to the state they were in before the tween was added to the scene.
         * @memberof! animation.GSAP#
         *
         * @example
         * // remove the tween from the scene without resetting it
         * scene.removeTween();
         *
         * // remove the tween from the scene and reset it to initial position
         * scene.removeTween(true);
         *
         * @param {boolean} [reset=false] - If `true` the tween will be reset to its initial values.
         * @returns {Scene} Parent object for chaining.
         */
        Scene.removeTween = function (reset) {
          if (_tween) {
            if (reset) {
              _tween.progress(0).pause();
            }
            _tween.kill();
            _tween = undefined;
            log(3, "removed tween (reset: " + (reset ? "true" : "false") + ")");
          }
          return Scene;
        };
    
      });
    
    export default ScrollMagic; 
    

    您会注意到这看起来几乎与 plugins/animation.gsap.js 完全一样,但以下情况除外:

    • 我在顶部添加了自己的导入行,因此请确保您已提前 npm 安装了 scrollmagic 和 gsap
    • 我将 ScrollMagic 对象导出到最后
    • plugins/animation.gsap.js 有一些其他代码将插件变成了我排除的工厂,因为它不适用于这里

    现在我可以在我的反应项目中使用.setTween()。示例用法:

    import React, {Component} from "react";
    import ScrollMagic from "./ScrollMagic"; // my own wrapper for scrollmagic that includes greensock
    
    export default class Home extends Component {
    
        componentDidMount()
        {
            var controller = new ScrollMagic.Controller();
            var item = "#whateverstuffselector";
            var scene = new ScrollMagic.Scene({triggerElement:item})
                    .setTween(item, 0.5, {backgroundColor: "red", scale: 3})
                    .addTo(controller);
    
        }
    
        render()
        {
            return (<div id="whateverstuffselector">stuff</div>);
        }
    }
    

    【讨论】:

      【解决方案2】:

      在将此问题升级 1 个月后,我想我找到了很好的解决方案。 所以这个问题表明在 React 环境中我们无法获取 animation.gsap 文件。 此修复不需要任何 webpack 更改,除了 animation.gsap 文件本身。

      1. 在“node_module”目录树中找到这些文件(在您的 PC 上可能有不同的位置)并以这种方式将其导入您的工作 JS 文件(例如 App.js)。 import "../../node_modules/scrollmagic/scrollmagic/uncompressed/plugins/animation.gsap"; import "../../node_modules/scrollmagic/scrollmagic/uncompressed/plugins/debug.addIndicators";

      2. 转到animation.gsap 并将这两行代码添加到文件的开头。 import { TimelineMax, TweenMax, TweenLite} from "gsap/all"; import ScrollMagic from "scrollmagic";

      3. 进入 debug.addIndicators 并在文件开头添加这行代码(以防万一你需要指标调试器,但我强烈建议不要跳过这一步)。 import ScrollMagic from "scrollmagic";
      4. 在animation.gsap 中找到第一个函数并删除所有“根”变量并将它们更改为我在下面提供的变量。 (你应该找到其中的 8 个)。

      之前:

      (function (root, factory) {
          if (typeof define === 'function' && define.amd) {
              // AMD. Register as an anonymous module.
              define(['ScrollMagic', 'TweenMax', 'TimelineMax'], factory);
          } else if (typeof exports === 'object') {
              // CommonJS
              // Loads whole gsap package onto global scope.
              require('gsap');
              factory(require('scrollmagic'), TweenMax, TimelineMax);
          } else {
              // Browser globals
              factory(root.ScrollMagic || (root.jQuery && root.jQuery.ScrollMagic), root.TweenMax || root.TweenLite, root.TimelineMax || root.TimelineLite);
          }
      }
      

      之后:

      (function (root, factory) {
          if (typeof define === 'function' && define.amd) {
              // AMD. Register as an anonymous module.
              define(['ScrollMagic', 'TweenMax', 'TimelineMax'], factory);
          } else if (typeof exports === 'object') {
              // CommonJS
              // Loads whole gsap package onto global scope.
              require('gsap');
              factory(require('scrollmagic'), TweenMax, TimelineMax);
          } else {
              // Browser globals
              factory(ScrollMagic || (jQuery && jQuery.ScrollMagic), TweenMax || TweenLite, TimelineMax || TimelineLite);
          }
      }
      
      1. 在 debug.addIndicators 中还删除所有“根”变量(您应该找到其中 4 个)并将它们更改为我在下面提供的变量。

      之前:

      (function (root, factory) {
          if (typeof define === 'function' && define.amd) {
              // AMD. Register as an anonymous module.
              define(['ScrollMagic'], factory);
          } else if (typeof exports === 'object') {
                  // CommonJS
                  factory(require('scrollmagic'));
          } else {
                  // no browser global export needed, just execute
              factory(root.ScrollMagic || (root.jQuery && root.jQuery.ScrollMagic));
          }
      }
      

      之后:

      (function (root, factory) {
          if (typeof define === 'function' && define.amd) {
              // AMD. Register as an anonymous module.
              define(['ScrollMagic'], factory);
          } else if (typeof exports === 'object') {
              // CommonJS
              factory(require('scrollmagic'));
          } else {
              // no browser global export needed, just execute
              factory(ScrollMagic || (jQuery && jQuery.ScrollMagic));
          }
      }
      

      我希望这个解决方案对你有用。 无论如何,您可以联系我寻求帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-23
        • 2018-03-01
        • 1970-01-01
        相关资源
        最近更新 更多