jQuery插件与Angularjs不兼容

时间:2022-08-23 13:12:46

i have used jQuery slider in my project in which i am loading images using angular. My current view looks like this;

我在我的项目中使用了jQuery滑块,我使用angular加载图像。我目前的观点是这样的;

        <div id="slides">
            <div class="slides_container">
                <a href="" data-ng-repeat="image in gallery">
                    <img data-ng-src="{{image.imageUrl}}" width="919" height="326" alt="" />
                </a>
            </div>
        </div>

the controller;

控制器;

blogApp.controller("HomeController", ['$scope', '$resource', function ($scope, $resource) {
    var basePath = '/api/',
        FrontGallery = $resource(basePath + 'gallery?culture=en-US'),

    $scope.gallery = FrontGallery.query();
}]);

And the jQuery slider code (to make it a slider. I'm using this plugin http://archive.slidesjs.com/)

和jQuery滑块代码(使它成为一个滑块。我正在使用这个插件http://archive.slidesjs.com/)

$(document).ready(function () {
    $('#slides').slides({
        preload: true,
        preloadImage: '/content/images/theme/loading.gif',
        play: 5000,
        pause: 2500,
        hoverPause: true
    });
});

When, i try this code, my all images are loaded from database (debugged it through firebug) but jQuery slider isn't applying the animation or sliding effect to it
And when i remove the data-ng-repeat="image in gallery and use Some static content i.e images, i get the sliding effect back.
What's the problem here. I think Angular is manipulating some how my DOM. That's why i'm getting this problem whenever i put i.e use some angular attributes on my slider.
Note: i have the same issue with jQuery news i.e jQuery InnerFade plugin http://medienfreunde.com/lab/innerfade/
Here is how the innerFade is used;

什么时候,我尝试这个代码,我的所有图像都从数据库加载(通过firebug调试)但jQuery滑块没有应用动画或滑动效果,当我删除数据-ng-repeat =“图像在库和使用一些静态内容,即图像,我得到了滑动效果。这里的问题是什么。我认为Angular正在操纵我的DOM。这就是为什么我每次放置时都会遇到这个问题,即在我的滑块上使用一些角度属性。 :我对jQuery新闻有同样的问题,即jQuery InnerFade插件http://medienfreunde.com/lab/innerfade/以下是如何使用innerFade;

<h1>
    <img src="/content/images/theme/hotnews.png" alt="" />Hot News</h1>
<ul id="news">
    <li class="ng-repeat:headline in news">
        <span class="ng-bind:headline.description"></span>
        <a href="#" title="Read More">» more</a>
    </li>
</ul>

and the controller;

和控制器;

var HotNews = $resource(basePath + 'article/hotnews?culture=en-US');
$scope.news = HotNews.query();

How do i fix these problems?
Update 2: Here is my routes;

我该如何解决这些问题?更新2:这是我的路线;

// declare a module
var blogApp = angular
    .module('blogApp', ['ngResource', 'ngSanitize'])
    .config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {
        //$locationProvider.html5Mode(true);
        //configure the routes
        $routeProvider
            .when('/', {
                // list the home page
                templateUrl: "tmpl/home.html",
                controller: "HomeController"
            })
            .when('/article/:id', {
                // access custom param
                foo: "hello world",
                // list the home page
                templateUrl: "tmpl/article.html",
                controller: "ArticleController"
            })
            .when('/404', {
                template: '<h1>404 Not Found!</h1>'
            })
            .otherwise({ redirectTo: '/404' });
    }]);

Solution #1: Temporary, (As @Jason Goemaat answered) works for me. So, here is what i have done. I didn't create any directive but straightly i injected the $timeout to my controller and then i did the following;

解决方案#1:临时,(正如@Jason Goemaat回答的)对我有用。所以,这就是我所做的。我没有创建任何指令,但直接我将$ timeout注入我的控制器,然后我做了以下操作;

