AngularJS指令滚动到给定项目

Mar*_*dig 33 angularjs

我有一个范围变量$ scope.first_unread_id,它在我的控制器中定义.在我的模板中,我有:

<div id="items" >
  <ul class="standard-list">
    <li ng-repeat="item in items" scroll-to-id="first_unread_id">
    <span class="content">{{ item.content }}</span>
    </li>
  </ul>
</div>
Run Code Online (Sandbox Code Playgroud)

我的指令看起来像:

angular.module('ScrollToId', []).
directive('scrollToId', function () {
  return function (scope, element, attributes) {
    var id = scope.$parent[attributes["scrollToId"]];
    if (id === scope.item.id) {
      setTimeout(function () {
        window.scrollTo(0, element[0].offsetTop - 100)
      }, 20);
    }
  }

});
Run Code Online (Sandbox Code Playgroud)

然而,它有两个问题:

  1. 是否有更好的方法可以将"first_unread_id"从控制器范围中移除到直接询问范围内.$ parent?这似乎有点'icky'.我希望我可以通过视图将其传递给直接作为参数,而不必在ever li元素上重复该参数.

  2. 有没有更好的方法来避免需要setTimeout()调用?没有它,它有时会起作用- 我想是由于布局时间的不同.我理解我使用的语法是定义一个链接函数 - 但我不清楚默认情况下这是一个前置链接还是后置链接 - 如果这对我的问题也很重要.

And*_*lin 39

  1. 您不应该需要范围.$ parent - 因为它将继承父作用域的值,并且当它在父作用域中发生更改时,它将被传递下去.
  2. 默认为后链接功能.你有一些图像或加载会使页面布局在初始加载后不久发生变化吗?您是否尝试过没有时间的setTimeout,例如setTimeout(function(){})?这将确保这将"一个接一个"其他一切完成.
  3. 我还会稍微改变你的指令的逻辑,使它更通用.如果给定条件为真,我会滚动到元素.

以下是这3个变化:

HTML:

<div id="items" >
  <ul class="standard-list">
    <li ng-repeat="item in items" scroll-if="item.id == first_unread_id">
      <span class="content">{{ item.content }}</span>
    </li>
  </ul>
</div>
Run Code Online (Sandbox Code Playgroud)

JS:

app.directive('scrollIf', function () {
  return function (scope, element, attributes) {
    setTimeout(function () {
      if (scope.$eval(attributes.scrollIf)) {
        window.scrollTo(0, element[0].offsetTop - 100)
      }
    });
  }
});
Run Code Online (Sandbox Code Playgroud)

  • $ timeout(fn,delay,false) - 没有脏检查! (6认同)
  • 为什么不使用$ timeout?另外,为什么$ eval而不是$ parse?$ $解析会不会更具角度? (4认同)

Uri*_*Uri 11

假设父元素是我们滚动的元素,这对我有用:

app.directive('scrollIf', function () {
  return function(scope, element, attrs) {
    scope.$watch(attrs.scrollIf, function(value) {
      if (value) {
        // Scroll to ad.
        var pos = $(element).position().top + $(element).parent().scrollTop();
        $(element).parent().animate({
            scrollTop : pos
        }, 1000);
      }
    });
  }
});
Run Code Online (Sandbox Code Playgroud)


Mat*_*Mat 6

我最终得到了以下代码(不依赖于jQ),如果滚动元素不是窗口,它也可以工作.

app.directive('scrollIf', function () {
    var getScrollingParent = function(element) {
        element = element.parentElement;
        while (element) {
            if (element.scrollHeight !== element.clientHeight) {
                return element;
            }
            element = element.parentElement;
        }
        return null;
    };
    return function (scope, element, attrs) {
        scope.$watch(attrs.scrollIf, function(value) {
            if (value) {
                var sp = getScrollingParent(element[0]);
                var topMargin = parseInt(attrs.scrollMarginTop) || 0;
                var bottomMargin = parseInt(attrs.scrollMarginBottom) || 0;
                var elemOffset = element[0].offsetTop;
                var elemHeight = element[0].clientHeight;

                if (elemOffset - topMargin < sp.scrollTop) {
                    sp.scrollTop = elemOffset - topMargin;
                } else if (elemOffset + elemHeight + bottomMargin > sp.scrollTop + sp.clientHeight) {
                    sp.scrollTop = elemOffset + elemHeight + bottomMargin - sp.clientHeight;
                }
            }
        });
    }
});
Run Code Online (Sandbox Code Playgroud)