在AngularJS中使用ScrollSpy

时间:2013-12-20 14:04:22

标签: angularjs angularjs-directive

我是AngularJS的新手。我正在使用AngularJS 1.2.5和Bootstrap 3.0。我想在我的应用程序中包含ScrollSpy。但是,我遇到了一些挑战。我正在尝试合并找到的here代码。目前,我的代码如下所示:

的index.html

<div class="row" scroll-spy>
  <div class="col-md-3 sidebar">
    <ul style="position:fixed;" class="nav nav-pills nav-stacked">
      <li class="active" spy="overview"><a href="#overview">Overview</a></li>
      <li spy="main"><a href="#main">Main Content</a></li>
      <li spy="summary"><a href="#summary">Summary</a></li>
      <li spy="links"><a href="#links">Other Links</a></li>
    </ul>
  </div>

  <div class="col-md-9 content">
    <h3 id="overview">Overview</h3>
    Lorem Ipsum Text goes here...

    <h3 id="main">Main Body</h3>
    Lorem Ipsum Text goes here...

    <h3 id="summary">Summary</h3>
    Lorem Ipsum text goes here...

    <h3 id="links">Other Links</h3>
  </div>
</div>

index.html.js

angular.module('td.controls.scrollSpy', [])
  .directive('spy', function ($location) {
    return {
      restrict: 'A',
      require: '^scrollSpy',
      link: function (scope, elem, attrs, scrollSpy) {
        var _ref;
        if ((_ref = attrs.spyClass) == null) {
          attrs.spyClass = 'current';
        }
        elem.click(function () {
          return scope.$apply(function () {
            return $location.hash(attrs.spy);
          });
        });
        return scrollSpy.addSpy({
          id: attrs.spy,
          'in': function () {
            return elem.addClass(attrs.spyClass);
          },
          out: function () {
            return elem.removeClass(attrs.spyClass);
          }
        });
      }
    };
  })
  .directive('scrollSpy', function ($location) {
    return {
      restrict: 'A',
      controller: function ($scope) {
        $scope.spies = [];
        return this.addSpy = function (spyObj) {
          return $scope.spies.push(spyObj);
        };
      },
      link: function (scope, elem, attrs) {
        var spyElems;
        spyElems = [];
        scope.$watch('spies', function (spies) {
          var spy, _i, _len, _results;
          _results = [];
          for (_i = 0, _len = spies.length; _i < _len; _i++) {
            spy = spies[_i];
            if (spyElems[spy.id] == null) {
              _results.push(spyElems[spy.id] = elem.find('#' + spy.id));
            } else {
              _results.push(void 0);
            }
          }
          return _results;
        });
        return $($window).scroll(function () {
          var highlightSpy, pos, spy, _i, _len, _ref;
          highlightSpy = null;
          _ref = scope.spies;
          for (_i = 0, _len = _ref.length; _i < _len; _i++) {
            spy = _ref[_i];
            spy.out();
            spyElems[spy.id] = spyElems[spy.id].length === 0 ? elem.find('#' + spy.id) : spyElems[spy.id];

            if (spyElems[spy.id].length !== 0) {
              if ((pos = spyElems[spy.id].offset().top) - $window.scrollY <= 0) {
                spy.pos = pos;
                if (highlightSpy == null) {
                  highlightSpy = spy;
                }
                if (highlightSpy.pos < spy.pos) {
                  highlightSpy = spy;
                }
              }
            }
          }
          return highlightSpy != null ? highlightSpy['in']() : void 0;
        });
      }
    };
  })
;

当我在浏览器中运行时,我遇到了几个错误。当我最初运行它时,我在浏览器控制台中看到以下错误:

TypeError: Object function (spyObj) { return $scope.spies.push(spyObj); } has no method 'addSpy'
ReferenceError: $window is not defined

我无法弄清楚a)为什么我会收到这些错误或b)如何让这个基本的例子工作。我真的很喜欢使用带有AngularJS的scrollspy的方法。这是我见过的最干净的实现。出于这个原因,我想知道如何使这个工作。

2 个答案:

答案 0 :(得分:2)

我最近也遇到过亚历山大的解决方案,并经历了翻译过程。

要回答您的直接问题:您需要将$window导入scrollSpy指令。

.directive('scrollSpy', function ($location, $window) {

以下是我对亚历山大代码的完整翻译:

app.directive('scrollSpy', function ($window) {
  return {
    restrict: 'A',
    controller: function ($scope) {
      $scope.spies = [];
      this.addSpy = function (spyObj) {
        $scope.spies.push(spyObj);
      };
    },
    link: function (scope, elem, attrs) {
      var spyElems;
      spyElems = [];

      scope.$watch('spies', function (spies) {
        var spy, _i, _len, _results;
        _results = [];

        for (_i = 0, _len = spies.length; _i < _len; _i++) {
          spy = spies[_i];

          if (spyElems[spy.id] == null) {
            _results.push(spyElems[spy.id] = elem.find('#' + spy.id));
          }
        }
        return _results;
      });

      $($window).scroll(function () {
        var highlightSpy, pos, spy, _i, _len, _ref;
        highlightSpy = null;
        _ref = scope.spies;

        // cycle through `spy` elements to find which to highlight
        for (_i = 0, _len = _ref.length; _i < _len; _i++) {
          spy = _ref[_i];
          spy.out();

          // catch case where a `spy` does not have an associated `id` anchor
          if (spyElems[spy.id].offset() === undefined) {
            continue;
          }

          if ((pos = spyElems[spy.id].offset().top) - $window.scrollY <= 0) {
            // the window has been scrolled past the top of a spy element
            spy.pos = pos;

            if (highlightSpy == null) {
              highlightSpy = spy;
            }
            if (highlightSpy.pos < spy.pos) {
              highlightSpy = spy;
            }
          }
        }

        // select the last `spy` if the scrollbar is at the bottom of the page
        if ($(window).scrollTop() + $(window).height() >= $(document).height()) {
          spy.pos = pos;
          highlightSpy = spy;
        }        

        return highlightSpy != null ? highlightSpy["in"]() : void 0;
      });
    }
  };
});


app.directive('spy', function ($location, $anchorScroll) {
  return {
    restrict: "A",
    require: "^scrollSpy",
    link: function(scope, elem, attrs, affix) {
      elem.click(function () {
        $location.hash(attrs.spy);
        $anchorScroll();
      });

      affix.addSpy({
        id: attrs.spy,
        in: function() {
          elem.addClass('active');
        },
        out: function() {
          elem.removeClass('active');
        }
      });
    }
  };
});

如果浏览器滚动到底部,上面的代码也支持突出显示菜单中的最后一个spy元素,原始代码没有。

答案 1 :(得分:0)

如果您不使用ng-include更改以下条件

      if (spyElems[spy.id].offset() === undefined) {
        continue;
      }

在此

if (spyElems[spy.id].offset() === undefined) {
    // try to refind it
    spyElems[spy.id] = elem.find('#' + spy.id);
    if(spyElems[spy.id].offset() === undefined)
        continue;
}