【问题标题】:Integrating Skrollr w/ AngularJS Single-page App将 Skrollr 与 AngularJS 单页应用程序集成
【发布时间】:2014-05-17 19:35:45
【问题描述】:

我使用 AngularJS 设置了一个单页应用程序,并在 home 页面上使用了 Skrollr。我以前没有使用过 Skrollr,所以在我开始使用更多功能之前,我想与其他人一起检查将它与 AngularJS 集成的正确“Angular”方式

我在 Angular 中所做的是创建一个服务来将脚本加载到页面上并调用 skrollr.init() 并将其作为承诺返回。然后将服务注入到一个指令中,该指令根据需要调用refresh。如果页面需要 skrollr,我可以在页面的某处使用此指令,并为每个 skrollr 文档设置 data 属性。

这行得通:

<div class="main" skrollr-tag>
    <div data-0="color:rgb(0,0,255);" data-90="color:rgb(255,0,0);">WOOOT</div>
</div>

似乎元素稍后添加到 DOM,例如 ngRepeat,skrollr 不知道,所以我需要在所有使用 skrollr data 属性动态生成的元素上包含这个指令才能工作。

<div class="main" skrollr-tag> 
    <!-- this heading will animate all the time -->
    <h1 data-0="opacity: 1" data-50="opacity: 0">WOOT!</h1>
    <div data-ng-repeat="item in items" class="had-to-add-skrollr-again" skrollr-tag> 
        <!-- skrollr animates this only on page refresh, unless skrollr-tag duplicated above -->
        <div data-0="color:rgb(0,0,255);" data-90="color:rgb(255,0,0);">{{item.name}}</div>
    </div>
</div>

因此,回顾一下,skrollr 在刷新后第一次加载时“意识到”这些动态元素,但是在导航到不同的路线然后再次返回后,它们不再具有动画效果,除非您再次刷新页面或添加 @987654328 @ 指令到动态元素本身。

出于性能原因,在需要 skrollr 的每个动态元素上包含此指令是不是一个坏主意,从而为每个元素再次调用 refresh()?理想的解决方案是每页加载一次skrollr-tag 指令,并且它知道动态元素。我愿意接受任何完全不同的清洁工更简单的方法来将 skrollr 集成到 angular。

角码在这里:

服务:

.service('skrollrService', ['$document', '$q', '$rootScope', '$window', 
    function($document, $q, $rootScope, $window){
        var defer = $q.defer();

        function onScriptLoad() {
            // Load client in the browser
            $rootScope.$apply(function() { 
                var s = $window.skrollr.init({
                        forceHeight: false
                    });
                defer.resolve(s); 
            });
        }

        // Create a script tag with skrollr as the source
        // and call our onScriptLoad callback when it
        // has been loaded

        var scriptTag = $document[0].createElement('script');
        scriptTag.type = 'text/javascript'; 
        scriptTag.async = true;
        scriptTag.src = 'lib/skrollr/dist/skrollr.min.js';

        scriptTag.onreadystatechange = function () {
            if (this.readyState === 'complete') onScriptLoad();
        };

        scriptTag.onload = onScriptLoad;

        var s = $document[0].getElementsByTagName('body')[0];
        s.appendChild(scriptTag);

        return {
            skrollr: function() { return defer.promise; }
        };

    }
 ]);

指令:

.directive('skrollrTag', [ 'skrollrService', 
    function(skrollrService){
        return {
            link: function(){
                skrollrService.skrollr().then(function(skrollr){
                    skrollr.refresh();
                });
            }
        };
    }
])

【问题讨论】:

  • 我可以看看你的 html,并举例说明当你的意思是你必须在所有这些上添加指令时你在谈论什么(不知道我明白为什么,从来没有使用过这个滚动之前的图书馆)。
  • 当然,我在上面第一句话中链接到了主页。基本上,如果元素是动态生成的(来自 ngRepeat 等),我需要对它们使用 skrollr-tag 指令才能使 skrollr 工作。否则我可以将 skrollr-tag 指令扔到页面上任何位置的元素上,它工作正常。

标签: javascript angularjs skrollr


【解决方案1】:

我目前在尝试将 Skrollr 集成到 AngularJS 时遇到同样的问题。

问题基本上是这个指令,它在页面第一次加载时起作用,但是即使在创建新的 html 元素或更改视图时调用它也没有发生任何事情。

.directive('skrollrTag', [ 'skrollrService', 
function(skrollrService){
    return {
        link: function(){
            skrollrService.skrollr().then(function(skrollr){
                skrollr.refresh();
            });
        }
    };
}

])

我认为原因是 angularJS 注入新 html 内容的方式。当 skrollr 确实“刷新”它尚未呈现或某种冲突时。 也许唯一的解决方案是修改 skrollr 脚本。

【讨论】:

    【解决方案2】:

    这个答案应该会有所帮助:AngularJS watch DOM change。尝试更新您的指令以观察子节点的变化。这样,每当添加新节点时,它都会自动刷新。

    .directive('skrollrTag', [ 'skrollrService', 
        function(skrollrService){
            return {
                link: function(scope, element, attrs){
                    skrollrService.skrollr().then(function(skrollr){
                        skrollr.refresh();
                    });
    
                   //This will watch for any new elements being added as children to whatever element this directive is placed on. If new elements are added, Skrollr will be refreshed (pulling in the new elements
                   scope.$watch(
                       function () { return element[0].childNodes.length; },
                       function (newValue, oldValue) {
                       if (newValue !== oldValue) {
                           skrollrService.skrollr().then(function(skrollr){
                               skrollr.refresh();
                           });
                       }
                   });
                }
            };
        }
    ]);
    

    编辑

    更新以说明您正在使用的承诺(已经解决),并添加了评论以进一步解释解决方案。

    【讨论】:

    • 您好,抱歉,示例最初有些不清楚。如果在动态项本身上添加了skrollr-tag 指令,这确实有效。我更多的是寻找一种方法,让它每页加载一次指令。我检查了 skrollr 源代码,你可以传递 refresh() 一个元素来重新解析,所以也许一个好的方法是对每个想要与 skrollr 一起使用的元素使用 skrollr-tag 指令,并更新指令使用refresh(element[0])?
    • 我的解决方案是这样您就可以每页使用一次 skrollr-tag。它监视所有子元素(因此您无需在 ng-repeat 中为所有动态元素添加指令)。只需在滚动部分的最外层父 div 上添加 skrollr-tag 指令(已更新以反映上面的代码),当动态添加子节点时,watcher 将导致 skrollr 刷新。
    • 忘了说,没用。相反,它适用于第一个页面加载或刷新,然后不再适用(使用或不使用 $watch)。基本上,它没有任何区别。我猜是因为 skrollr 的工作原理。
    • 请注意,如果您复制并粘贴此代码供自己使用,则需要在第 10 行将“$scope”更改为“scope”以避免出现语法错误。跨度>
    【解决方案3】:

    我为 skrollr

    做了一个指令
    (function () {
      'use strict';
      angular.module('myApp', [])
        .directive('skrollr', function () {
          var obj = {
            link: function () {
              /* jshint ignore:start */
              skrollr.init().refresh();
              /* jshint ignore:end */
            }
          };
          return obj;
        });
    })();
    

    并像这样使用

    <div skrollr data-0="background-color:rgb(0,0,255);" data-500="background-color:rgb(255,0,0);">WOOOT</div>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-24
      • 1970-01-01
      • 1970-01-01
      • 2015-02-20
      • 2019-02-11
      • 2015-12-28
      • 2012-06-28
      • 1970-01-01
      相关资源
      最近更新 更多