Функция ScrollTo в AngularJS
Я пытаюсь быстро работать над навигацией. Он плавает на стороне. Когда они нажимают на ссылку, она берет их на этот идентификатор на странице. Я следую этому руководству от Treehouse.
Это то, что у меня есть для прокрутки:
$("#quickNav a").click(function(){
var quickNavId = $(this).attr("href");
$("html, body").animate({scrollTop: $(location).offset().top}, "slow");
return false;
});
Я сначала разместил его перед </body>
. Но я, похоже, сталкиваюсь с состоянием гонки, когда он стрелял до компиляции quickNav (на нем размещен ng-hide
, не уверен, что это вызывает его, но он находится внутри DOM).
Если я запустил этот блок кода в консоли, прокрутка будет работать, как ожидалось.
Я полагал, что было бы более эффективно переносить это в контроллер - или, скорее, в директиву. Но мне не повезло. Как я могу заставить этот блок кода работать с AngularJS?
Ответы
Ответ 1
Вот простая директива, которая будет прокручиваться до элемента на клике:
myApp.directive('scrollOnClick', function() {
return {
restrict: 'A',
link: function(scope, $elm) {
$elm.on('click', function() {
$("body").animate({scrollTop: $elm.offset().top}, "slow");
});
}
}
});
Демо: http://plnkr.co/edit/yz1EHB8ad3C59N6PzdCD?p=preview
Чтобы помочь в создании директив, просмотрите видео в http://egghead.io, начиная с первой директивы # 10.
изменить. Чтобы сделать его прокруткой к определенному элементу, указанному 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");
});
}
}
});
Затем вы можете использовать его следующим образом: <div scroll-on-click></div>
для прокрутки до щелчка элемента. Или <a scroll-on-click href="#element-id"></div>
для прокрутки к элементу с идентификатором.
Ответ 2
Это лучшая директива, если вы хотите ее использовать:
вы можете прокручивать любой элемент на странице:
.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");
});
}
}})
Использование (например, нажатие на div "back-to-top" будет прокручиваться до прокрутки вверх):
<a id="top-scroll" name="top"></a>
<div class="back-to-top" scroll-to-item scroll-to="#top-scroll">
Он также поддерживается chrome, firefox, safari и IE причиной элемента html, body.
Ответ 3
Чтобы анимировать определенный элемент внутри контейнера прокрутки (фиксированный 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");
}
Ответ 4
Решение angular с использованием $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();
};
});
И вот плунж: http://plnkr.co/edit/xi2r8wP6ZhQpmJrBj1jM?p=preview
И если вы заботитесь о чистом javascript решении, вот один из них:
Вызвать 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);
}
Ссылка: Кросс-браузер JavaScript (не jQuery...) прокручивает до верхней анимации
Ответ 5
Спасибо Andy за пример, это было очень полезно. Я закончил реализацию немного другой стратегии, так как я разрабатываю прокрутку на одну страницу и не хочу, чтобы Angular обновлялся при использовании URL-адреса hashbang. Я также хочу сохранить действие назад/вперед браузера.
Вместо использования директивы и хэша я использую $scope. $watch на $location.search и получаю цель оттуда. Это дает хороший чистый тег привязки
<a ng-href="#/?scroll=myElement">My element</a>
Я приковал код часов к объявлению моего модуля в 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");
});
})
Предостережение с приведенным выше кодом заключается в том, что если вы получаете доступ по 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");
});
});
})
Протестировано с помощью Chrome и FF
Ответ 6
Я использовал andrew joslin answer, который отлично работает, но вызвал изменение маршрута angular, которое создало для меня потрясающий свиток. Если вы хотите избежать изменения маршрута,
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;
});
}
}
});
Ответ 7
Как насчет angular-scroll, он активно поддерживается и нет зависимости от jQuery..
Ответ 8
Другое предложение. Одна директива с селектором.
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
});
}
});
}
}
});
Также обратите внимание на $anchorScroll
Ответ 9
Возобновление этого старого потока, чтобы добавить исправление для некоторых, которые, возможно, не смогли использовать какую-либо из приведенных здесь директив. Оба тела и html не должны иметь установленную процентную высоту, в противном случае эффект не наблюдается. Автоматическое значение может устранить проблему без ограничения размера страницы.
body, html {
height: auto;
}