Backbone.js中的Keypress是什么?

9
似乎按键只能在焦点元素上执行?我不完全同意这一点,必须有一种类似于单击事件的方法来执行按键事件吧?
我有一个视图,一次只能处理一个项目。我有一个mouseenter-mouseleave函数,它会向鼠标所在的项目添加一个类。当该项目接收到该类时,我希望能够使用按键事件在该项目上运行一个函数。
显然,这是一个小障碍,但我想找出需要做什么。下面是一个示例视图。
var PlayerView = Backbone.View.extend({
    tagName: 'div',

    events: {
        'click .points, .assists, span.rebounds, span.steals':'addStat',
        'mouseenter': 'enter',
        'mouseleave': 'leave',
        'keypress': 'keyAction'
    },

    enter: function() {
        this.$el.addClass('hover');
    },

    leave: function() {
        this.$el.removeClass('hover');
    },

    keyAction: function(e) {
        var code = e.keyCode || e.which;
        if(code == 65) { 
            alert('add assist')
        }
    }
});

这里没有太多的逻辑,但我想写出类似这样的东西。

    keyAction: function(e) {
        var code = e.keyCode || e.which;
        if(code == 65) { 
            var addAssist = parseInt(this.model.get('assists')) + 1;        
            this.model.save({assists: addAssist});
        }
    }

基本上,如果我能弄清楚如何触发keyAction方法,那么我就可以继续进行了。那么,在执行此类代码时,我错过了哪些注意事项呢?我确信有一些。
我理解这段代码中的一些问题,它无法知道我们何时在该视图中运行keypress,我必须添加一个条件或其他内容来查找活动类,因此当我执行keypress时,它知道我正在谈论哪个模型,这里描述得非常模糊,但我知道有些地方不对,只是不确定如何解决? 我的解决方案:
initialize: function() {
    this.listenTo(this.model, "change", this.render);
    _.bindAll(this, 'on_keypress');
    $(document).bind('keydown', this.on_keypress);
},

enter: function(e) {
    this.$el.addClass('hover');
},

leave: function(e) {
    this.$el.removeClass('hover');
},

on_keypress: function(e) {
    // A for assist
    if(e.keyCode == 65) { 
        if(this.$el.hasClass('hover')) {
            var addThis = parseInt(this.model.get('assists')) + 1;        
            this.model.save({assists: addThis});
        }
    }
    // R for rebound
    if(e.keyCode == 82) { 
        if(this.$el.hasClass('hover')) {
            var addThis = parseInt(this.model.get('rebounds')) + 1;        
            this.model.save({rebounds: addThis});
        }
    }
    // S for steal
    if(e.keyCode == 83) { 
        if(this.$el.hasClass('hover')) {
            var addThis = parseInt(this.model.get('steals')) + 1;        
            this.model.save({steals: addThis});
        }
    }
    // 1 for one point
    if(e.keyCode == 49) { 
        if(this.$el.hasClass('hover')) {
            var addMake = parseInt(this.model.get('made_one')) + 1;        
            this.model.save({made_one: addMake});

            var addOne = parseInt(this.model.get('points')) + 1; 
            this.model.save({points: addOne});
        }
    }
    // 2 for two points
    if(e.keyCode == 50) { 
        if(this.$el.hasClass('hover')) {
            var addMake = parseInt(this.model.get('made_two')) + 1;        
            this.model.save({made_two: addMake});

            var addTwo = parseInt(this.model.get('points')) + 2; 
            this.model.save({points: addTwo});
        }
    }
    // 2 for two points
    if(e.keyCode == 51) { 
        if(this.$el.hasClass('hover')) {
            var addMake = parseInt(this.model.get('made_three')) + 1;        
            this.model.save({made_three: addMake});

            var addThree = parseInt(this.model.get('points')) + 3; 
            this.model.save({points: addThree});
        }
    }
}

这对我的应用程序非常有用,因为当用户将光标悬停在项目上时,用户可以按键添加数据,而无需单击。


可能是重复的问题:如何从视图中捕获按键事件? - mekwall
我在提问之前看过那篇帖子,我同意它基本上是相同的概念,但对我来说太抽象了,也许我没有理解答案的意思,但它并不能满足我,或者真的没有多少意义吗? - Michael Joseph Aubry
1
你可以在添加类的同时加上一个简单的 .focus() 来捕获 keypress 事件。this.$el.addClass('hover').focus() 应该足以捕获 keypress。 - Shashank Mehta
1
@MichaelJosephAubry,我想象这是一个HTML篮球游戏。如果是的话,我非常喜欢这个想法,你可以通过鼠标悬停在球员上并按键来控制他们。如果你做出了这样的东西,请在完成后在评论中发布链接,这样我们就可以看到它(并标记我,这样我就知道它已经上线了)。 - RustyToms
1
谢谢,你非常接近了,这是一个统计应用程序,并且它是一个过程。我参加了一个男子联赛,并决定将我的技能付诸实践,我们已经进行到第三周了,我的目标是每周改进应用程序。我正在尝试让应用程序跟踪更多的数据,比如罚球命中/未命中、两分球和三分球。因此,通过使用热键,跟踪统计数据的人可以非常快速地添加数据。所有用户需要做的就是看谁打出了这个动作,然后将鼠标悬停在他们的名字上,然后按下相应的键。我决定采用backbone.js来完成这个项目,以便我可以专业地使用它。 - Michael Joseph Aubry
显示剩余3条评论
1个回答

15

所以你只能在设置监听器的元素(或其子元素)中监听按键事件。而且只有在元素聚焦时才会触发按键事件。因此,我认为对于你来说最好的解决方案是,在你正在悬停的元素上设置focus,然后你可以监听keypress,或者更好的办法是,监听keydown,因为它在跨浏览器方面表现得更加标准。

这里有一个演示这种技术的工作JSFiddle:http://jsfiddle.net/DfjF2/2/

仅特定的表单元素接受focus。你可以为元素添加contenteditabletabindex属性,这样就可以允许几乎任何元素接收焦点,但是keydown事件实际上不会被触发!这是一个浏览器特定的问题。根据我的经验,<span>会导致keydownkeyup事件在我测试过的每个浏览器(Chrome、Firefox、IE、Safari、Android浏览器、Silk)中都会被触发。因此,在jsfiddle中,我在目标元素内添加了一个span,将focus放在其中,并为其添加了keydown事件监听器。

因此,如果你在你的视图中添加一个空的<span>,那么你的代码可能看起来像这样:

var PlayerView = Backbone.View.extend({
    tagName: 'div',

    events: {
        'click .points, .assists, span.rebounds, span.steals':'addStat',
        'mouseenter': 'enter',
        'mouseleave': 'leave',
        'keydown': 'keyAction'
    },

    enter: function() {
        this.$el.addClass('hover');
        var span = this.$el.find('span');
        span.attr('tabindex', '1').attr('contenteditable', 'true');
        span.focus();
    },

    leave: function() {
        this.$el.removeClass('hover');
        var span = this.$el.find('span');
        span.removeAttr('contenteditable').removeAttr('tabindex');
        span.blur();
    },

    keyAction: function(e) {
        var code = e.keyCode || e.which;
        if(code == 65) { 
            alert('add assist')
        }
    }
});

2
这个SO答案会很有帮助 - 哪些HTML元素可以接收焦点? - Shashank Mehta
抱歉回复晚了,感谢您抽出时间撰写答案并提供 fiddle!我会将它标记起来,因为它确实有效。昨晚在得到这个答案之前,我已经写了一些可行的代码,在 OP 中发布它。 - Michael Joseph Aubry

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