2015-04-20 10 views
5

jak mówię w pytaniu, co staram się osiągnąć jest odpowiednikiem kodu jak te w kątowa tylko:Jak ustawić margines stopki na podstawie wysokości innych elementów w Angular i bez jQuery?

jQuery sposób

$(document).ready(function(){ 
    var windowHeight = $(window).height(); 
    var headerHeight = $('header').height(); 
    var footerHeight = $('footer').height(); 
    var contentHeight = $('.content').height(); 
    var paginationHeight = $('.pagination').height(); 

    var footerMarginTop = (windowHeight - headerHeight - footerHeight) - (contentHeight + paginationHeight); 

    $('footer').on('content.loaded', function() { 
    if(footerMarginTop > 0) { 
     $(this).css('margin-top', footerMarginTop + 'px'); 
    } 
    } 
}); 

Na dokumencie gotowy muszę ustawić margines górny stopki na podstawie obliczenia wysokości innych elementów, po załadowaniu zawartości strony. Myślenie w jQuery jest łatwe do zrobienia, ale w kątowa tylko nie znalazłem innego sposobu oprócz tłumaczenia go bezpośrednio jak ta, z katalogu

Kątowymi sposób

angular.module('myApp', []).directive('FooterMargin', ['$window', '$document', function($window, $document){ 
    return { 
    restrict: 'A', 
    link: function(scope, element, attrs) { 

     var windowHeight = $window.innerHeight; 
     var headerHeight = $document[0].getElementById('header').offsetHeight; 
     var footerHeight = $document[0].getElementById('footer').offsetHeight; 
     var paginationHeight = $document[0].getElementById('pagination').offsetHeight; 
     var contentHeight = $document[0].getElementById('content').offsetHeight; 

     var footerMarginTop = (windowHeight - headerHeight - footerHeight) - (contentHeight + paginationHeight); 

     scope.$on('content.loaded', function(){       
      if(footerMarginTop > 0) { 
      attrs.$set('style', 'margin-top: ' + footerMarginTop + 'px'); 
      } 
     } 
     }); 
    } 
    }; 
}]); 

dodałem do identyfikatorów moje elementy, aby odzyskać je w Angular, ale nawet jeśli działa, wydaje mi się, że nie jest to dobry sposób na zrobienie tego, a także trudno jest go przetestować.

nie mogę używać jQuery w tym projekcie, a ja używałem kątowa do drugiej dyrektywy o wydarzeniach, które łatwiej się z nim (jak czasowniki modalne i rozwijanego menu) w zadowalający sposób

Pomożesz mi zrozumieć jak podejść do tego w lepszy sposób Angular?

+0

Dlaczego robisz to w JavaScript, a nie z CSS? Możesz również użyć Jquery Lite, który jest zawarty w kanciastym. – Skatox

+1

Nie mogę używać tylko css, ponieważ muszę popchnąć stopkę na tyle, aby użytkownik mógł zobaczyć ostateczną treść strony nad zakładką, więc muszę obliczyć wszystko na podstawie wysokości zawartości (czyli zawsze różne). i nie używam jqLite, ponieważ nie można wybrać znaczników z klasami lub identyfikatorami – urbando

+0

Możesz to zrobić za pomocą zwykłego kodu JavaScript. –

Odpowiedz

2

Bardziej kątową metodą może być użycie usługi i innej dyrektywy, która definiuje elementy, które chcesz wybrać i ustawia ich wysokość dla usługi.

Twoja oryginalna dyrektywa pobierze wstępnie obliczoną wysokość z nowej usługi.

W moim przykładzie użyłem fabryki heightFactory jako usługi. Musiałem również dodać brzydki czas oczekiwania na to, aby elementy DOM były poprawnie renderowane (i mają rozmiar). Myślę, że to właśnie chciałeś osiągnąć z scope.$on('content.loaded') również w swoim przykładzie.

Zwróć uwagę na użycie dyrektyw w znacznikach jako set-height="header" dla przykładu dla elementu, który ma wysokość nagłówka. Po zarejestrowaniu każdego elementu w usłudze, wartość zwracana dla heightFactory.getMarginTop() będzie zgodna z Twoim algorytmem.

// this directive will ste the window height and retrieve the margin value from the height service 
 
