7

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

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

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

回顾一下,在refresh 方法中创建的元素,在_create 方法期间调用绑定没问题。_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;
};
4

1 回答 1

14

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

例如,如果您尝试绑定对给定类 '.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>');
于 2013-04-28T00:24:26.550 回答