簡體   English   中英

使用Angular UI Router在一頁上具有AngularJS中的歷史記錄的多個視圖

[英]Multiple views on one page with history in AngularJS using Angular UI Router

在我的AngularJS應用中,我有一個關於頁面,其中包含幾個小節。 所有這些小節都在同一頁面上,並且是同一模板的一部分。 但是,我想通過它自己的URL訪問每個部分,如果匹配,它將向下滾動到正確的部分。

我已經將狀態設置為:

.state('about', {
    url: "/about",
    templateUrl: "partials/about.html",
})
.state('about.team', {
    url: "/about/team",
    templateUrl: "partials/about.html"
})
.state('about.office', {
    url: "/about/office",
    templateUrl: "partials/about.html"
})
.state('about.other', {
    url: "/about/other",
    templateUrl: "partials/about.html"
});

在About頁面上,我有一個類似的菜單:

<div class="menu">
    <a ui-sref-active="selected"
    ui-sref="about.team">The Team</a>
    <a ui-sref-active="selected"
    ui-sref="about.office">The Office</a>
    <a ui-sref-active="selected"
    ui-sref="about.other">Other</a>
</div>

此菜單固定在底部,當用戶單擊鏈接或通過地址欄直接訪問URL時,應滾動到該部分(在需要匹配的URL上進行更新)。

但是我不確定如何做到這一點(通過Angular)。 總結一下:

  1. 如何通過URL滾動到同一頁面的不同部分? 由於我無法使用標准的哈希技巧,因為它已經在地址中使用了哈希(我們支持IE8)。 而且,在HTML5模式下,我根本不想使用哈希! 應用加載后,它還應該滾動到頁面加載部分,因此需要一種觸發代碼的方法,以便在其他情況下滾動用戶。
  2. 單擊按鈕如何進行這項工作? 當前,當單擊按鈕時,它們會更改URL,但不會滾動到內容。

該頁面的HTML看起來像: http : //pastebin.com/Q60FWtL7

您可以在此處查看該應用程序: http : //dev.driz.co.uk/AngularPage/app/#/about

有關類似示例( https://devart.withgoogle.com/#/about/your-opportunity )的示例,您可以看到頁面加載后,它會根據URL向下滾動到正確的部分。不要使用哈希,而是使用ACTUAL網址。

您可以在創建可觸發點擊滾動的指令時嘗試這種方法。 您可以將此指令作為屬性添加到鏈接。 sref屬性將是目標div的ID。

app.directive('scrollTo', function() {
  return {
    link: function(scope, element, attrs) {
    element.bind('click', function() {
      var divPosition = $(attrs.sRef).offset();
      $('html, body').animate({
      scrollTop: divPosition.top
      }, "slow");

    });
   }
  };
});

柱塞

ui-router對狀態對象的簽名沒有限制,因此您只需添加一個屬性即可:

  .state('about.office', {
     url: "/about/office"
    ,templateUrl: "partials/about.html"
    ,scrollToId = "divAboutOffice";
  })

這樣,當您注入$ state服務時,控制器就可以訪問此數據。

  $('html, body').animate({
    scrollTop:  $($state.current.scrollToId).offset().top
  }, "slow");

假設您在HTML中添加了id="divAboutOffice" (並且假設我的jQuery引用是正確的;我不使用jquery,所以我不確定。)根據您的需要,您可以將animate()包裝在$on()用於以下事件之一: $locationChangeSuccess)$routeChangeSuccess$stateChangeSuccess

還:您不必像我一樣使用“ id”-如果您確實想按屬性搜索元素,則可以利用現有的ui-sref 在您的示例中,看起來與$state.current.name匹配

我將使用window.scrollTo或jquery scrollTo插件創建scrollTo指令。

示例:使用window.scrollTo 滾動到給定項目的Angular指令

jQuery scrollTo插件:

https://github.com/flesler/jquery.localScroll

https://github.com/flesler/jquery.scrollTo

在頁面加載中,您滾動到由標簽或任何其他url參數定義的視圖。 例如:www.sample.com#aboutUs或www.samplecom?view = aboutUs

在滾動時,我應該:

