javascript - 切换 jQuery 1.3.2 → 1.4.4 时出错

标签 javascript jquery-plugins jquery jquery-1.4

我正在使用 JavaScript 制作自定义选择/自定义下拉菜单,使用 jQuery 1.3.2 可以完美运行,但我在 1.4.4 中遇到一个错误。如果有人可以提供一些想法,我想使用它,这真的很有帮助。

Error (this.change[x].call) is not function.

// JavaScript Document

jQuery( document ).ready( function()
{
jQuery( 'select.jsDropdown' ).each( function() { var dropdown = this; setTimeout( function() { new GenericDropdown( dropdown ) }, 1 ) } );
} );

// GENERIC DROPDOWNS
GenericDropdown = function( element )
{
var _self = this;
this.element = this.element ? this.element : element;
this.field;
this.ddelement = null;
this.options = this.options ? this.options : [];
this.selectedIndex = 0;
this.width = 0;
this.position = [];
this.change = [];
this.attributes = {};
this.className = this.className ? this.className : 'jsDropdown';
this.value = null;
this.keySelected = 0;

this.eventOpen = this.eventOpen ? this.eventOpen : function(e) { _self.open(e) };
this.eventSelect = this.eventSelect ? this.eventSelect : function(e) { _self.select(e) };
this.eventKeydown = this.eventKeydown ? this.eventKeydown : function(e) { _self.keydown(e) };
this.eventClose = this.eventClose ? this.eventClose : function(e) { _self.close(e) };
this.eventCancel = this.eventCancel ? this.eventCancel : function(e) { _self.cancel(e) };

if ( this.element )
{
    // save options data
    jQuery( this.element ).find( 'option' ).each( function(i)
    {
        if ( !_self.options[i] ) _self.options[i] = [];
        _self.options[i][0] = jQuery( this ).val();
        _self.options[i][1] = jQuery( this ).text();
        _self.options[i][2] = jQuery( this ).attr( 'class' )

        if ( this.selected ) _self.selectedIndex = i;
    } );

    // get name
    var name = jQuery( this.element ).attr( 'name' );

    // save attributes
    var attributes = this.element.attributes;
    for ( var x = 0; x < attributes.length; x++ ) this.attributes[ attributes[x].nodeName ] = attributes[x].nodeValue;

    // save class names
    this.className = this.className + ' ' + this.element.className.replace( this.className, '' );

    // copy over events
    var events = jQuery.data( this.element, 'events' ) ? jQuery.data( this.element, 'events' )[ 'change' ] : null;
    if ( events ) for ( var handler in events ) this.change.push( events[handler] );

    // calculate max width
    var tmp = jQuery( '<div class="jsDropdownMenu" style="position:static"><ul><li style="display:inline; padding:0"></li></ul></div>' );
    jQuery( 'body' ).append( tmp );
    for ( var x = 0; x < this.options.length; x++ )
    {
        tmp.find( 'li' ).text( this.options[x][1] );
        if ( tmp.find( 'li' )[0].offsetWidth > this.width ) this.width = tmp.find( 'li' )[0].offsetWidth;
    }
    tmp.remove();

    // draw styled dropdown
    this.draw();

    // save reference to object in jQuery
    this.element.data( 'jDropdown', _self );

    // create hidden field with data
    this.field = jQuery( '<input type="hidden" name="' + name + '" value="' + this.options[this.selectedIndex][0] + '" />' );
    this.element.after( this.field );

    // save data into jQuery
    this.element.data( 'name', name );
    this.element.data( 'value', this.options[this.selectedIndex][0] );
    this.element.val( this.options[this.selectedIndex][0] );

    // save selected value
    this.value = this.options[this.selectedIndex][0];

    // bind window close event to replace normal selects for server data
    // jQuery( window ).bind( 'beforeunload', unload );
}
}

GenericDropdown.prototype.draw = function()
{
var self = this;

// get id if there is one
var id = ( this.element.id ) ? this.element.id : null;

var widthFactor = jQuery('#selectCatFAQ').length ? 0 : 27;

// build up dropdown
var width = ( jQuery( this.element ).css( 'width' ) != 'auto' ) ? ( parseInt( jQuery( this.element ).css( 'width' ) ) > this.width ) ? parseInt( jQuery( this.element ).css( 'width' ) ) - widthFactor : this.width + 5 : this.width + 5;

// setting max width for the dropdowns
width = width > 340 ? 340 : width;
var dropdown = jQuery( '<a href="#" class="' + this.className + '"><span>' + this.options[this.selectedIndex][1] + '</span></a>' );

// bind events
dropdown.width( width );
dropdown.bind( 'click', self.eventOpen );
dropdown.bind( 'keydown', self.eventKeydown );
spanwidth=width-17;
dropdown.find( 'span' ).css( { width:spanwidth+'px' } );
if ( id ) dropdown.attr( 'id', id );

// replace existing dropdown with styled one
var select = jQuery( this.element );
this.element = jQuery( dropdown );
select.replaceWith( this.element );
// custom width set for accordion
}


