使用AngularJS和jQuery修改DOM(slideDown / slideUp)

20
我正在尝试使用AngularJS实现slideDown/slideUp动画。不幸的是,我不能使用CSS3的过渡效果,因为高度设置为auto(我不想使用max-height解决方法),所以我尝试使用jQuery的slideToggle方法。
给定以下标记:
<ul>
    <li ng-repeat="entry in data">
        <span>{{entry.title}}</span>
        <a ng-click="clicked($event)" href>more?</a>
        <p>{{entry.description}}</p>
    </li>
</ul>

我在我的控制器中实现了以下方法:

$scope.clicked = function($event) {
    var a = jQuery($event.target);
    var p = a.next();
    p.slideToggle();
};

小提琴

即使它看起来按预期工作,我明白修改DOM应该仅在指令内完成。

阅读了AngularJS的文档(我认为有点简略),指令对我来说仍然有点模糊,所以有人能告诉我以下指令是否符合AngularJS最佳实践吗?

.directive('testDirective', [
function() {
    return {
        restrict: 'A',
        scope: {
            entry: '=testDirective'
        },
        template: '<span>{{entry.title}}</span> ' +
                  '<a ng-click="clicked($event)" href>more?</a>' +
                  '<p>{{entry.description}}</p>',
        link: function(scope, element) {
            var p = jQuery(element.find('p'));
            scope.clicked = function($event) {
                p.slideToggle();
            };
        }
    };
}])

小提琴

这个能否改进?我可以在指令中使用jQuery吗?它是否尊重关注点分离

2个回答

42

或者,您可以使用AngularJS的$animate

.animation('.slide', function() {
    var NG_HIDE_CLASS = 'ng-hide';
    return {
        beforeAddClass: function(element, className, done) {
            if(className === NG_HIDE_CLASS) {
                element.slideUp(done); 
            }
        },
        removeClass: function(element, className, done) {
            if(className === NG_HIDE_CLASS) {
                element.hide().slideDown(done);
            }
        }
    }
});

使用ng-hideng-show来显示或隐藏描述。

    <li ng-repeat="entry in data">
        <span>{{entry.title}}</span>
        <a ng-click="expand = !expand" href="#">more?</a>
        <p class="slide" ng-show="expand">{{entry.description}}</p>
    </li>

请查看JSFiddle

附注:您必须包括jqueryangular-animate.js


1
有趣,谢谢!这里可能是另一个解决方案,你觉得怎么样? - sp00m
这也很好。使用ng-show只是个人喜好的问题。 - LostInComputer
1
太棒了,我通过jsFiddle让它工作了。在展开当前类之前,如何关闭(slideUp())所有其他类(以保持所有结果紧凑)?我已经尝试在不同的位置使用jQuery(className).slideUp(done),但没有成功。而且仅使用纯jQuery($('.slide').slideUp();)似乎会破坏一些东西:( - Robert Johnstone
1
非常好的答案,谢谢。如果有人需要默认情况下扩展某些内容:JSFiddle - szymonm
@LostInComputer - 这真是太棒了。但我只需要一个帮助。我将其实施到我的项目中。出现的情况是,当我点击按钮时,所有项会同时折叠。而在jQuery中,我们使用 .closest() 查找容器中最近的元素进行切换。但在Angular中该怎么做呢? - Unknown User
显示剩余8条评论

8
我想展示一个使用ng-if的例子,因为我花了几个小时寻找解决方案,发现有多种完全不同的方法只适用于ng-show。如果需要指令在可见时才初始化,可以使用ng-if而不是ng-show
要在ng-if中使用jQuery slideDown / slideUp,您还可以使用ngAnimate,但使用不同的钩子:enterleave
app.animation('.ng-slide-down', function() {
  return {
    enter: function(element, done) {
      element.hide().slideDown()
      return function(cancelled) {};
    },
    leave: function(element, done) { 
      element.slideUp();
    },
  };
});

<div class="ng-slide-down" ng-if="isVisible">
     I will slide down upon entering the DOM.
</div>

即使尝试了各种基于JS和CSS的方法,这个任务仍然出乎意料地困难。最终,jQuery的动画效果在某些情况下是必要且有效的。


不错的解决方案,对我有用,谢谢;你打算用 return function(cancelled) {}; 做什么? - marebine
@marebine 这是一个如果动画在中途被取消时要执行的行为存根。我不确定具体细节,但应该在文档中有说明。 - Yuji 'Tomita' Tomita

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接