我有一个范围变量$ 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>
我的指示如下:
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);
}
}
});
然而,它有两个问题:
是否有更好的方法可以将“first_unread_id”从控制器范围中移入直接询问范围。$ parent?这似乎有点'icky'。我希望我可以通过视图传递给直接作为参数,而不必在ever li元素上重复这一点。
有没有更好的方法来避免需要setTimeout()调用?没有它,它有时 - 我想象由于布局时间的不同。我理解我使用的语法是定义一个链接函数 - 但是我不清楚这是默认情况下的前置链接还是后置链接 - 如果这对我的问题也很重要。
答案 0 :(得分:39)
以下是这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>
JS:
app.directive('scrollIf', function () {
return function (scope, element, attributes) {
setTimeout(function () {
if (scope.$eval(attributes.scrollIf)) {
window.scrollTo(0, element[0].offsetTop - 100)
}
});
}
});
答案 1 :(得分: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);
}
});
}
});
答案 2 :(得分: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;
}
}
});
}
});
答案 3 :(得分:3)
与接受的答案相同,但使用javascript内置方法“scrollIntoView”:
angular.module('main').directive('scrollIf', function() {
return function(scope, element, attrs) {
scope.$watch(attrs.scrollIf, function(value) {
if (value) {
element[0].scrollIntoView({block: "end", behavior: "smooth"});
}
});
}
});
答案 4 :(得分:1)
结合UI路由器的$uiViewScroll,我最终得到了以下指令:
app.directive('scrollIf', function ($uiViewScroll) {
return function (scope, element, attrs) {
scope.$watch(attrs.scrollIf, function(value) {
if (value) {
$uiViewScroll(element);
}
});
}
});
答案 5 :(得分:0)
在与@uri的组合中,这适用于我在.run中使用ui-router和stateChangeSuccess的动态内容:
$rootScope.$on('$stateChangeSuccess',function(newRoute, oldRoute){
setTimeout(function () {
var postScroll = $state.params.postTitle;
var element = $('#'+postScroll);
var pos = $(element).position().top - 100 + $(element).parent().scrollTop();
$('body').animate({
scrollTop : pos
}, 1000);
}, 1000);
});
答案 6 :(得分:0)
如果答案在这里得到了最好的答案,请参阅ES6:
档案:scroll.directive.js
export default function ScrollDirective() {
return {
restrict: 'A',
scope: {
uiScroll: '='
},
link: link
};
function link($scope, $element) {
setTimeout(() => {
if ($scope.uiScroll) {
$element[0].scrollIntoView({block: "end", behavior: "smooth"});
}
});
}
}
档案scroll.module.js
import ScrollDirective from './scroll.directive';
export default angular.module('app.components.scroll', [])
.directive('uiScroll', ScrollDirective);
在项目中导入后,您可以在html中使用它:
<div id="items" >
<ul class="standard-list">
<li ng-repeat="item in items" ui-scroll="true">
<span class="content">{{ item.content }}</span>
</li>
</ul>
</div>