jQuery AngularJS 中的 ScrollTo 函数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17284005/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
ScrollTo function in AngularJS
提问by EnigmaRM
I'm trying to get a quick nav to work correctly. It's floating on the side. When they click on a link, it takes them to that ID on the page. I'm following this guide from Treehouse. This is what I have for the scrolling:
我正在尝试快速导航以正常工作。它漂浮在一边。当他们点击一个链接时,它会将他们带到页面上的那个 ID。我正在遵循Treehouse 的本指南。这是我滚动的内容:
$("#quickNav a").click(function(){
var quickNavId = $(this).attr("href");
$("html, body").animate({scrollTop: $(location).offset().top}, "slow");
return false;
});
I initially placed it before the </body>
. But I seem to be running into a race condition where that was firing before the quickNav compiled (it has a ng-hide
placed on it, not sure if that's causing it - but it is within the DOM).
我最初把它放在</body>
. 但是我似乎遇到了在 quickNav 编译之前触发的竞争条件(它有一个ng-hide
放置在上面,不确定这是否导致它 - 但它在 DOM 内)。
If I run that block of code in the console, then the scrolling works as expected.
如果我在控制台中运行该代码块,则滚动按预期工作。
I figured it'd be more effective to move this into the controller - or more likely within a directive. But I'm not having luck accomplishing that. How can I get this block of code to work with AngularJS?
我认为将其移动到控制器中会更有效 - 或者更有可能在指令中。但我没有运气做到这一点。我怎样才能让这段代码与 AngularJS 一起工作?
回答by Andrew Joslin
Here is a simple directive that will scroll to an element on click:
这是一个简单的指令,它会在点击时滚动到一个元素:
myApp.directive('scrollOnClick', function() {
return {
restrict: 'A',
link: function(scope, $elm) {
$elm.on('click', function() {
$("body").animate({scrollTop: $elm.offset().top}, "slow");
});
}
}
});
Demo: http://plnkr.co/edit/yz1EHB8ad3C59N6PzdCD?p=preview
演示:http: //plnkr.co/edit/yz1EHB8ad3C59N6PzdCD?p=preview
For help creating directives, check out the videos at http://egghead.io, starting at #10 "first directive".
有关创建指令的帮助,请查看http://egghead.io 上的视频,从 #10“第一个指令”开始。
edit: To make it scroll to a specific element specified by a href, just check attrs.href
.
编辑:要使其滚动到由 href 指定的特定元素,只需选中attrs.href
.
myApp.directive('scrollOnClick', function() {
return {
restrict: 'A',
link: function(scope, $elm, attrs) {
var idToScroll = attrs.href;
$elm.on('click', function() {
var $target;
if (idToScroll) {
$target = $(idToScroll);
} else {
$target = $elm;
}
$("body").animate({scrollTop: $target.offset().top}, "slow");
});
}
}
});
Then you could use it like this: <div scroll-on-click></div>
to scroll to the element clicked. Or <a scroll-on-click href="#element-id"></div>
to scroll to element with the id.
然后你可以像这样使用它:<div scroll-on-click></div>
滚动到点击的元素。或者<a scroll-on-click href="#element-id"></div>
滚动到带有 id 的元素。
回答by Liad Livnat
This is a better directive in case you would like to use it:
如果您想使用它,这是一个更好的指令:
you can scroll to any element in the page:
您可以滚动到页面中的任何元素:
.directive('scrollToItem', function() {
return {
restrict: 'A',
scope: {
scrollTo: "@"
},
link: function(scope, $elm,attr) {
$elm.on('click', function() {
$('html,body').animate({scrollTop: $(scope.scrollTo).offset().top }, "slow");
});
}
}})
Usage (for example click on div 'back-to-top' will scroll to id scroll-top):
用法(例如点击 div 'back-to-top' 将滚动到 id scroll-top):
<a id="top-scroll" name="top"></a>
<div class="back-to-top" scroll-to-item scroll-to="#top-scroll">
It's also supported by chrome,firefox,safari and IE cause of the html,body element .
chrome、firefox、safari 和 IE 也支持 html,body 元素。
回答by teter
In order to animate to a specific element inside a scroll container (fixed DIV)
为了动画滚动容器内的特定元素(固定 DIV)
/*
@param Container(DIV) that needs to be scrolled, ID or Div of the anchor element that should be scrolled to
Scrolls to a specific element in the div container
*/
this.scrollTo = function(container, anchor) {
var element = angular.element(anchor);
angular.element(container).animate({scrollTop: element.offset().top}, "slow");
}
回答by Hasteq
An angular solution using $anchorScroll http://www.benlesh.com/2013/02/angular-js-scrolling-to-element-by-id.html:
使用 $anchorScroll http://www.benlesh.com/2013/02/angular-js-scrolling-to-element-by-id.html的角度解决方案 :
app.controller('MainCtrl', function($scope, $location, $anchorScroll) {
var i = 1;
$scope.items = [{ id: 1, name: 'Item 1' }];
$scope.addItem = function (){
i++;
//add the item.
$scope.items.push({ id: i, name: 'Item ' + i});
//now scroll to it.
$location.hash('item' + i);
$anchorScroll();
};
});
And here is a plunk: http://plnkr.co/edit/xi2r8wP6ZhQpmJrBj1jM?p=preview
这是一个 plunk:http://plnkr.co/edit/xi2r8wP6ZhQpmJrBj1jM? p=preview
And if you care for a pure javascript solution, here is one:
如果您喜欢纯 javascript 解决方案,这里有一个:
Invoke runScroll in your code with parent container id and target scroll id:
在您的代码中使用父容器 ID 和目标滚动 ID 调用 runScroll:
function runScroll(parentDivId,targetID) {
var longdiv;
longdiv = document.querySelector("#" + parentDivId);
var div3pos = document.getElementById(targetID).offsetTop;
scrollTo(longdiv, div3pos, 600);
}
function scrollTo(element, to, duration) {
if (duration < 0) return;
var difference = to - element.scrollTop;
var perTick = difference / duration * 10;
setTimeout(function () {
element.scrollTop = element.scrollTop + perTick;
if (element.scrollTop == to) return;
scrollTo(element, to, duration - 10);
}, 10);
}
Reference: Cross browser JavaScript (not jQuery...) scroll to top animation
回答by danyamachine
I used andrew joslin's answer, which works great but triggered an angular route change, which created a jumpy looking scroll for me. If you want to avoid triggering a route change,
我使用了 andrew joslin 的答案,这很好用,但触发了角度路线的变化,这为我创造了一个看起来很跳跃的卷轴。如果您想避免触发路由更改,
myApp.directive('scrollOnClick', function() {
return {
restrict: 'A',
link: function(scope, $elm, attrs) {
var idToScroll = attrs.href;
$elm.on('click', function(event) {
event.preventDefault();
var $target;
if (idToScroll) {
$target = $(idToScroll);
} else {
$target = $elm;
}
$("body").animate({scrollTop: $target.offset().top}, "slow");
return false;
});
}
}
});
回答by Marc Gibbons
Thanks Andy for the example, this was very helpful. I ended implementing a slightly different strategy since I am developing a single-page scroll and did not want Angular to refresh when using the hashbang URL. I also want to preserve the back/forward action of the browser.
感谢安迪的例子,这很有帮助。由于我正在开发单页滚动并且不希望 Angular 在使用 hashbang URL 时刷新,因此我结束了实施略有不同的策略。我还想保留浏览器的后退/前进动作。
Instead of using the directive and the hash, I am using a $scope.$watch on the $location.search, and obtaining the target from there. This gives a nice clean anchor tag
我没有使用指令和哈希,而是在 $location.search 上使用 $scope.$watch,并从那里获取目标。这提供了一个漂亮干净的锚标签
<a ng-href="#/?scroll=myElement">My element</a>
<a ng-href="#/?scroll=myElement">My element</a>
I chained the watch code to the my module declaration in app.js like so:
我将监视代码链接到 app.js 中的模块声明中,如下所示:
.run(function($location, $rootScope) {
$rootScope.$watch(function() { return $location.search() }, function(search) {
var scrollPos = 0;
if (search.hasOwnProperty('scroll')) {
var $target = $('#' + search.scroll);
scrollPos = $target.offset().top;
}
$("body,html").animate({scrollTop: scrollPos}, "slow");
});
})
The caveat with the code above is that if you access by URL directly from a different route, the DOM may not be loaded in time for jQuery's $target.offset() call. The solution is to nest this code within a $viewContentLoaded watcher. The final code looks something like this:
上面代码的警告是,如果您直接从不同的路由通过 URL 访问,DOM 可能无法及时加载 jQuery 的 $target.offset() 调用。解决方案是将此代码嵌套在 $viewContentLoaded 观察器中。最终代码如下所示:
.run(function($location, $rootScope) {
$rootScope.$on('$viewContentLoaded', function() {
$rootScope.$watch(function() { return $location.search() }, function(search) {
var scrollPos = 0
if (search.hasOwnProperty('scroll')) {
var $target = $('#' + search.scroll);
var scrollPos = $target.offset().top;
}
$("body,html").animate({scrollTop: scrollPos}, "slow");
});
});
})
Tested with Chrome and FF
用 Chrome 和 FF 测试
回答by Marwen Trabelsi
What about angular-scroll, it's actively maintained and there is no dependency to jQuery..
angular-scroll怎么样,它是积极维护的,并且不依赖于 jQuery..
回答by Undefitied
Another suggestion. One directive with selector.
另一个建议。一个带有选择器的指令。
HTML:
HTML:
<button type="button" scroll-to="#catalogSection">Scroll To</button>
Angular:
角度:
app.directive('scrollTo', function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
element.on('click', function () {
var target = $(attrs.scrollTo);
if (target.length > 0) {
$('html, body').animate({
scrollTop: target.offset().top
});
}
});
}
}
});
Also notice $anchorScroll
还要注意$anchorScroll
回答by Anja Ishmukhametova
very clear answer, using just ANGULARJS, no any JQUERY depends
非常明确的答案,只使用 ANGULARJS,没有任何 JQUERY 依赖
in your html somewhere on the bottom <back-top>some text</back-top>
在你的 html 底部的某个地方 <back-top>some text</back-top>
in your html somewhere on the top <div id="top"></div>
在您的 html 顶部某处 <div id="top"></div>
in your js:
在你的js中:
/**
* @ngdoc directive
* @name APP.directive:backTop
<pre>
<back-top></back-top>
</pre>
*/
angular
.module('APP')
.directive('backTop', ['$location', '$anchorScroll' ,function($location, $anchorScroll) {
return {
restrict: 'E',
replace: true,
transclude: true,
template: '<span class=\'btn btn-mute pull-right\'><i class=\'glyphicon glyphicon-chevron-up\'></i><ng-transclude></ng-transclude></span>',
scope: {
},
link: function(scope, element) {
element.on('click', function(event) {
$anchorScroll(['top']);
});
}
};
}]);