$timeout(function () {
    jQuery('#news').innerfade({
        animationtype: 'slide',
        speed: 750,
        timeout: 2000,
        type: 'random',
        containerheight: '1em'
    });
    jQuery('#slides').slides({
        preload: true,
        preloadImage: 'image/theme/loading.gif',
        play: 5000,
        pause: 2500,
        hoverPause: true
    });

}, 100);

And it did work for both i.e for Slider and for InnerFade

它确实适用于Slider和InnerFade

5 个解决方案

#1


6  

Angular IS manipulating your dom, the ng-repeat directive is creating the elements when it has a list to work from. Because of that you need to call .slides after angular is done creating the elements because that plugin is altering the DOM itself.

Angular IS操纵你的dom,ng-repeat指令在有一个可以使用的列表时创建元素。因此,你需要在角度完成之后调用.slides创建元素,因为该插件正在改变DOM本身。

Here's a directive you can use to call $.slides on an element based on when an array has length > 0. It shows using extra attributes like 'start' to modify the call to slides too. Here it checks an array on your $scope called 'images' and calls $timeout() during the link phase to call .slidesjs() when angular is done creating the DOM. I didn't know what plugin you used so I found one called 'slidesjs that looked similar. 'Here's a plunker: http://plnkr.co/edit/4qdUctYMIpd8WqEg0OiO?p=preview

这是一个指令,您可以使用它来根据数组长度> 0时调用元素上的$ .slides。它显示使用额外的属性,如'start'来修改对幻灯片的调用。在这里,它检查$ scope上的一个名为'images'的数组,并在链接阶段调用$ timeout(),以便在创建DOM时完成角度调用.slidesjs()。我不知道你使用了什么插件,所以我发现了一个名为'slidejs,看起来很相似。 '这是一个吸烟者:http://plnkr.co/edit/4qdUctYMIpd8WqEg0OiO?p=preview

Html:

HTML:

<div my-slides="images" start="4">
  <img ng-repeat="image in images" ng-src="{{image.url}}" />
</div>

Directive:

指示:

app.directive('mySlides', function() {
  var directive = {
    restrict: 'A',
    link: function(scope, element, attrs, ctrl) {
      scope.$watch(attrs.mySlides, function(value) {
        setTimeout(function() {
          // only if we have images since .slidesjs() can't
          // be called more than once
          if (value.length > 0) {
            $(element[0]).slidesjs({
              preload: true,
              preloadImage: '/content/images/theme/loading.gif',
              play: attrs.play || 5000,
              pause: attrs.pause || 2500,
              start: attrs.start || 1,
              hoverPause: attrs.hoverPause || true,
              navigation: { active: true, effect: "slide" }
            });
          }
        }, 1);
      });
    }
  };
  return directive;
});

One thing to note is that it still can only be called once, so if your image list gets updated it won't work. To do that you could create the content in the directive...

需要注意的一点是,它仍然只能被调用一次,因此如果您的图像列表得到更新,它将无法工作。为此,您可以在指令中创建内容......

#2