1. bind to "scroll" events, 
2. compare if I reached the position of each headers, using "element.offset().top"

(在將標題設置為指令后。(我應將標題設置為指令,檢查如何從ngtutorial.com/learn/scope生成目錄)

3. update location.url()

在加載時(我更喜歡使用標簽,因為我可以只使用$ anchorScroll()或.when()),無論如何,在加載時進行更新的示例是:

1. http://ngtutorial.com/guide.html#/learn-filter.html
2. http://ngtutorial.com/learn/route.html#/_tblcontents_5

如果您不喜歡主題標簽,則可以解析location.url()

我在自己的應用程序中使用https://github.com/durated/angular-scroll進行滾動控制(和滾動間諜工作),而不是使用locationHash。 我自己沒有嘗試過此解決方案,但我認為它可以工作。

您需要在重要的div上聲明某種項目ID(作為您滾動到的位置)。

然后,您可以使用url / about /:locale聲明狀態“ about.stately”(在ui路由器state中,Param不必為整數)。 然后在控制器中大約。狀態,您可以(從角度滾動自述文件中)執行以下操作:

var someElement = angular.element(document.getElementById('some-id'));
$document.scrollToElement(someElement, offset, duration);

根據控制器中的$ stateParams.locale選擇要滾動到的元素。 請注意,直到所有子指令和所有內容加載完畢后,您可能需要$ evalAsync才能使其正常工作。 但是,我認為這就是要點。

這是我目前所嘗試的:

var scrolled = false;

var listenToScroll = false;

$('.subsection').each(function(i) {
    var position = $(this).position();
    $(this).scrollspy({
        min: position.top,
        max: position.top + $(this).outerHeight(),
        onEnter: function(element, position) {
            if(element.id){
                if(listenToScroll) {
                    scrolled = true;
                    $state.transitionTo('about.'+element.id);
                }
            } else {
                if(listenToScroll) {
                    scrolled = true;
                    $state.transitionTo('about');
                }
            }
        }
    });
});

$scope.startListenToScroll = function() {       

    listenToScroll = true;
}

$scope.stopListenToScroll = function(){

    listenToScroll = false;
}

$scope.$on('$stateChangeStart', function(){

    $scope.stopListenToScroll();

});

$scope.$on('$stateChangeSuccess', function(){

    console.log(scrolled);

    if( !scrolled ) {
        var link = $state.current.name.split('.');
        if(link.length>1){
            var divPosition = $( '#' + link[1] ).offset();
            $('body').stop(true,true).animate({ scrollTop: divPosition.top }, "fast", function(){
                $scope.startListenToScroll();
                scrolled = false;
            });
        } else {
            $('body').stop(true,true).animate({ scrollTop: 0 }, "fast", function(){
                $scope.startListenToScroll();
                scrolled = false;
            });
        }
    } else {
        $scope.startListenToScroll();
        scrolled = false;
    }

});

如您所見,我聽stateChangeSuccess而不是點擊! 這樣,無論鈎子是由鏈接還是由瀏覽器歷史記錄按鈕調用的,我都會陷入任何狀態更改,並根據需要執行滾動。

我會在開始更改開始后立即關閉scrollspy,以便滾動動畫不會調用其他狀態更改(因為您可能會通過其他部分進行滾動,從而創建偽造的歷史記錄條目)。 動畫完成后再將其重新打開,這樣我就可以再次收聽滾動事件。

stateChangeSuccess在頁面加載時觸發,因此它可以處理任何URL粘貼。

我有一個名為scrolled的變量,因此我可以跟蹤狀態更改是否由用戶滾動引起。 這是因為當用戶滾動它們時,我不需要為scrollTop設置動畫。

有什么想法嗎?

您需要做的是在ui-router之外的頁面頂部創建一個指令,該指令可以監視狀態,然后根據右錨點滾動。 然后,您無需使用templateUrls,因為您要實現的是某種平滑。

// get the current path
var x=$location.path();
// say x='about/team'
//read the last tag and set scrollTo to the top offset of desired div
if(lasttag(x)==team){
scroll to top offset of TEAM div;
}
else if(lasttag(x)==office){
scroll to top offset of OFFICE div;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM