jQuery Swiper 脚本在加载 Ng-Repeat 元素后运行 [英] jQuery Swiper script to run after Ng-Repeat elements are loaded

查看:32
本文介绍了jQuery Swiper 脚本在加载 Ng-Repeat 元素后运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 AngularJS、jQuery、HTML、CSS 和 Bootstrap 制作一个 Web 应用程序,我想从位于 Apache2 服务器中的 JSON 中选择一些图像链接并使用它们来呈现这些图像我的主页.我也想像在旋转木马中一样滑动它们.为了使这项工作发挥作用,我正在尝试使用

不适用于 ng-repeat:

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

Main.html:

 

<div ng-repeat="slide in data.slides" isLoaded=""><div class="swiper-slide" style="{{slide.background}}"ng-click="swipers()"></div>

<script type="text/javascript-lazy" src="scripts/custom/main/swipers.js"></script>

ma​​inJson.json:

幻灯片":[{"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 (){返回{范围:真,限制: 'A',//属性类型链接:函数(作用域、元素、参数){if (scope.$last === true) {scope.pageIsReady = true;console.log('页面准备好了!');}}}})

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

myApp.directive('src', function (){返回{范围:真,限制: 'A',//属性类型链接:函数(作用域、元素、参数){scope.$on(pageIsReady===true, function(){if (attr.type === 'text/javascript-lazy'){scope.scriptLink = arguments.src;}})},replace: true,//替换我们的元素模板:'{{scriptLink}}'}})

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

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

我做错了什么?有没有更好的解决方案?

解决方案

在开始讨论如何使其工作之前,大多数这些类型的 jQuery 插件不能很好地与 angular 配合使用,因为它们对 DOM 进行了修改,而 angular 不能不知道.

话虽如此,诀窍是将 jQuery 插件的调用推迟到 Angular 呈现 DOM 之后.

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

.directive('swiper', function($timeout) {返回 {链接:函数(范围,元素,属性){//选项 1 - 关于 ng-repeat 更改通知scope.$on('内容改变', function() {新的 Swiper(元素,{方向:'水平',分页:'.swiper-分页',分页可点击:真);}//选项 2 - 使用 $timeout$超时(功能(){新的 Swiper(元素,{方向:'水平',分页:'.swiper-分页',分页可点击:真);});}};})

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

myApp.directive('isLoaded', function (){返回{scope:false,//不需要新的作用域限制: 'A',//属性类型链接:函数(作用域、元素、参数){如果(范围.$last){scope.$emit('内容改变');console.log('页面准备好了!');}}}})

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

<div ng-repeat="slide in data.slides" is-loaded><div class="swiper-slide" style="{{slide.background}}"ng-click="swipers()"></div>

如前所述,大多数具有轮播功能的 jQuery 插件不能很好地处理对 DOM(即新元素)的更改.即使有这两个选项,如果在首次渲染 ng-repeat 之后更改模型,您也可能会看到意外的事情.但是,如果您的模型是静态的,这应该适合您.如果您的模型发生变化,那么您可能需要搜索更有角度"的轮播指令.

I'm making a web app using AngularJS, jQuery, HTML, CSS and Bootstrap, and I would like to pick some image links from my JSON that is located in an Apache2 server and use them in order to render those images in my main page. I would also like to swipe them like in a carousel. To make that work, I'm trying to use iDangero.us Swiper.

When I pick my images with 3 separated divs, I have no problems. I get my images and then I can normally swipe them as I want. I do it like shown below:

Main.html:

<div ng-init="initGetRequestMain()">

  <div class="swiper-slide" ng-click="swipers()" 
              style="{{data.background1}}"></div>
  <div class="swiper-slide" ng-click="swipers()" 
              style="{{data.background2}}"></div>
  <div class="swiper-slide" ng-click="swipers()" 
              style="{{data.background3}}"></div>

   <script src="scripts/custom/main/swipers.js"></script>
</div>

I use Swiper to swipe from one image to another, and it seems to work as it should. It's a jQuery plugin, and you can see some demos at this link.

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;
       })
      }
  }]);

The problem is that when I try to use ng-repeat instead of 3 separated divs, I can't see them anymore and my Swiper script triggers before they are fully loaded. I have no errors in my console or in my JSON (validated with JSONLint). Below, I added 2 screenshots of my output in both situations.

Working with 3 separated divs:

Not working with ng-repeat:

This is the code where I try to make ng-repeat work keeping the same controller and the same Swiper script as before:

Main.html:

  <div ng-init="initGetRequestMain()">

       <div ng-repeat="slide in data.slides" isLoaded="">
           <div class="swiper-slide" style="{{slide.background}}" 
                       ng-click="swipers()"></div>
       </div>

    <script type="text/javascript-lazy" src="scripts/custom/main/swipers.js"></script>
  </div>

mainJson.json:

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

In order to get my images loaded before triggering the script, I'm trying to use 2 custom directives.

isLoaded tells me when the last ng-repeat element is loaded and sets 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 waits for pageIsLoaded = true; and loads the script:

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}}'
       }
  })   

They do not seem to fix my problem. I also can't see console.log('page Is Ready!'); when making the first one.

I'm just having some troubles when I have to trigger a script like Swiper after the page is loaded in order to avoid these kind of problems. My images seem to have no height. I think that the problem is caused by ng-repeat not fully loading before triggering my script.

What am I doing wrong? Are there better solutions?

解决方案

Before getting into how to make this work, most of these types of jQuery plugins don't work well with angular since they make modifications to the DOM that angular doesn't know about.

That being said, the trick is deferring the invocation of the jQuery plugin until after Angular has rendered the DOM.

First, put your swiper plugin into a directive:

.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);
            });

        }
    };
})

For Option 1, you need a modified isLoaded directive

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!');
        }
     }   
   }
})

Finally, your markup (note the change from isLoaded to is-loaded....this is probably the reason you weren't seeing the notification).

<div ng-init="initGetRequestMain()" swiper>

   <div ng-repeat="slide in data.slides" is-loaded>
       <div class="swiper-slide" style="{{slide.background}}" 
                   ng-click="swipers()"></div>
   </div>
</div>

As mentioned, most jQuery plugins that do carousel functionality don't handle changes to the DOM (i.e new elements) very well. Even with both options, you may see unexpected things if you change your model after the ng-repeat is first rendered. However, if your model is static, this should work for you. If your model changes, then you might want to search for a more "angular" carousel directive.

这篇关于jQuery Swiper 脚本在加载 Ng-Repeat 元素后运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