如何在AngularJS中为悬停元素添加延迟?

12

我有一个元素:

    <span ng-mouseenter="showIt()" ng-mouseleave="hideIt()">Hover Me</span>
    <div class="outerDiv" ng-show="hovering">
        <p>Some content</p>
        <div class="innerDiv">
            <p>More Content</p>
        </div>
    </div>

这是 JavaScript 代码:

// mouseenter event
$scope.showIt = function () {
    $scope.hovering = true;
};

// mouseleave event
$scope.hideIt = function () {
    $scope.hovering = false;
};

我希望能在hover事件上设置500毫秒的延迟。

我已经有了这个问题的答案,但是我还需要等待8个小时才能发表。我会回来的!

7个回答

16

像其他人在这里已经提到的那样,我在mouseenter事件中添加了一个计时器。

// create the timer variable
var timer;

// mouseenter event
$scope.showIt = function () {
    timer = $timeout(function () {
        $scope.hovering = true;
    }, 500);
};

我遇到的问题是,当我滚动屏幕时,如果鼠标光标碰到某个项目,弹出窗口仍会在半秒后出现。我希望能够轻松滚过一个项目而不会意外触发弹出窗口。

将超时设置为变量后,我可以取消超时。我在鼠标离开事件上执行此操作,以确保用户不会意外触发弹出窗口。

// mouseleave event
$scope.hideIt = function () {
    $timeout.cancel(timer);
    $scope.hovering = false;
};

这里提供了一个jsfiddle的链接,以便任何人都可以在其中查看并操作示例代码:

jsfiddle

9
我建议使用CSS过渡和angular-animate来实现动画效果: JS
var app = angular.module('app', ['ngAnimate']);

CSS

.outerDiv.ng-hide-remove {
    -webkit-transition: 0.5s linear all; 
    transition: 0.5s linear all;
    transition-delay: 0.5s;
    opacity: 0;
}
.outerDiv.ng-hide-remove.ng-hide-remove-active {
    opacity: 1;
}

HTML

<span ng-mouseenter="hovering=true" ng-mouseleave="hovering=false">Hover Me</span>
<div class="outerDiv" ng-show="hovering">
    <p>Some content</p>
    <div class="innerDiv">
        <p>More Content</p>
    </div>
</div>

Demo Plunker


3
感谢您提出这个问题,因为这个例子帮助我更好地理解了$timeout的工作原理,比AngularJS文档更加易懂。然而,在正确的答案上稍微进行了改进,并想在此分享给大家。 您不必创建一个空的名为timer的变量。实际上,这样做会占用您本来不需要的内存。您有一个变量和两个函数来处理实际上是单个操作。 所以,我创建了一个名为“toggleHover”的单个函数,它接受一个名为“bool”的布尔参数。然后,if/else语句确定您需要运行哪个$timeout函数。

控制器中的AngularJS

$scope.hovering = false; //Sets the initial state of hover

$scope.toggleHover = function (bool) {
    if (bool === true) {
        $timeout(function () {
            $scope.hovering = !$scope.hovering;
        }, 500);
    } else {
        $timeout(function() {
            $scope.hovering = !$scope.hovering;
        }, 500);
    };
}

HTML/VIEW

<span ng-mouseenter="toggleHover(true)" ng-mouseleave="toggleHover(false)">Hover Me</span>

EXAMPLE

http://jsfiddle.net/89RTg/12/


抱歉,如果我没有理解错的话...看着你的代码,你甚至不需要布尔值,除非你想改变进入和离开的时间。但是如果你这样做,而且离开比进入更快,你需要清除进入的超时(否则它可能在你离开后触发)。这就是为什么你需要这个变量的原因。 - commonpike
2
为什么需要if else?它们不是做同样的事情吗? - Viswanath Lekshmanan

3

window.setTimeout函数在指定的延迟时间后调用一个函数或执行一段代码。

$scope.hideIt = function () {
    window.setTimeout(function() {
        $scope.hovering = false;
        $scope.$apply();
    }, 500);  // 500ms delay        
};

或者使用 Angular 的 $timeout 服务:

$scope.hideIt = function () {
    $timeout(function() {
        $scope.hovering = false;
    }, 500);  // 500ms delay        
};

1
推荐使用$timeout服务而不是setTimeout,因为它允许测试,并自动调用$scope.$apply(),而这段代码中缺少了这个。 - runTarm
1
对于我目前无法发布的答案,我使用$timeout,然后在mouseleave时取消它。[链接](http://jsfiddle.net/tgienger/89RTg/) - Tj Gienger

3
使用 $timeout
$scope.showIt = function () {
    $timeout(function(){
        $scope.hovering = true;
    }, 500);
};
不要忘记将其添加为依赖项。 如果您希望进一步操作,可以创建自己的指令,例如delayedMouseEnter,其中包含延迟并使用它。

3
我为此编写了一个简单的指令。
(function () {
    'use strict';
    angular
        .module('app')
        .directive('scHover', scHoverDirective);

    function scHoverDirective($timeout) {
        return {
            link: function(scope, element, attrs, modelCtrl) {
                    var inTimeout = false;
                    var hoverDelay = parseInt(attrs.scHoverDelay, 10) | 1000;

                    element.on('mouseover', function () {
                      inTimeout = true;
                      $timeout(function () {
                        if (inTimeout) {
                          scope.$eval(attrs.scHover);
                          inTimeout = false;
                        }
                      }, hoverDelay);
                    });

                    element.on('mouseleave', function () {
                      inTimeout = false;
                      scope.$apply(function () {
                        scope.$eval(attrs.scHoverEnd);
                      });
                    });
            }
        }
    }
})();

示例用法(sc-hover-delay是可选的):

<div sc-hover='vm.title="Hovered..."' sc-hover-end='vm.title=""' sc-hover-delay="800">Hover me!  {{ vm.title }}</div>

这里有一个plunker: http://plnkr.co/edit/iuv604Mk0ii8yklpp6yR?p=preview


2

你好。上面的回答很好。我想补充一点,如果鼠标已经离开但指令还没有被触发或者当你销毁指令时,不要忘记取消计时器。

 $timeout.cancel( timer );
 $scope.$on("$destroy",
                    function( event ) {

                        $timeout.cancel( timer );

                    }
                );

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