GenericDropdown.prototype.unload = function()
{
var select = jQuery( '<select></select>' ).css( { visibility:'hidden' } );

// copy back attributes
jQuery.each( this.attributes, function(key, value) { select[0].setAttribute( key, value ) } );

// add in options
jQuery.each( this.options, function() { select.append( jQuery( '<option value="' + this[0] + '">' + this[1] + '</option>' ) ) } );

// set selected option
select.find( 'option' )[ this.selectedIndex ].selected = 'selected';

// replace jsDropdown
this.element.replaceWith( select.removeClass( 'jsDropdown' ) );
this.element = select;
}

GenericDropdown.prototype.open = function(e)
{
var self = this;
if ( this.element.attr( 'disabled' ) != 'disabled' )
{
    // get position for dropdown
    var in_popup = this.element.parents( '#Popup' ).length ? true : false;
    // This line is not working with jquery 1.4 so removing border and padding paramaters
    //var jquery_offset = this.element.offset( { border:true, padding:true } );
    var jquery_offset = this.element.offset();
    this.position = [ jquery_offset.left+2, jquery_offset.top + this.element.outerHeight()-3 ];
    var width = ( this.element.innerWidth() > this.width ) ? this.element.innerWidth() : this.width;
    var top = this.position[1];
    if ( in_popup && !( jQuery.browser.msie && jQuery.browser.version < 7 ) ) top = top - jQuery( document ).scrollTop();

    // create dropdown
    this.ddelement = jQuery( '<div class="jsDropdownMenu"><div class="top-content"><ul class="content"></ul></div></div>' ).css({ width:width-6 });
    this.ddelement.css( { top:top, left:this.position[0]+0+'px' } );
    if ( in_popup && !( jQuery.browser.msie && jQuery.browser.version < 7 ) ) this.ddelement.css( { position:'fixed' } );
    if ( jQuery.browser.msie && jQuery.browser.version < 7 && in_popup ) { var dd = this.ddelement; jQuery( window ).bind( 'scroll', function() { dd.css( { top:top + jQuery( document ).scrollTop() } ) } ) };
    for ( var x = 0; x < this.options.length; x++ )
    {
        var item = jQuery( '<li><span>' + this.options[x][1] + '</span></li>' );

        if ( x == this.selectedIndex ) item.addClass( 'selected' );

        if (this.options[x][2]) item.addClass( this.options[x][2] )

        item.bind( 'click', self.eventSelect );
        item.bind( 'mouseover', function(e)
        {
            self.ddelement.find( 'li.selected' ).removeClass( 'selected' );
            jQuery( this ).addClass( 'selected' );

            self.keySelected = self.ddelement.find( 'li' ).index( this );
        } );

        this.ddelement.find( 'ul.content' ).append( item );
    }

    // append dropdown to container
    jQuery( 'body' ).append( this.ddelement );

    // remove open event and add cancel event
    this.element.unbind( 'click', self.eventOpen );
    this.element.bind( 'click', self.eventCancel );

    // add close event
    setTimeout( function() { jQuery( 'body' ).bind( 'click', self.eventClose ) }, 1);

    //jQuery('.jsDropdownMenu .first span').append(this.options[this.selectedIndex][1])

}

//  e.stopPropagation();
e.preventDefault();
}

GenericDropdown.prototype.keydown = function(e)
{
if ( e.keyCode == 32 ) // space
{
    if ( !this.ddelement )
    {
        this.keySelected = this.selectedIndex;

        this.open(e);
    }
    else
    {
        this.ddelement.find( 'li.selected' ).click();

        e.preventDefault();
    }
}
else if ( e.keyCode == 40 ) // down
{
    if ( ++this.keySelected > this.options.length - 1 ) this.keySelected = 0;

    if ( this.ddelement )
    {
        this.ddelement.find( 'li.selected' ).removeClass( 'selected' );
        this.ddelement.find( 'li:eq(' + this.keySelected + ')' ).addClass( 'selected' );
    }
    else
    {
        this.selectedIndex = this.keySelected;

        // set text dropdown
        this.element.find( 'span' ).text( this.options[this.selectedIndex][1] );

        // save value in jQuery
        this.element.data( 'value', this.options[this.selectedIndex][0] );

        // save selected value
        this.value = this.options[this.selectedIndex][0];
        this.element.val( this.options[this.selectedIndex][0] );
        this.field.val( this.options[this.selectedIndex][0] );

        // perform custom event listeners if they exist
        e.target = this.element[0];
        if ( this.change.length ) for ( var x = 0; x < this.change.length; x++ ) this.change[x].call( this, e);
    }

    e.preventDefault();
}
else if ( e.keyCode == 38 ) // up
{
    if ( --this.keySelected < 0 ) this.keySelected = this.options.length - 1;

    if ( this.ddelement )
    {
        this.ddelement.find( 'li.selected' ).removeClass( 'selected' );
        this.ddelement.find( 'li:eq(' + this.keySelected + ')' ).addClass( 'selected' );
    }
    else
    {
        this.selectedIndex = this.keySelected;

        // set text dropdown
        this.element.find( 'span' ).text( this.options[this.selectedIndex][1] );

        // save value in jQuery
        this.element.data( 'value', this.options[this.selectedIndex][0] );

        // save selected value
        this.value = this.options[this.selectedIndex][0];
        this.element.val( this.options[this.selectedIndex][0] );
        this.field.val( this.options[this.selectedIndex][0] );

        // perform custom event listeners if they exist
        e.target = this.element[0];
        if ( this.change.length ) for ( var x = 0; x < this.change.length; x++ ) this.change[x].call( this, e);
    }

    e.preventDefault();
}
else if ( e.keyCode == 13 ) // return
{
    this.ddelement.find( 'li:eq(' + this.keySelected + ')' ).click();

    e.preventDefault();
}
else if ( e.keyCode == 9 && this.ddelement ) // tab
{
    this.ddelement.find( 'li:eq(' + this.keySelected + ')' ).click();
}
}

