加载Ng-Repeat元素后运行的jQuery Swiper脚本

我正在使用AngularJS,jQuery,HTML,CSS和Bootstrap创建一个Web应用程序,我想从我的JSON中选择一些位于Apache2服务器中的图像链接并使用它们来在我的主页面中呈现这些图像。 我也想像旋转木马一样刷它们。 为了做到这一点,我正在尝试使用iDangero.us Swiper 。

当我用3个分开的div选择我的图像时,我没有问题。 我得到了我的图像然后我可以按照我想要的方式刷它们。 我这样做如下所示:

main.html中:

我使用Swiper从一个图像滑动到另一个图像,它似乎应该工作。 这是一个jQuery插件,你可以在这个链接上看到一些演示。

Swipers.js:

 angular.module('swipers', []) .controller('',[ $(document).ready(function (){ var swiper = new Swiper('.swiper-container',{ direction: 'horizontal', pagination: '.swiper-pagination', paginationClickable: true }) })]); 

JSON:

 "background1":"background-image: url(images/img1.jpg)", "background2":"background-image: url(images/img2.jpg)", "background3":"background-image: url(images/img3.jpg)" 

mainController.js:

  myApp.controller('MainController', ["$scope","$http", function($scope,$http){ $scope.initGetRequestMain = function(){ $http.get('http://localhost/main.json').success(function(data){ $scope.data=data; }) } }]); 

问题是,当我尝试使用ng-repeat而不是3个单独的div时,我再也看不到它们了,我的Swiper脚本在完全加载之前就会触发。 我的控制台或JSON中没有错误(使用JSONLintvalidation)。 下面,我在两种情况下都添加了2个输出屏幕截图。

使用3个独立的div:

使用3个独立的div

不使用ng-repeat:

不使用ng-repeat

这是我尝试使ng-repeat工作保持与以前相同的控制器和相同的Swiper脚本的代码:

main.html中:

  

mainJson.json:

 "slides":[ {"background":"background-image:url('images/img1.jpg')"}, {"background":"background-image:url('images/img2.jpg')"}, {"background":"background-image: url('images/img3.jpg')"} ], 

为了在触发脚本之前加载我的图像,我正在尝试使用2个自定义指令。

