一、easyUI
问题:在easyUI的下拉选框combobox组件中,默认上下选择并回车选中数值,但是当鼠标正好在数据框的一行时,用户按回车选中数据,回车确定却选中了鼠标悬停在那的数据。
原因:easyui的组件combobox中默认设置了回车选中事件。
分析:通过easyUI的官网找到combobox组件的文档,找到它combobox有可扩展的方法。
解决方案:
对combobox扩展,并重写相关调用方法,从而上下和回车选中去掉鼠标的影响。
(function(){ function getRowIndex(target, value){ var state = $.data(target, 'combobox'); return $.easyui.indexOfArray(state.data, state.options.valueField, value); } /** * do the query action */ function doQuery(target, q){ var state = $.data(target, 'combobox'); var opts = state.options; var highlightItem = $(); var qq = opts.multiple ? q.split(opts.separator) : [q]; if (opts.mode == 'remote'){ _setValues(qq); //request(target, null, {q:q}, true); } else { var panel = $(target).combo('panel'); panel.find('.combobox-item-hover').removeClass('combobox-item-hover'); panel.find('.combobox-item,.combobox-group').hide(); var data = state.data; var vv = []; $.map(qq, function(q){ q = $.trim(q); var value = q; var group = undefined; highlightItem = $(); for(var i=0; i<data.length; i++){ var row = data[i]; if (opts.filter.call(target, q, row)){ var v = row[opts.valueField]; var s = row[opts.textField]; var g = row[opts.groupField]; var item = opts.finder.getEl(target, v).show(); if (s.toLowerCase() == q.toLowerCase()){ value = v; if (opts.reversed){ highlightItem = item; } else { select(target, v, true); } } if (opts.groupField && group != g){ opts.finder.getGroupEl(target, g).show(); group = g; } } } vv.push(value); }); _setValues(vv); } function _setValues(vv){ if (opts.reversed){ highlightItem.addClass('combobox-item-hover'); } else { setValues(target, opts.multiple ? (q?vv:[]) : vv, true); } } } function doEnter(target){ var t = $(target); var opts = t.combobox('options'); var panel = t.combobox('panel'); // var item = panel.children('div.combobox-item-hover'); // if (item.length){ // item.removeClass('combobox-item-hover'); // var row = opts.finder.getRow(target, item); // var value = row[opts.valueField]; // if (opts.multiple){ // if (item.hasClass('combobox-item-selected')){ // t.combobox('unselect', value); // } else { // t.combobox('select', value); // } // } else { // t.combobox('select', value); // } // } var vv = []; $.map(t.combobox('getValues'), function(v){ if (getRowIndex(target, v) >= 0){ vv.push(v); } }); t.combobox('setValues', vv); if (!opts.multiple){ t.combobox('hidePanel'); } } function nav(target, dir){ var opts = $.data(target, 'combobox').options; var panel = $(target).combobox('panel'); // var item = panel.children('div.combobox-item-hover'); // if (!item.length){ // item = panel.children('div.combobox-item-selected'); // } var item = panel.children('div.combobox-item-selected'); //item.removeClass('combobox-item-hover'); var firstSelector = 'div.combobox-item:visible:not(.combobox-item-disabled):first'; var lastSelector = 'div.combobox-item:visible:not(.combobox-item-disabled):last'; if (!item.length){ item = panel.children(dir=='next' ? firstSelector : lastSelector); } else { if (dir == 'next'){ item = item.nextAll(firstSelector); if (!item.length){ item = panel.children(firstSelector); } } else { item = item.prevAll(firstSelector); if (!item.length){ item = panel.children(lastSelector); } } } if (item.length){ //item.addClass('combobox-item-hover'); var row = opts.finder.getRow(target, item); if (row){ $(target).combobox('scrollTo', row[opts.valueField]); if (opts.selectOnNavigation){ select(target, row[opts.valueField]); } } } } /** * select the specified value */ function select(target, value, remainText){ var opts = $.data(target, 'combobox').options; var values = $(target).combo('getValues'); if ($.inArray(value+'', values) == -1){ if (opts.multiple){ values.push(value); } else { values = [value]; } setValues(target, values, remainText); } } /** * set values */ function setValues(target, values, remainText){ var opts = $.data(target, 'combobox').options; var panel = $(target).combo('panel'); if (!$.isArray(values)){ values = values.split(opts.separator); } if (!opts.multiple){ values = values.length ? [values[0]] : ['']; } // unselect the old rows var oldValues = $(target).combo('getValues'); if (panel.is(':visible')){ panel.find('.combobox-item-selected').each(function(){ var row = opts.finder.getRow(target, $(this)); if (row){ if ($.easyui.indexOfArray(oldValues, row[opts.valueField]) == -1){ $(this).removeClass('combobox-item-selected'); } } }); } $.map(oldValues, function(v){ if ($.easyui.indexOfArray(values, v) == -1){ var el = opts.finder.getEl(target, v); if (el.hasClass('combobox-item-selected')){ el.removeClass('combobox-item-selected'); opts.onUnselect.call(target, opts.finder.getRow(target, v)); } } }); var theRow = null; var vv = [], ss = []; for(var i=0; i<values.length; i++){ var v = values[i]; var s = v; var row = opts.finder.getRow(target, v); if (row){ s = row[opts.textField]; theRow = row; var el = opts.finder.getEl(target, v); if (!el.hasClass('combobox-item-selected')){ el.addClass('combobox-item-selected'); opts.onSelect.call(target, row); } } else { s = findText(v, opts.mappingRows) || v; } vv.push(v); ss.push(s); } if (!remainText){ $(target).combo('setText', ss.join(opts.separator)); } if (opts.showItemIcon){ var tb = $(target).combobox('textbox'); tb.removeClass('textbox-bgicon ' + opts.textboxIconCls); if (theRow && theRow.iconCls){ tb.addClass('textbox-bgicon ' + theRow.iconCls); opts.textboxIconCls = theRow.iconCls; } } $(target).combo('setValues', vv); panel.triggerHandler('scroll'); // trigger the group sticking function findText(value, a){ var item = $.easyui.getArrayItem(a, opts.valueField, value); return item ? item[opts.textField] : undefined; } } /** * combobox扩展,去掉鼠标放在展开面板时默认选中鼠标悬停数值 */ $.extend($.fn.combobox.defaults, { keyHandler: { up: function(e){nav(this,'prev');e.preventDefault()}, down: function(e){nav(this,'next');e.preventDefault()}, left: function(e){}, right: function(e){}, enter: function(e){doEnter(this)}, query: function(q,e){doQuery(this, q)} }, }); })(jQuery)
二、不要在 Array 上使用 for-in 循环
for-in 循环只用于 object/map/hash
的遍历, 对 Array
用 for-in 循环有时会出错. 因为它并不是从 0 到 length - 1 进行遍历, 而是所有出现在对象及其原型链的键值。