使用this._on()在jQuery UI Widget Factory中实时绑定事件

时间:2013-04-27 22:56:42

标签: jquery jquery-ui jquery-ui-widget-factory

我目前正在开发一个级联树状菜单。展开树项目时,会在其下方创建新的<div>,也可以展开。我可以得到第一组<div>来绑定并因此扩展,但我似乎无法使用“this._on”方法自动绑定新创建的div。我正在寻找类似于live(),delegate()和on()的功能。

我已在http://jsfiddle.net/vEAhq/的jsFiddle中发布了我的代码。

我在第60行的_setupEvents方法下设置了事件绑定。

回顾一下,在_create方法中调用的refresh方法中创建的元素绑定没问题。它是_expand方法中创建的元素,不像我期望的那样受到约束。

提前感谢您的时间。

$.widget( "custom.categoryMenu", {

    options: {
        links: null
    },

    _create: function() {
        this.refresh();
        this._on('.categoryNavigationExpandIcon', {
            click: function(event) {
                var $container = $(event.target).parent();
                if( ($container).data('expanded') === false ) {
                    this._expand($container);
                } else {
                    this._contract($container);
                }
            }
        });
    },

    refresh: function() {
        var $elm = this.element;
        var $newElem;
        var $itemTree = this.options.links;
        var $itemTreeRoot = sortObj( $itemTree['1'], 'function', true );

        this._setupEvents();

        $.each( $itemTreeRoot, function( key, value ) {
            var ID = $itemTreeRoot[key];
            var label = key;
            $newElem = $( '<div style="padding:8px 0;"></div>' )
                .data( 'expanded', false )
                .data( 'id', ID )
                .data( 'level', 1 )
                .addClass( 'categoryNavigationLevel1' );
            $( '<div class="categoryNavigationExpandIcon"></div>' ).appendTo($newElem);
            $( '<a href="index.cfm?action=products&cat=' + ID + '" rel="?cat=' + ID + '" class="categoryMenuLabel">' + label + '</a>' ).appendTo($newElem);
            // Add triangle icons if there are children
            if ($itemTree[ID]) {
                $($newElem)
                    .find('.categoryNavigationExpandIcon')
                    .addClass('ui-icon')
                    .addClass('ui-icon-triangle-1-e');
            }
            $elm.append($newElem);
        });
    },

    _setupEvents: function() {
        var events = {
            click: function( event ) {
                event.preventDefault();
            }
        };

        this._on('.categoryNavigationExpandIcon', {
            click: function(event) {
                var $container = $(event.target).parent();
                if( ($container).data('expanded') === false ) {
                    this._expand($container);
                } else {
                    this._contract($container);
                }
            }
        });
    },

    _expand: function(container) {
        var $elm = this.element;
        var $itemTree = this.options.links;
        var containerLevel = $(container).data('level');
        var containerID = $(container).data('id');
        var newContainerLevel = containerLevel + 1;

        var $itemTreeBranch = sortObj( $itemTree[containerID], 'function', true );

        $(container)
            .data('expanded', true)
            .find('.ui-icon-triangle-1-e')
            .removeClass('ui-icon-triangle-1-e')
            .addClass('ui-icon-triangle-1-se');

        $.each( $itemTreeBranch, function( key, value ) {
            var ID = $itemTreeBranch[key];
            label = key;
            $newElem = $( '<div style="padding:8px 0;"></div>' )
                .data('expanded', false)
                .data( 'id', ID )
                .data( 'level', newContainerLevel )
                .addClass( 'categoryNavigationLevel' + newContainerLevel );
            $( '<div class="categoryNavigationExpandIcon"></div>' ).appendTo($newElem);
            $( '<a href="index.cfm?action=products&cat=' + ID + '" rel="?cat=' + ID + '" class="categoryMenuLabel">' + label + '</a>' ).appendTo($newElem);
            // Add triangle icons if there are children
            if ($itemTree[ID]) {
                $($newElem)
                    .find('.categoryNavigationExpandIcon')
                    .addClass('ui-icon')
                    .addClass('ui-icon-triangle-1-e');
            }
            $(container).after($newElem);
        });
    },

    _contract: function(container) {
        var containerLevel = $(container).data('level');
        $(container)
            .data( 'expanded', false )
            .find('.ui-icon-triangle-1-se')
            .removeClass('ui-icon-triangle-1-se')
            .addClass('ui-icon-triangle-1-e');

        $(container)
            .nextUntil( '.categoryNavigationLevel' + containerLevel )
            .remove();
    },

    destroy: function() {
        $.widget.prototype.destroy.call(this);
    }

});

/**
* Name: Sort Javascript Object
* Credit: Arne Martin Aurlien
* URL: http://am.aurlien.net/post/1221493460/sorting-javascript-objects
*/
sortObj = function(obj, type, caseSensitive) {
    var temp_array = [];
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            if (!caseSensitive) {
                key = (key['toLowerCase'] ? key.toLowerCase() : key);
            }
            temp_array.push(key);
        }
    }
    if (typeof type === 'function') {
        temp_array.sort(type);
    } else if (type === 'value') {
        temp_array.sort(function(a,b) {
            var x = obj[a];
            var y = obj[b];
            if (!caseSensitive) {
                x = (x['toLowerCase'] ? x.toLowerCase() : x);
                y = (y['toLowerCase'] ? y.toLowerCase() : y);
            }
            return ((x < y) ? -1 : ((x > y) ? 1 : 0));
        });
    } else {
        temp_array.sort();
    }

    var temp_obj = {};
    for (var i=0; i<temp_array.length; i++) {
        temp_obj[temp_array[i]] = obj[temp_array[i]];
    }

    return temp_obj;
};

1 个答案:

答案 0 :(得分:13)

当您必须附加一些新创建的内容时,最好绑定文档上的事件,给定选择器或自定义事件。

例如,如果您尝试绑定给定类'.your-class'的点击:

$('.your-class').on('click', function (e) {
    // ...
})

您希望将其替换为:

$(document).on('click', '.your-class', function (e) {
    // ...
})

jQuery UI完全相同:

您更愿意替换:

// Here you just bind a click on the existing elements of your class
this._on('.categoryNavigationExpandIcon', {
    click: function(event) {
        var $container = $(event.target).parent();
        if( ($container).data('expanded') === false ) {
            this._expand($container);
        } else {
            this._contract($container);
        }
    }
});

人:

// Bind a custom event on the document in order to delegate this event event to the new created classes
this._on(this.document, {
    'click.categoryNavigationExpandIcon': function(event) {
        var $container = $(event.target).parent();
        if( ($container).data('expanded') === false ) {
            this._expand($container);
        } else {
            this._contract($container);
        }
    }
});

您可以在此处找到更新的JSFiddle: http://jsfiddle.net/vEAhq/7/

顺便说一下,在使用jQuery创建元素时可以跳过结束标记。

$('<div>'); // instead of $('<div></div>');