【问题标题】:Prevent hover on an element when scrolling event happened发生滚动事件时防止悬停在元素上
【发布时间】:2015-01-07 22:10:26
【问题描述】:

我使用主干/牵线木偶构建了一个下拉小部件,可让您使用键盘在下拉列表中上下导航。我需要区分选定和突出显示,因此我将布尔值存储在列表项模型的 isSelected 和 isHighlighted 中。每当项目悬停时,isHighlighted 就会更改为 true。

这是我的问题,我已将下拉列表设置为具有 maxItem,因此当下拉列表中的项目太多时,我会显示一个滚动条,以便人们可以滚动以查看更多列表项目。当我使用键盘导航来导航通过该 maxItem 限制时,我会调用 animate 并 scrollTop 一定距离,以便突出显示的内容保持在视图中。问题是如果我碰巧在下拉列表中有鼠标并且发生了这种滚动,它将在鼠标指针所在的项目上触发 mouseenter 事件。然后它将悬停元素的 isHighlighted 更改为 true。这意味着突出显示的项目又回到了,当我再次使用键盘向下导航时,它将从顶部向下而不是从之前的位置继续。

当滚动事件触发时,我是否可以阻止 mouseenter 事件?

尝试包含所有相关代码,希望这会有所帮助:

onKeyUp: function (event) {
    var key = event.which;

    switch (key) {
        case 38: // UP
            this.onUpArrow();
            break;
        case 40: // DOWN
            this.onDownArrow();
            break;
        default:
            // default method
    }
},
onDownArrow: function () {
    if (!this.isDropdownOpen()) {
        this.openDropdown();
    } else {
        this.dropdown.highlightNext();
        this.dropdown.scroll();
    }
},

在另一个文件中,我有

events: {
    'mouseenter': 'onMouseEnter'
},
onMouseEnter: function (event) {
    this.triggerMethod('dropdown:option:mouseenter', {
        event: event,
        view: this,
        model: this.model
    });
},

在另一个文件中,我有

onDropdownOptionMouseenter: function () {
    var data = _.last(arguments),
        event = data.event,
        view = data.view;
    view.highlight();
}

此时,滚动发生了,并且 mouseenter 触发器被触发并且突出显示发生了变化。我只是不知道在哪里可以添加代码以防止浏览器识别 mouseenter。我想为此添加自定义事件吗? imo 工作量很大,必须有一个更简单的解决方案。

【问题讨论】:

  • 我之前遇到过这个问题。发布您的代码,以便我指导您找到解决方案。
  • @Seebiscuit 添加了相关的代码,希望这就足够了。谢谢。
  • 是的,因为您正在浏览视图,所以您必须使用消息系统(事件聚合器)或全局变量(不要这样做,代码很臭)。要我给你看一个样品吗?
  • 是的,那太好了。

标签: javascript events backbone.js marionette


【解决方案1】:

设置事件聚合器

在 Backbone 中创建事件聚合器很简单,只需 extend 事件对象,

window.vent = _.extend({}, Backbone.Events);

我们将事件聚合器vent 附加到全局范围,以便任何人都可以监听。

如果您使用 Marionette,您可以使用内置 Marionette 消息系统 Backbone.Wreqr 中的内置聚合器(注意: Wreqr 将使用新的消息 API ,Radio,从 Marionette v.3 开始,但我有一个很好的来源,更新管理器应该将所有 Wreqr 实例迁移到 Radio)。

创建一个事件聚合器是一个调用的问题,

window.vent = new Backbone.Wreqr.EventAggregator();

现在,为了解决您的问题,我们将使用事件聚合器来设置一个 pubsub 系统,您的项目视图将订阅一个事件,以帮助他们正确地对滚动做出反应。管理滚动的视图将发布此事件。

注意: Backbone.Wreqr 也可以配备使用 Channels 如果您想创建独立的消息传递管道。查看docs

订阅

让我们设置订阅。在项目的视图中做

initialize: function ()  {
  this.listenTo(vent, "dropdown:before:scroll", function() {
    this.isScrolling = true;
  }
  this.listenTo(vent, "dropdown:end:scroll", function() {
    this.isScrolling = false;
  }
}

发布

我们刚刚订阅的事件将在scrollTop 调用之前和之后通过触发vent 上的事件来发布。所以你会像这样重写 maxlimit 检查器,

if (currItem > maxItem) {
  vent.trigger("dropdown:before:scroll");
  someElement.scrollTop();
  vent.trigger("dropdown:end:scroll");
}

监听这些事件的项目会知道您正在滚动,因为触发事件是同步的,并且会以正确的顺序触发。

防止突出显示

最后,既然您正在发布 scrollTop 事件并且您的项目正在监听它,您要确保遇到 mouseenter 的项目知道何时突出显示。

onMouseEnter: function (event) {
  if (!this.isScrolling) {
    this.triggerMethod('dropdown:option:mouseenter', {
        event: event,
        view: this,
        model: this.model
    });
  }
},

【讨论】:

  • 很高兴能帮上忙!如果您有任何问题,请发表评论。
  • 是的,我实际上对此有疑问。我对 Marionette.Wreqr 不太熟悉,所以这基本上是一个全球事件聚合器,对吧?如果我的组件有多个实例,Wreqr 会为每个实例创建一个单独的全局通道吗?我怎么知道哪个事件是针对哪个实例的?
  • 是的,除非您使用Channels(请参阅答案上的链接),否则您的所有事件都将被这个全球聚合器“收集”。因此,任何监听“this:event”的人都会调用其关联的回调。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-05-16
  • 2011-02-28
  • 2011-09-15
  • 1970-01-01
  • 2015-03-18
  • 2012-05-09
相关资源
最近更新 更多