【问题标题】:Backbone.js hover event not triggeringBackbone.js 悬停事件未触发
【发布时间】:2012-01-19 13:32:37
【问题描述】:

我是第一次尝试使用 Backbone.js,但遇到了一些麻烦。我不知道我的问题是我不了解骨干应该如何工作,还是只是代码问题。

我正在尝试创建一个动态菜单,使用它的项目创建主菜单栏没有问题,但是当我悬停其中一个菜单项时,我无法触发悬停事件。

观看次数

var MenuView = Backbone.View.extend({
    initialize: function(items) {
        this.menu = items;
        //Main navigation bar
        this.el = $("#main-nav");
        this.trigger('start');
        this.render();
    },
    render: function() {
        var me = this;
        _.each(this.menu, function(mi) {
            mi.render(me.el);
        });
        return this;
    },
    handleHover: function(e) {
        console.debug(e);
    }
});

var MenuItemView = Backbone.View.extend({
    tagName: 'li',
    className:'menu-item',
    events: { //none of these work
        'hover a':'handleHover',
        'mouseover a':'handleHover',
        'mouseover':'handleHover',
        'click': 'handleHover',
        'click a': 'handleHover'
    },
    initialize: function(mi) {
        this.menuItem = mi;
        this.el = $("<li class=\"menu-item\"></li>")
    }, 
    render: function(parent) {
        this.el.append('<a href="' + this.menuItem.get("link") + '">' + this.menuItem.get("text") + '</a>');
        parent.append(this.el);
        return this;
    },

    handleHover: function(ev) {
        console.debug("Hovering! " + ev + this.menuItem.get("cid"));
        console.debug(ev);
        return false;
    }
});

型号

var MenuItem = Backbone.Model.extend({
    defaults: {
        parent: null,
        children: [],
        link: "",
        text: ""
    }   
});

启动代码

$(document).ready(function() {
    var menu = new MenuView([
        new MenuItemView( new MenuItem({link: "/", text: "Home"})),
        new MenuItemView( new MenuItem({link: "/", text: "Users"})),
        new MenuItemView( new MenuItem({link: "/", text: "Configuration"}))
    ]);
});

任何帮助将不胜感激!

谢谢!

更新

好的,在 MenuItemView 视图的 initialize 方法之外定义 el 之后,它可以工作,但是相同的元素会在视图的所有实例上重用,所以我不得不将视图更改为以下代码以使其按我想要的方式工作:

 var MenuItemView = Backbone.View.extend({

    events: { //none of these work
        'hover a':'handleHover',
        'mouseover a':'handleHover',
        'mouseover':'handleHover',
        'click': 'handleHover',
        'click a': 'handleHover'
    },
    el: $('<li class="menu-item"></li>'),
    initialize: function(mi) {
        this.menuItem = mi;
        this.el = $(this.el).clone(true);
    }, 
    render: function(parent) {
        this.el.append('<a href="' + this.menuItem.get("link") + '">' + this.menuItem.get("text") + '</a>');
        parent.append(this.el);
        return this;
    },

    handleHover: function(ev) {
        console.debug("Hovering! " + ev + this.menuItem.get("cid"));
        console.debug(ev);
        return false;
    }
});

我是否必须在新实例上克隆元素?

【问题讨论】:

  • 你为什么要克隆你的el?考虑一下何时评估 $('&lt;li class="menu-item"&gt;&lt;/li&gt;'),您就会得到答案。
  • 如果我在initialize方法上为el创建元素,那么事件没有被触发,我该如何解决呢?

标签: javascript jquery backbone.js


【解决方案1】:

hover 不是正常的事件,而是 jquery 提供的“方便”事件。它是 mouseenter 和 mouseleave 的组合。

绑定到 mouseenter 和 mouseleave 而不是 hover 将满足您的需求。

【讨论】:

    【解决方案2】:

    回复:“为什么我必须在新实例上克隆元素?”

    根本问题就在这里:

    var MenuItemView = Backbone.View.extend({
        // ...
        el: $('<li class="menu-item"></li>'),
    

    $('&lt;li class="menu-item"&gt;&lt;/li&gt;') 调用是在定义 MenuItemView 时执行的,因此您最终只会在 MenuItemView 的所有实例之间共享一个 $('&lt;li&gt;')

    如果您在initializerender 中创建el,那么您必须使用delegateEvents 手动绑定事件:

    默认情况下,delegateEvents 会在视图的构造函数中为您调用 [...]

    因此,如果您自己创建this.el,那么您必须自己调用this.delegateEvents()。例如:

    var MenuItemView = Backbone.View.extend({
        // ...
        render: function() {
            this.el = $('<li class="menu-item"><a>' + this.cid + '</a></li>');
            this.delegateEvents();
            return this;
        },
        //...
    });
    

    演示:http://jsfiddle.net/ambiguous/RPqMh/2/

    但是,如果你 clone 你的 this.el 带有 withDataAndEvents 标志,那么你应该没问题:

    var MenuItemView = Backbone.View.extend({
        el: $('<li class="menu-item"></li>'),
        // ...
        initialize: function() {
            this.el = this.el.clone(true);
            this.el.append('<a>' + this.cid + '</a>');
        }, 
        //...
    });
    

    演示:http://jsfiddle.net/ambiguous/hCW3F/1/

    但如果你只是this.el.clone(),它不会起作用,因为delegate 不会绑定到克隆:

    var MenuItemView = Backbone.View.extend({
        el: $('<li class="menu-item"></li>'),
        // ...
        initialize: function() {
            this.el = this.el.clone();
            this.el.append('<a>' + this.cid + '</a>');
        }, 
        // ...
    });
    

    演示:http://jsfiddle.net/ambiguous/KZNPA/

    但是,如果您添加自己的 delegateEvents 电话,就可以了:

    var MenuItemView = Backbone.View.extend({
        el: $('<li class="menu-item"></li>'),
        // ...
        initialize: function() {
            this.el = this.el.clone();
            this.el.append('<a>' + this.cid + '</a>');
        },
        render: function() {
            this.delegateEvents();
            return this;
        },
        // ...
    });
    

    演示:http://jsfiddle.net/ambiguous/KZNPA/1/

    【讨论】:

    • 非常感谢您的解释!它为我清除了整个事情:)
    • @Deleteman:我必须先确保自己头脑清楚,所以我分享了我的笔记:)
    【解决方案3】:

    在我看来你不需要这个属性:

    tagName: 'li',
    className:'menu-item'
    

    如果您指定this.el = $('&lt;li class="menu-item"&gt;&lt;/li&gt;'),则在 MenuItemView 中;

    【讨论】:

    • 是的,该代码是在测试期间添加的,只是为了检查这是否能解决我的问题,但它没有......
    • 是的,我也查过了。没修。无论如何,而不是tagNameclassName 直接定义el: $('&lt;li class="menu-item"&gt;&lt;/li&gt;'),它应该可以工作。
    • 是的,在initialize 方法之外定义el 是可行的(有点),但是相同的元素会在视图的每个实例上重用。我会写一个更新给你看......
    • 嗯,这很有趣..我看到了问题。现在我只能说像var menu = new MenuItemView({el: $("&lt;li class='menu-item'&gt;&lt;/li&gt;")}); 这样创建实例似乎可以按预期工作。
    • 顺便说一句,你最好只使用tagName: 'li', className: 'menu-item'。它也有效。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-16
    • 2014-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-02
    相关资源
    最近更新 更多