isLoaded告诉我何时加载了最后一个ng-repeat元素并设置了pageIsLoaded = true;

 myApp.directive('isLoaded', function (){ return{ scope:true, restrict: 'A', //Attribute type link: function (scope, elements, arguments){ if (scope.$last === true) { scope.pageIsReady = true; console.log('page Is Ready!'); } } } }) 

gettingTheScript等待pageIsLoaded = true; 并加载脚本:

 myApp.directive('src', function (){ return{ scope:true, restrict: 'A', //Attribute type link: function (scope, elements, arguments){ scope.$on(pageIsReady===true, function(){ if (attr.type === 'text/javascript-lazy'){ scope.scriptLink = arguments.src; } }) }, replace: true, //replaces our element template: '{{scriptLink}}' } }) 

他们似乎没有解决我的问题。 我也看不到console.log('page Is Ready!'); 在制作第一个时。

当我加载页面后必须触发像Swiper这样的脚本以避免这些问题时,我只是遇到了一些麻烦。 我的图像似乎没有高度。 我认为问题是由于在触发我的脚本之前ng-repeat没有完全加载。

我究竟做错了什么? 有更好的解决方案吗?

在开始如何使这项工作成功之前,大多数这些类型的jQuery插件都不能很好地处理角度,因为它们会修改角度不知道的DOM。

话虽这么说,诀窍是推迟jQuery插件的调用,直到Angular渲染DOM。

首先,将swiper插件放入指令中:

 .directive('swiper', function($timeout) { return { link: function(scope, element, attr) { //Option 1 - on ng-repeat change notification scope.$on('content-changed', function() { new Swiper(element , { direction: 'horizontal', pagination: '.swiper-pagination', paginationClickable: true); } //Option 2 - using $timeout $timeout(function(){ new Swiper(element , { direction: 'horizontal', pagination: '.swiper-pagination', paginationClickable: true); }); } }; }) 

对于选项1,您需要修改的isLoaded指令

 myApp.directive('isLoaded', function (){ return{ scope:false, //don't need a new scope restrict: 'A', //Attribute type link: function (scope, elements, arguments){ if (scope.$last) { scope.$emit('content-changed'); console.log('page Is Ready!'); } } } }) 

最后,你的标记(注意从isLoaded到is-loaded的变化….这可能是你没有看到通知的原因)。

 

如上所述,大多数执行轮播function的jQuery插件都不能很好地处理DOM(即新元素)的更改。 即使有这两个选项,如果在首次渲染ng-repeat后更改模型,也可能会看到意外情况。 但是,如果您的模型是静态的,这应该适合您。 如果您的模型发生变化,那么您可能希望搜索更“有角度”的轮播指令。

你可以使用更简单的方法将其融入到Swiper.js中。 初始化swiper时,只需将observer属性设置为true即可。 这将使Swiper监视幻灯片的更改,因此您无需担心是否在通过ng-repeat添加所有幻灯片之前运行它。

例:

var galleryTop = new Swiper('.gallery-top', { observer: true });

从观察者属性的Swiper文档中:

设置为true以在Swiper及其元素上启用Mutation Observer。 在这种情况下,如果您更改其样式(如隐藏/显示)或修改其子元素(如添加/删除幻灯片),Swiper将每次更新(重新初始化)

我正在回答这个老问题,因为有些人要我这样做,因为我想帮助其他开发人员解决这个“有趣”的问题。

一年多之后,我设法使用PromisesFactories解决了这个问题。

基本上,我创建了一个FactoryItemFactory确保获得所需的所有项目(在本例中为幻灯片),然后,我创建了另一个FactorySwiperFactory ,它使用Promise来触发那个有趣的家伙, swipers() 。 我将所有这些工厂方法调用到MainController中,在获取幻灯片并触发脚本之后,它会执行$scope.apply(); 反映主视图中的更改。

main.html中:

 //MainController known as mainCtrl 

MainController.js:

 angular .module('myApp') .controller('MainController', MainController); function MainController($scope, ItemFactory, SwiperFactory) { var vm = this; //Initializing slides as an empty array vm.slides = []; /** Gets called as soon as the Controller is called **/ getData('main.json'); function getData(path){ ItemFactory.getItems(path).then( function(response){ //If response is not empty if (response) { //Assigning fetched items to vm.items vm.slides = response.data; } //Calling triggerSwiper after we ensured fetching item data SwiperFactory.triggerSwiper(); //Callig $scope.$apply() to reflect correctly the changes in the view $scope.$apply(); }) }; } 

ItemFactory.js:

 angular .module('myApp') .factory('ItemFactory', function ($http) { /** Using this referring as ItemFactory Controller **/ var vm = this; vm.API_URL = 'http://localhost/'; /** Gets items from API based on jsonPath **/ function getItems(jsonPath) { return $http.get(vm.API_URL + jsonPath ).then(function (response) { return (response); }); } //Exposing getItems method return { getItems : getItems } }); 

SwiperFactory.js:

 angular .module('myApp') .factory('SwiperFactory', function () { /** Using this referring as SwiperFactory Controller **/ var vm = this; /** Triggers Swiper Script * Resolving only after swiper has been triggered **/ function triggerSwiper(){ return new Promise( function(resolve, reject){ resolve({ $(document).ready(function (){ var swiper = new Swiper('.swiper-container',{ direction : 'horizontal', pagination : '.swiper-pagination', paginationClickable : true }) }); }, function(error){ console.log('Error while triggering Swiper'); }) } //Exposing triggerSwiper method return { triggerSwiper : triggerSwiper } }); 
  • $scope.$apply(); 可以删除,这不是必不可少的
  • 通常,这种方法适用于异步任务

上面的代码完成了工作,但请注意我在下面说的内容

尝试避免在AngularJS项目中使用jQuery库,例如iDangero.us Swiper。 相反,寻找一个Angular库来做同样的工作。 如果回来的话我就像现在这样熟练,我从来没有用过它,尤其是$(document).ready东西。 相反,研究Promises或AngularJS这样做的方式。 我对AngularJS和Web Development一般都是新手,所以我做出了错误的决定。

我希望我一直很有帮助。