【问题标题】:JQuery UI widget - How to raise events with a wrapper elementJQuery UI 小部件 - 如何使用包装元素引发事件
【发布时间】:2012-03-02 21:46:31
【问题描述】:

我一直在开发一个扩展 ui.mouse 的 jquery 小部件。

小部件需要通过创建元素并将它们附加到 this.element 来对鼠标事件做出反应。

如果小部件应用于不能包含子元素的 HTML 元素(例如 IMG 标记),小部件会创建代理包装元素并包装 this.element。

如果我用包装元素替换 this.element,小部件触发的事件永远不会被处理,因为小部件实例上的 .bind() 调用会将处理程序应用于原始元素,而不是包装。

如果我不将 this.element 替换为 wrapper 元素,则 ui.mouse 定义的 _mouse* 事件不会被正确调用,因为它们应用于 this.element 而不是 wrapper。

是否有一种优雅的方式以某种方式返回包装器元素,以便将后续的 bind() 调用应用于它或使 ui.mouse 原型应用于 this.element 以外的元素?

非常欢迎任何其他优雅的解决方案或建议。

这是我尝试过的两种方案。

不替换 this.element

$.widget("ui.example", ui.mouse, {

    _containerElement: null,

    _create: function ()
    {
        if (this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i))
        {
            this._applyContainer();
        }else{
            this._containerElement = this.element;
        }

        // Applies mouse interaction handlers to this.element
        this._mouseInit();

    },

    _applyContainer: function () 
    {
        this.element.wrap("<span>");
        this._containerElement = this.element.parent();
        this._containerElement.css({position:'relative'});
    },


    _mouseStart: function (event) {

        // Not always called because it handles mouse interaction with
        // the IMG element rather than the wrapper element

        this._trigger("mouseevent");
    }
})

$("IMG").example().bind("examplemouseevent", function(){
    //This fires but only when the original IMG element is clicked, not the wrapper
})

替换 this.element

$.widget("ui.example", ui.mouse, {

    _create: function ()
    {
        if (this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i))
        {
            this._applyContainer();
        }

        // Applies mouse interaction handlers to this.element
        this._mouseInit();

    },

    _applyContainer: function () 
    {
        this.element.wrap("<span>");
        this.element = this.element.parent();
        this.element.css({position:'relative'});
    },

    _mouseStart: function (event) {

        // This event is never handled because it is not raised on the original element. 
        this._trigger("mouseevent");
    }
})

$("IMG").example().bind("examplemouseevent", function(){
    //This never fires because the bind is to the IMG element, not the wrapper
})

我很确定我遇到的问题是由于我理解 jquery ui.mouse 工作方式的缺陷,或者 jquery 小部件框架的限制。

用包装原始 this.element 的元素替换 this.element 是可行的,但事件不会传递给稍后绑定到小部件的处理程序。

不替换 this.element 并存储对包装器的单独引用会导致 jquery 基础 ui.mouse 的行为将事件附加到错误的元素。

代码按设计工作,我的问题是找到处理设计限制的最佳方法。

我可以看到许多解决此问题的方法。例如;在 ui.mouse 附加所需的处理程序时,对 _trigger 方法进行打孔以触发正确元素上的事件或前后交换 this.element 值。 这些以及我考虑过的任何其他方法似乎都很混乱。

我查看了本机 jquery.resizable 小部件代码,它也创建了一个包装器,但据我所知,如果它试图触发事件,它也会遇到同样的问题。

这是我第一次使用 JQuery 小部件,所以我想从 JQuery 专家那里确认我没有遗漏什么?

【问题讨论】:

  • 你在什么浏览器中测试这个?我也遇到过类似的问题,原因通常是 DOM 没有及时更新。当您尝试获取 .parent() 时, 还不存在。我知道 IE 对此非常恼火,因为它只会在脚本停止运行后更新 DOM。
  • 我在 Chrome、IE9、Firefox 中测试过。
  • 为了排除这个不可调试的错误,我建议通过创建第二个按钮链接到单独触发的事件来测试它,该事件采用该元素的父级。如果我是对的,如果在修改 DOM 和遍历新 DOM 之间有一个沉默的时刻(脚本方面),它应该可以工作。没有其他方法可以调试它,因为您不知道浏览器何时真正更新其原始 DOM。只是一个建议:-)

标签: javascript jquery jquery-ui widget


【解决方案1】:

我会尝试这样的方法:

_applyContainer: function () 
{
    this.element.wrap("<span>");
    this.element.bind("list of events", function(){
        this.element.parent().trigger("name of event");
    });
    this.element = this.element.parent();
    this.element.css({position:'relative'});
}

在构建包装器元素时,在子元素上绑定任何事件列表(如果此概念不起作用,您可以迭代)并触发父(作用域,已知)元素同名事件。 注意:“事件列表”应该类似于“鼠标悬停鼠标点击”等,然后“事件名称”应该替换为一些逻辑来检测哪些列表被触发。

【讨论】:

    【解决方案2】:

    我对此并不完全满意,但我采用的解决方案是换掉 this.element call _mouseInit 并再次换回来。

    _containerElement: null,
    
    _applyContainer: function () 
    {
        var origionalElement = this.element;
        this.element.wrap("<div>");
        this._containerElement = this.element.parent();
        this.element = this._containerElement;
        this._mouseInit();
        this.element = origionalElement;
        this._containerElement.css({position:'relative'});
    },
    

    我不漂亮,但它有效。我可能会在未来的某个时候尝试覆盖 _mouseInit,但这适合我现在的目的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-11
      • 1970-01-01
      • 2015-06-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-03
      相关资源
      最近更新 更多