【问题标题】:Why does my $timeout.cancel work here, but not here?为什么我的 $timeout.cancel 在这里工作,但在这里不行?
【发布时间】:2015-07-01 15:17:22
【问题描述】:

我的 Angular 应用程序出现了一个奇怪的问题。

在边栏中,我有一些带有代码的标签来显示悬停和隐藏悬停。它要求用户在显示悬停之前坐在标签上 2 秒,如果用户在 2 秒前离开,$timeout.cancel 将连接到mouseleave 函数并杀死它。所以效果很好。

但是在另一个指令中这不会发生,我基本上/90% 有完全相同的代码,但是 $timeout.cancel 被完全忽略,所以一旦你将鼠标悬停在另一个指令中的标签上,2 秒后无论如何,悬停都会触发。

工作代码(tagsPanel 指令)

function hoverTag(tag) {
    vs.hoverTimeout = $timeout(function() {
        ApiFactory.getTagDataSilm(tag.term_id).then(function(data) {
            console.log('getTagDataSilm: ', data.data.ticker_tag);
            tag.tickers = data.data.ticker_tag.tickers;
            tag.tagsHoverDisplay = true; 
        });
    }, 2000);
}

function leaveTag(tag) {
    $timeout.cancel(vs.hoverTimeout);
    tag.tagsHoverDisplay = false;
}

工作标记

<li ng-repeat="t in tags" ng-class="{'selected': t.selected}">
    <div class="tag-container-container">
        <div class="tag-container"
             ng-class="{'width-auto': widthAuto}"
             ng-mouseleave="leaveTag(t)">
            <div class="tag"
                 ng-click="selectTag(t)"
                 ng-mouseover="hoverTag(t)"
                 ng-class="{'positive': t.direction == 'positive',
                            'negative': t.direction == 'negative',
                            ''        : t.direction == 'stagnant'}">
                            {{t.term}}
            </div>
            <tags-hover tag="t"></tags-hover>
        </div>
    </div>
</li>

不工作的代码(viewHeader 指令)

function hoverViewTag(ticker, tag) {
    console.log('hoverViewTag ', tag);
    vs.hoverViewTimeout = $timeout(function() {

        ApiFactory.getTagData(ticker, tag.term_id).then(function(data) {
            var timeSpan = TimeSpanFactory.getTimeSpan();
            var period   = createSortString(timeSpan.when);
            var singleTagArray = [];
            singleTagArray.push(data.data.ticker_tag);
            var tagDetails = TagFactory.renderDirections(singleTagArray, null, period);

            tag.tagsHoverDisplay         = true;
            tag.favorite                 = tagDetails[0].favorite;
            tag.quantity                 = tagDetails[0].quantity;
            tag.tickers                  = tagDetails[0].tickers;
            tag.tweet_percentage         = tagDetails[0].tweet_percentage;
            tag.momentum_twitter_preview = tagDetails[0].momentum_twitter_preview;
        });
    }, 2000);
}

function leaveViewTag(tag) {
    // Cancel damn it!
    $timeout.cancel(vs.hoverViewTimeout);
    tag.tagsHoverDisplay = false;
}

标记不起作用(尽管有 mouseleave 功能,但仍会触发超时)

<ul class="view-tags-ul" ng-repeat="obj in vh.viewTickerTags">
    <li ng-repeat="t in obj.tags track by $index">
        <div class="tag-container"
             ng-mouseleave="vh.leaveViewTag(t)">
            <div class="tag"
                 ng-click="vh.removeTag(obj.ticker, t)"
                 ng-mouseover="vh.hoverViewTag(obj.ticker, t)"
                 ng-class="{'positive': t.direction == 'positive',
                            'negative': t.direction == 'negative',
                            ''        : t.direction == 'stagnant'}">{{t.term}}
                <div class="close-x-sml"></div>
            </div>
            <tags-hover tag="t"></tags-hover>
        </div>
    </li>
</ul>

补充

这是tags 在 tagsPanel 范围内的样子:

这是vh.viewTickerTags 对象的样子:


.tag 的 CSS

.tag {
    text-align: left;
    border: 1px solid $gray_light;
    background: $gray_bg;

    &:hover {
        -webkit-transition : border 2000ms ease-out; 
        -moz-transition : border 2000ms ease-out;
        -o-transition : border 2000ms ease-out;
        border: 1px solid $gray4 !important;
        background: #fff !important;
    }

    &.positive,
    &.negative { border: 1px solid $gray2; }

    &.positive:after {
        position: absolute;
        top: -10px;
        right: 0;
        @include triangle(left, 10px, $green);
    }

    &.negative:after {
        position: absolute;
        right: -10px;
        bottom: 0;
        @include triangle(up, 10px, $red);
    }

    &.blue1 { @include colored-tag($blue1) }
    &.blue2 { @include colored-tag($blue2) }
    &.blue3 { @include colored-tag($blue3) }
}

li.selected {
    .tag {
        font-family: 'robotoregular';
        border: 1px solid $gray4;
    }
}

.tag 在 viewHeader 范围内的 CSS

.viewing-tags {
    margin-left: 20px;

    span {
        float: left;
        position: relative;
        top: 2px;
        font-style: Condensed;
        font-weight: 700;
        font-size: em(10);
        text-transform: uppercase;
    }

    .ticker { margin-right: 0; }

    .tags-hover-container {
        .ticker { margin-right: 5px; }
    }

    .tag { margin-right: 0; padding-right: 0px; }
    .tag { padding-bottom: 6px; }
    .tag {
        max-width: auto !important;
        width: auto !important;
        border: 1px solid $gray4 !important;
        background: none !important;
    }
}

【问题讨论】:

  • 注意,你有一个 div 在你有 mouseover 事件的 div 中,当你将鼠标悬停在这两个 div 中的任何一个上时都会触发 mouseover 事件。因此,您当然有可能有两个计时器正在运行,其中一个由于失去对 ID 的引用而无法停止。需要更多的调试来查看是否确实如此。一种快速测试是将 mouseover 替换为 mouseenter,在上述场景中只会触发一次。
  • 是的,我在一个 div 里面有一个 div 的原因是因为 tagHover 出现在容器 div 里面。用户需要能够将鼠标悬停在实际的tagHover 上,一旦它显示出来,而无需在滚动激活它的标签按钮后立即关闭它。
  • 是的,但这会导致在第一个计时器被取消之前启动第二个计时器的可能性,从而使第一个计时器无法停止。
  • 您可以通过在每个事件处理程序中添加日志语句来测试我的上述理论。如果鼠标悬停发生的次数比鼠标离开的次数多,那就是你的问题。
  • 试试我在第一条评论中提到的建议,简单地将 ng-mouseover 替换为 ng-mouseenter。

标签: javascript angularjs angularjs-directive


【解决方案1】:

在您的第二个(非工作)示例中,该 div 有子级,并且由于您使用的是 mouseover,因此每次将鼠标悬停在该 div 的子级上时,事件处理程序都会运行。

要解决此问题,只需将ng-mouseover 替换为ng-mouseenter,这与mouseover 的不同之处在于它会在您进入div 时触发,但不会在您将鼠标悬停在其中一个子上时触发。它与 mouseleave 正好相反。 mouseover 的反义词是 mouseout。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-11-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-20
    • 1970-01-01
    • 2011-03-24
    • 1970-01-01
    相关资源
    最近更新 更多