9  

 $(document).ready(function () {

is firing before angular has loaded the content onto the page. The jQuery slider script should only be activated after angular has loaded the content. Part of the problem here is that angular does not provide a callback for $digest so you don't have an event to listen for.

在角度已将内容加载到页面上之前触发。只有在角度加载内容后才能激活jQuery滑块脚本。这里的部分问题是angular不提供$ digest的回调,所以你没有要监听的事件。

The content load -> event callback -> ui build, while common in jQuery and standard javascript thinking, its not part of the angular mentality. Luckily angular has an insanely powerful method for handling this problem.

内容加载 - >事件回调 - > ui构建,虽然在jQuery和标准的javascript思维中很常见,但它不是角度心态的一部分。幸运的角度有一个非常强大的方法来处理这个问题。

What you need is to turn the jQuery slideshow script into an angular directive. Then it will become part of the angular process space and get instantiated as a part of the angular digest cycle.

您需要的是将jQuery幻灯片脚本转换为角度指令。然后它将成为角度处理空间的一部分并被实例化为角度摘要周期的一部分。

Something like

就像是

   <div id="slides" my-slideshow >
        <div class="slides_container">
            <a href="" data-ng-repeat="image in gallery">
                <img data-ng-src="{{image.imageUrl}}" width="919" height="326" alt="" />
            </a>
        </div>
    </div>

Good luck!

祝你好运!


Happy example time using innerfade (I have not tested this yet, will do ASAP). First your application must declare an angular module if it doesn't already. ng-app="myModule". http://docs.angularjs.org/api/angular.module

使用innerfade的快乐示例时间(我还没有测试过,会尽快做到)。首先,您的应用程序必须声明角度模块(如果尚未声明)。 NG-应用= “MyModule的”。 http://docs.angularjs.org/api/angular.module

(make sure your controller is attached as well!)

(确保您的控制器也已连接!)

Now you can declare a directive on that module. Which is super cool.

现在您可以在该模块上声明一个指令。哪个超酷。

angular.module('myModule').directive("innerFade", function () {
   var res = {
     restrict : 'C',
     link     : function (scope, element, attrs) {
           scope.$watch(attrs.innerFade, function(){             
               element.innerfade({
                  speed: 'slow',
                  timeout: 1000,
                  type: 'sequence',
                  containerheight: '1.5em'
               });
           });
        }
     };
  return res;
});

The way this works is pretty simple. The $watch function will monitor the part of scope containing your data. When that changes (including initialization), it will fire the innerfade jQuery function on the element with the directive. We are also passing 'C' to the restrict argument so this custom directive will be a class only directive (I noticed you seem to like that).

这种方式非常简单。 $ watch函数将监视包含数据的范围部分。当更改(包括初始化)时,它将使用指令触发元素上的innerfade jQuery函数。我们也将'C'传递给restrict参数,所以这个自定义指令将是一个只有类的指令(我注意到你似乎喜欢这样)。

 <ul class="inner-fade:innerData" >
      <li class="ng-repeat:fadeItem in innerData">{{fadeItem}}</li>
 </ul>

Now all you have to do is bind the data to $scope.innerData in your controller (bind it any way you like including ajax), and it will just work. You can even change the data on $scope.innerData and it will update with full jQuery glory.

现在你所要做的就是将数据绑定到控制器中的$ scope.innerData(以任何你喜欢的方式绑定它,包括ajax),它就可以了。您甚至可以更改$ scope.innerData上的数据,它将使用完整的jQuery荣耀进行更新。

#3


1  

A few thoughts
1) My guess is that there is something sequentially wrong with your main app page. Do you have jQuery include after angularjs? I assume you are using ng-repeat directive?

一些想法1)我的猜测是你的主应用页面有一些顺序错误。在angularjs之后你有jQuery包含吗?我假设您正在使用ng-repeat指令?

2) change $ to jQuery

2)将$更改为jQuery

3) place document.ready script in main page ... also consider replacing it with

3)将document.ready脚本放在主页面中......也考虑将其替换为

 window.onload=function(){} 

I am sure I can debug if you can show code for main page as well as the view.

如果你能显示主页面和视图的代码,我相信我可以调试。

#4


1  

Add a directive to #slides

向#slides添加指令