GenericDropdown.prototype.select = function(e)
{
// get index of selected item
var new_selection = -1;
var target_li = e.target;
if ( target_li.nodeName != 'LI' ) target_li = jQuery( target_li ).parents( 'li' )[0];
var list_items = this.ddelement.find( 'li' );
for ( var x = 0; x < list_items.length; x++ ) if ( list_items[x] == target_li ) { new_selection = x; break }
if ( new_selection != this.selectedIndex )
{
    this.selectedIndex = new_selection;
        // set text dropdown
        this.element.find( 'span' ).html( this.options[this.selectedIndex][1] );

        // save value in jQuery
        this.element.data( 'value', this.options[this.selectedIndex][0] );

        // save selected value
        this.value = this.options[this.selectedIndex][0];
        this.element.val( this.options[this.selectedIndex][0] );
        this.field.val( this.options[this.selectedIndex][0] );

        // perform custom event listeners if they exist
        e.target = this.element[0];
        if ( this.change.length ); for ( var x = 0; x < this.change.length; x++ ) this.change[x].call(this, e);
}

this.eventClose(e);

e.stopPropagation();
e.preventDefault();
 }

GenericDropdown.prototype.close = function(e)
{
var self = this;

this.ddelement.remove();
delete this.ddelement;

// remove close event
jQuery( 'body' ).unbind( 'click', self.eventClose );

// add open event and remove cancel event
setTimeout( function() { self.element.bind( 'click', self.eventOpen ) }, 1 );
this.element.unbind( 'click', self.eventCancel );

if (e) e.preventDefault();
}

GenericDropdown.prototype.cancel = function(e)
{
this.eventClose(e);

e.stopPropagation();
}

GenericDropdown.prototype.reset = function( dropdown )
{
var select = jQuery( '<select></select>' );

// copy back attributes
jQuery.each( this.attributes, function(key, value) { select[0].setAttribute( key, value ) } );
if ( dropdown.id ) select[0].id = dropdown.id;

// add in options
jQuery.each( this.options, function() { select.append( jQuery( '<option value="' + this[0] + '">' + this[1] + '</option>' ) ) } );

// set selected option
select.find( 'option' )[ this.selectedIndex ].selected = 'selected';

// replace jsDropdown
jQuery( dropdown ).replaceWith( select.removeClass( 'jsDropdown' ) );

// remove adjacent hidden field
select.next( 'input[type=hidden]' ).remove();

return select[0];
}

最佳答案

函数本身现在存储在 .handler 属性中,因此您需要更改它:

if ( events ) for ( var handler in events ) this.change.push( events[handler] );

对此:

if ( events ) for ( var handler in events ) this.change.push( events[handler].handler );

You can see the working version here .

关于javascript - 切换 jQuery 1.3.2 → 1.4.4 时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4350382/

相关文章:

javascript - 未捕获的类型错误 : Cannot read property 'appendChild' of undefined after Ajax call

javascript - jQuery AJAX 请求返回原始 PHP,而不是运行 PHP 的结果

php - 如果我的选项卡内容在各处都相同,为什么我的 JQuery 脚本似乎只在开始浏览我的选项卡之前才起作用?

javascript - 转换 12 小时 hh :mm AM/PM to 24-hour hh:mm

javascript - 在 javascript 中解析 xml 服务的最佳方法?

javascript - 我应该如何调整类型化数组的大小?

JavaScript:如何将多个参数传递给对象成员内的回调函数?

javascript - 接下来如何修复错误不是 Angular 中的函数

javascript - 有没有办法从 datamodel.prisma 文件生成 schema.graphql 文件?

javascript - jstree jquery plugin - 获取父节点的所有子节点和子节点