Директива Angular.js с использованием stellar.js используется несколько раз - работает только первая
Я написал директиву angular.js, которая использует stellar.js для эффектов параллакса. Когда я вызываю одну и ту же директиву несколько раз одна за другой, stellar.js будет работать только с первой. Я читаю о $.stellar('refresh');
который должен повторно инициализировать звездный после введения элементов в DOM, но это не повлияло на меня. Также вызов звездного на окне не имел никакого эффекта.
Вот код моей директивы:
angular.module('ClientApp')
.directive('parallaxModule', function () {
return {
templateUrl: 'views/parallax-module.html',
restrict: 'E',
scope: {
data: '='
},
controller: function() {
$(function(){
$(this).stellar({
horizontalScrolling: false,
verticalScrolling: true,
verticalOffset: 50
});
});
}
};
});
Вот как я использую директиву:
<parallax-module data="sectionData.para"></parallax-module>
<parallax-module data="sectionData.para"></parallax-module>
И вот мой шаблон:
<div class="parallax-module" data-stellar-background-ratio="0.2">
<div class="wrapper" data-stellar-ratio="2.5">
<div class="title">{{data.title}}</div>
<div class="caption">{{data.caption}}</div>
</div>
</div>
Вот плункер: http://plnkr.co/edit/TJbPL3dhSsiitZQWm9Qe?p=preview
3 ответа
$timeout
работает, потому что предполагается, что звездный плагин применяется не к каждому элементу параллакса, а к контейнеру прокрутки. В примере в документах он применяется к window
: $(window).stellar();
И так, с $timeout
, код "ждет" конца очереди дайджеста, и когда он выполняется, все директивы загружаются. К сожалению, он выполняется для каждой директивы без необходимости.
Решение состоит в том, чтобы применить директиву к контейнеру. Тогда это становится так просто, как:
.directive("parallaxContainer", function(){
return {
link: function(scope, element){
element.stellar({
horizontalScrolling: false,
verticalScrolling: true,
verticalOffset: 0
});
}
}
})
Это решение основано на наличии совместимого с звездой элемента (с data-stellar-background-ratio
например) в этом контейнере:
<body parallax-container>
<div data-stellar-background-ratio="0.2">
...
</div>
<div data-stellar-background-ratio="0.2">
...
</div>
</body>
РЕДАКТИРОВАТЬ:
Приведенный выше код не будет работать, если элементы параллакса загружаются динамически. Это немного усложняет, но не сильно. В этом случае нам понадобится директива контейнера, отвечающая за запуск плагина, и фактические директивы элементов параллакса, которые будут регистрироваться в контейнере и уведомлять контейнер, когда они загрузятся.
Директива элемента может использовать ng-include
получить уведомление о загрузке контента. Эта директива использует require: "^parallaxContainer"
,
app.directive('parallaxModule', function() {
return {
template: '<div ng-include="\'parallax-module.html\'" onload="notifyLoaded()"></div>',
restrict: 'E',
scope: {
data: '='
},
require: "^parallaxContainer",
link: {
pre: function(scope, element, attrs, parallaxContainer){
parallaxContainer.registerElement();
scope.notifyLoaded = parallaxContainer.notifyElementLoaded;
}
}
};
})
parallaxContainer
Директивы добавляет контроллер, который предоставляет методы для регистрации и уведомления. И он запускает плагин, когда все дети загружены
app.directive("parallaxContainer", function() {
var parallaxElementCount = 0;
var parallaxElementLoaded = 0;
return {
controller: function($element){
this.registerElement = function(){
parallaxElementCount++;
};
this.notifyElementLoaded = function(){
parallaxElementLoaded++;
if (parallaxElementCount !== 0 && parallaxElementCount === parallaxElementLoaded){
$element.stellar({
horizontalScrolling: false,
verticalScrolling: true,
verticalOffset: 0
});
}
}
},
}
})
Обратите внимание, что stellar
не работает (по какой-то причине - возможно, есть некоторая информация об этом в звездных документах), когда он активируется более одного раза, поэтому после запуска загрузка большего количества дочерних элементов ничего не изменит.
Я нашел решение: поскольку звездный не является частью угловой структуры, я должен использовать $apply() для выполнения звездных выражений. Но так как $ digest уже выполняется в моей директиве, я должен использовать $timeout, чтобы получить вызов stellar() в другом цикле дайджеста. $ timeout неявно вызывает $ apply. Я также должен вызвать stellar() для angular.element($window), чтобы правильно запустить несколько директив.
Итак, вот мой рабочий код:
angular.module('ClientApp')
.directive('parallaxModule', function ($timeout, $window) {
return {
templateUrl: 'views/parallax-module.html',
restrict: 'E',
scope: {
data: '='
},
link: function() {
$timeout(function () {
angular.element($window).stellar({
horizontalScrolling: false,
verticalScrolling: true,
verticalOffset: 50
});
});
}
};
});
Использовать директиву NG-PARALLAX для Angular2/Angular4 очень просто.
Ссылка: https://www.npmjs.com/package/ng2-parallaxscroll
Git: https://github.com/tyrantwave/ng2-parallaxscroll
Пример 1:
<div parallax [config]="{axis: x, speed: -.3}" style=" background-image: url('/parallax_img.jpg');"></div>
Пример 2:
<ng-parallax img="img/img.jpg" [config]="{axis: x, speed: -.3}" class="some-class"></ng-parallax>