angular.module('myApp', []).directive('footerMargin', ['$window', 'heightFactory', 
 
    function($window, heightFactory) { 
 
    return { 
 
     restrict: 'A', 
 
     link: function(scope, element, attrs) { 
 

 
     heightFactory.setHeight('window', $window.innerHeight); 
 

 
     // delay only for testing purposes, remove this 
 
     $window.setTimeout(function() { 
 
      attrs.$set('style', 'margin-top: ' + heightFactory.getMarginTop() + 'px'); 
 
      console.log(heightFactory.getMarginTop()); 
 
     }, 1000); 
 

 

 
     scope.$on('content.loaded', function() { 
 
      if (heightFactory.getMarginTop() > 0) { 
 
      attrs.$set('style', 'margin-top: ' + heightFactory.getMarginTop() + 'px'); 
 
      } 
 
     }); 
 
     } 
 
    }; 
 
    } 
 
]); 
 

 
// this directive is used for each element, whichs size you want need for your calculation 
 
angular.module('myApp').directive('setHeight', ['heightFactory', 
 
    function(heightFactory) { 
 
    return { 
 
     restrict: 'A', 
 
     link: function(scope, element, attrs) { 
 
     element.ready(function() { 
 
      heightFactory.setHeight(attrs['setHeight'], element[0].offsetHeight); 
 
      console.log(attrs['setHeight'] + ' set to ' + element[0].offsetHeight); 
 
     }); 
 
     } 
 
    } 
 

 
    } 
 
]); 
 

 
// the algorithm for the margin is hardcoded, this service could also just return an object with the heights, and the algorithm would still be in your original directive. It depends on the use case imho. 
 
angular.module('myApp').factory('heightFactory', [ 
 
    function() { 
 
    var height = {}; 
 

 
    return { 
 
     setHeight: function(element, value) { 
 
     height[element] = value; 
 
     }, 
 
     getMarginTop: function() { 
 
     return (height['window'] - height['header'] - height['footer']) - (height['content'] + height['pagination']); 
 
     } 
 
    }; 
 

 
    } 
 
]);
#header { 
 
    background-color: red; 
 
} 
 
#footer { 
 
    background-color: blue; 
 
} 
 
#pagination { 
 
    background-color: grey; 
 
}
<body ng-app="myApp"> 
 
    <header id="header" set-height="header">Header</header> 
 

 
    <section id="content" set-height="content"> 
 
    <p>Some Content</p> 
 
    <p>Some Content</p> 
 
    <p>Some Content</p> 
 
    <p>Some Content</p> 
 
    </section> 
 

 
    <div id="some element" footer-margin>Some Element</div> 
 
    <section id="pagination" set-height="pagination"> 
 
    1 2 3 4 5 6 
 
    </section> 
 
    <footer id="footer" set-height="footer">Footer</footer> 
 

 
</body> 
 

 
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

2

Spróbuj

angular 
    .module('myApp') 
    .directive('FooterMargin', [ 

     function() { 

      function calculateMargins() { 

       // elements 
       var $windowHeight = angular.element(window).height(), 
        $headerHeight = angular.element('#header').height(), 
        $footerHeight = angular.element('#footer').height(), 
        $paginationHeight = angular.element('#pagination').height(), 
        $contentHeight = angular.element('#content').height(); 

       // margin 
       return ($windowHeight - $headerHeight - $footerHeight) - ($contentHeight + $paginationHeight); 

      }; 

      return { 

       restrict: 'A', 

       link: function($scope, element, attrs) { 

        // optional (window resize) 
        angular.element(window).off("resize").on("resize", function(){ 

         // will trigger event to get new margin 
         $scope.$broadcast('content.loaded'); 
        }); 

        // some event 
        $scope.$on('content.loaded', function() { 

         var marginTop = calculateMargins(); 

         if (marginTop > 0) { 
          element.css('margin-top', marginTop); 
         } 

        }); 

       } 
      }; 
     } 


    ]); 

Zauważ użycie "angular.element". Jest to metoda proxy używana jako abstrakcja dla jQLite i jQuery.

Dodałem również zdarzenie zmiany rozmiaru okna. Jest to opcjonalne, ale chodzi o to, że jeśli okno zmieni rozmiar, stopka zostanie ponownie obliczona.

Wreszcie,

Większość tego można osiągnąć poprzez CSS. Wątpię, że nie możesz sprawić, żeby to działało. Zapytanie DOM o 5 elementów jest kosztowne. Powiedział, że użyj swojej dyskrecji.

Dobrą praktyką jest definiowanie metod poza metodą "LINK". To, w teorii, zmniejsza alokację pamięci, którą przeglądarka robi, gdy dyrektywa jest kompilowana i "trawiona".

+0

czy możesz wyjaśnić więcej "Większość tego można osiągnąć poprzez CSS"? – urbando

Powiązane problemy