クイックナビを正常に動作させようとしています。それは横に浮いています。リンクをクリックすると、ページ内のそのIDに移動します。私はこの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で動作させることができるのでしょうか?
ここでは、クリックすると要素にスクロールする簡単なディレクティブをご紹介します。
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 "first directive"から始まるビデオをご覧ください。
編集。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>
とすると、idを持つ要素にスクロールします。
これは、万が一に備えて、より良いディレクティブを使用しています。
を使うと、ページ内の任意の要素にスクロールすることができます。
.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'をクリックすると、id scroll-topまでスクロールします)。
<a id="top-scroll" name="top"></a>
<div class="back-to-top" scroll-to-item scroll-to="#top-scroll">
html,body要素が原因で、chrome,firefox,safari,IEでもサポートされています。
アンディさん、例を挙げていただきありがとうございます。私はシングルページスクロールを開発しており、ハッシュバングURLを使用する際にAngularがリフレッシュすることを望んでいなかったので、少し異なる戦略を実施することになりました。また、ブラウザの戻る/進むアクションを維持したいと考えています。
ディレクティブとハッシュを使う代わりに、$location.searchに$scope.$watchを使い、そこからターゲットを取得しています。これできれいなアンカータグができました。
<a ng-href="#/?scroll=myElement">My element</a>
時計のコードをapp.jsのmyモジュール宣言に連結してみました。
.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にアクセスした場合、jQuery'の$target.offset()の呼び出しに間に合わず、DOMがロードされない可能性があることです。解決策は、このコードを$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でテストした結果