app.directive("slideDirective", function () {
     return function (scope, element, attrs) {
         // Dom
         element.slides({
             preload: true,
             preloadImage: '/content/images/theme/loading.gif',
             play: 5000,
             pause: 2500,
             hoverPause: true
         });
     }
}

#5


1  

as it was said: "The jQuery slider script should only be activated after angular has loaded the content" So you can wait before it will be loaded, and then your jQuery code will start running.

正如所说:“jQuery滑块脚本只应在angular加载内容后才能激活”所以你可以等到它加载之后,然后你的jQuery代码就会开始运行。

$(document).ready(function () {
setTimeout(function(){
      $('#slides').slides({
        preload: true,
        preloadImage: '/content/images/theme/loading.gif',
        play: 5000,
        pause: 2500,
        hoverPause: true
     });
}, 10);
});

#1


6  

Angular IS manipulating your dom, the ng-repeat directive is creating the elements when it has a list to work from. Because of that you need to call .slides after angular is done creating the elements because that plugin is altering the DOM itself.

Angular IS操纵你的dom,ng-repeat指令在有一个可以使用的列表时创建元素。因此,你需要在角度完成之后调用.slides创建元素,因为该插件正在改变DOM本身。

Here's a directive you can use to call $.slides on an element based on when an array has length > 0. It shows using extra attributes like 'start' to modify the call to slides too. Here it checks an array on your $scope called 'images' and calls $timeout() during the link phase to call .slidesjs() when angular is done creating the DOM. I didn't know what plugin you used so I found one called 'slidesjs that looked similar. 'Here's a plunker: http://plnkr.co/edit/4qdUctYMIpd8WqEg0OiO?p=preview

这是一个指令,您可以使用它来根据数组长度> 0时调用元素上的$ .slides。它显示使用额外的属性,如'start'来修改对幻灯片的调用。在这里,它检查$ scope上的一个名为'images'的数组,并在链接阶段调用$ timeout(),以便在创建DOM时完成角度调用.slidesjs()。我不知道你使用了什么插件,所以我发现了一个名为'slidejs,看起来很相似。 '这是一个吸烟者:http://plnkr.co/edit/4qdUctYMIpd8WqEg0OiO?p=preview

Html:

HTML:

<div my-slides="images" start="4">
  <img ng-repeat="image in images" ng-src="{{image.url}}" />
</div>

Directive:

指示:

app.directive('mySlides', function() {
  var directive = {
    restrict: 'A',
    link: function(scope, element, attrs, ctrl) {
      scope.$watch(attrs.mySlides, function(value) {
        setTimeout(function() {
          // only if we have images since .slidesjs() can't
          // be called more than once
          if (value.length > 0) {
            $(element[0]).slidesjs({
              preload: true,
              preloadImage: '/content/images/theme/loading.gif',
              play: attrs.play || 5000,
              pause: attrs.pause || 2500,
              start: attrs.start || 1,
              hoverPause: attrs.hoverPause || true,
              navigation: { active: true, effect: "slide" }
            });
          }
        }, 1);
      });
    }
  };
  return directive;
});

One thing to note is that it still can only be called once, so if your image list gets updated it won't work. To do that you could create the content in the directive...

需要注意的一点是,它仍然只能被调用一次,因此如果您的图像列表得到更新,它将无法工作。为此,您可以在指令中创建内容......

#2


9  

 $(document).ready(function () {

is firing before angular has loaded the content onto the page. The jQuery slider script should only be activated after angular has loaded the content. Part of the problem here is that angular does not provide a callback for $digest so you don't have an event to listen for.

在角度已将内容加载到页面上之前触发。只有在角度加载内容后才能激活jQuery滑块脚本。这里的部分问题是angular不提供$ digest的回调,所以你没有要监听的事件。

The content load -> event callback -> ui build, while common in jQuery and standard javascript thinking, its not part of the angular mentality. Luckily angular has an insanely powerful method for handling this problem.

内容加载 - >事件回调 - > ui构建,虽然在jQuery和标准的javascript思维中很常见,但它不是角度心态的一部分。幸运的角度有一个非常强大的方法来处理这个问题。

What you need is to turn the jQuery slideshow script into an angular directive. Then it will become part of the angular process space and get instantiated as a part of the angular digest cycle.

您需要的是将jQuery幻灯片脚本转换为角度指令。然后它将成为角度处理空间的一部分并被实例化为角度摘要周期的一部分。

Something like

就像是

   <div id="slides" my-slideshow >
        <div class="slides_container">
            <a href="" data-ng-repeat="image in gallery">
                <img data-ng-src="{{image.imageUrl}}" width="919" height="326" alt="" />
            </a>
        </div>
    </div>

Good luck!

祝你好运!


Happy example time using innerfade (I have not tested this yet, will do ASAP). First your application must declare an angular module if it doesn't already. ng-app="myModule". http://docs.angularjs.org/api/angular.module

使用innerfade的快乐示例时间(我还没有测试过,会尽快做到)。首先,您的应用程序必须声明角度模块(如果尚未声明)。 NG-应用= “MyModule的”。 http://docs.angularjs.org/api/angular.module

(make sure your controller is attached as well!)

(确保您的控制器也已连接!)

Now you can declare a directive on that module. Which is super cool.

现在您可以在该模块上声明一个指令。哪个超酷。

angular.module('myModule').directive("innerFade", function () {
   var res = {
     restrict : 'C',
     link     : function (scope, element, attrs) {
           scope.$watch(attrs.innerFade, function(){             
               element.innerfade({
                  speed: 'slow',
                  timeout: 1000,
                  type: 'sequence',
                  containerheight: '1.5em'
               });
           });
        }
     };
  return res;
});

The way this works is pretty simple. The $watch function will monitor the part of scope containing your data. When that changes (including initialization), it will fire the innerfade jQuery function on the element with the directive. We are also passing 'C' to the restrict argument so this custom directive will be a class only directive (I noticed you seem to like that).

这种方式非常简单。 $ watch函数将监视包含数据的范围部分。当更改(包括初始化)时,它将使用指令触发元素上的innerfade jQuery函数。我们也将'C'传递给restrict参数,所以这个自定义指令将是一个只有类的指令(我注意到你似乎喜欢这样)。

 <ul class="inner-fade:innerData" >
      <li class="ng-repeat:fadeItem in innerData">{{fadeItem}}</li>
 </ul>

Now all you have to do is bind the data to $scope.innerData in your controller (bind it any way you like including ajax), and it will just work. You can even change the data on $scope.innerData and it will update with full jQuery glory.

现在你所要做的就是将数据绑定到控制器中的$ scope.innerData(以任何你喜欢的方式绑定它,包括ajax),它就可以了。您甚至可以更改$ scope.innerData上的数据,它将使用完整的jQuery荣耀进行更新。

#3


1  

A few thoughts
1) My guess is that there is something sequentially wrong with your main app page. Do you have jQuery include after angularjs? I assume you are using ng-repeat directive?

一些想法1)我的猜测是你的主应用页面有一些顺序错误。在angularjs之后你有jQuery包含吗?我假设您正在使用ng-repeat指令?

2) change $ to jQuery

2)将$更改为jQuery

3) place document.ready script in main page ... also consider replacing it with

3)将document.ready脚本放在主页面中......也考虑将其替换为

 window.onload=function(){} 

I am sure I can debug if you can show code for main page as well as the view.

如果你能显示主页面和视图的代码,我相信我可以调试。

#4


1  

Add a directive to #slides

向#slides添加指令

app.directive("slideDirective", function () {
     return function (scope, element, attrs) {
         // Dom
         element.slides({
             preload: true,
             preloadImage: '/content/images/theme/loading.gif',
             play: 5000,
             pause: 2500,
             hoverPause: true
         });
     }
}

#5


1  

as it was said: "The jQuery slider script should only be activated after angular has loaded the content" So you can wait before it will be loaded, and then your jQuery code will start running.

正如所说:“jQuery滑块脚本只应在angular加载内容后才能激活”所以你可以等到它加载之后,然后你的jQuery代码就会开始运行。

$(document).ready(function () {
setTimeout(function(){
      $('#slides').slides({
        preload: true,
        preloadImage: '/content/images/theme/loading.gif',
        play: 5000,
        pause: 2500,
        hoverPause: true
     });
}, 10);
});