使用 Ctrl+单击和 Shift+单击选择多个 HTML 表格行
Posted
技术标签:
【中文标题】使用 Ctrl+单击和 Shift+单击选择多个 HTML 表格行【英文标题】:Select multiple HTML table rows with Ctrl+click and Shift+click 【发布时间】:2013-07-31 14:35:59 【问题描述】:Demo
我想使用 Windows Shift 和 Ctrl 键选择多行,就像 Windows 中的多个文件夹选择一样。
我必须从选定行的表中获取第一列(学生 ID)并传递到服务器端 C#
并从数据库中删除这些记录。
我已经用 javascript 编写了一个代码,但是 classname 没有被应用于 Shift 或 Ctrl+ 上的<tr>
左键单击。
HTML
<table id="tableStudent" border="1">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Class</th>
</tr>
</thead>
<tbody>
<tr onmousedown="RowClick(this,false);">
<td>1</td>
<td>John</td>
<td>4th</td>
</tr>
<tr onmousedown="RowClick(this,false);">
<td>2</td>
<td>Jack</td>
<td>5th</td>
</tr>
<tr onmousedown="RowClick(this,false);">
<td>3</td>
<td>Michel</td>
<td>6th</td>
</tr>
<tr onmousedown="RowClick(this,false);">
<td>4</td>
<td>Mike</td>
<td>7th</td>
</tr>
<tr onmousedown="RowClick(this,false);">
<td>5</td>
<td>Yke</td>
<td>8th</td>
</tr>
<tr onmousedown="RowClick(this,false);">
<td>6</td>
<td>4ke</td>
<td>9th</td>
</tr>
<tr onmousedown="RowClick(this,false);">
<td>7</td>
<td>7ke</td>
<td>10th</td>
</tr>
</tbody>
</table>
JavaScript
var selectedrow;
function RowClick(currenttr, lock)
var trs =tableStudent.tBodies[0].getElementsByTagName("tr");
var cnt;
if(window.event.button==2)
if(currenttr.className=='selected')
return false;
alert(trs.length);
if (((window.event.shiftKey) && (window.event.ctrlKey) ) ||(window.event.shiftKey))
for(var j=0; j<trs.length; j++)
if (trs[j].className!='normallock')
trs[j].className='normal';
var mark=false;
if (typeof(selectedrow)=="undefined")
selectedrow=currenttr;
selectedrow.className='selected'
return false;
for(var j=0; j<trs.length; j++)
if ((trs[j].id ==selectedrow.id) || (trs[j].id ==currenttr.id) )
if (trs[j].className!='normallock')
trs[j].className='selected'
mark = !(mark);
else
if(mark==true)
if (trs[j].className!='normallock')
trs[j].className='selected'
else if(window.event.ctrlKey)
//if ctrl key is seelcted while selecting the patients
// select the patient with currently clicked row plus
// maintain the previous seelcted status
cnt=0;
for(var j=0; j<trs.length; j++)
if(trs[j].id == currenttr.id)
if(trs[j].className=='selected')
trs[j].className='normal';
else
trs[j].className='selected';
if(trs[j].className=='selected')
cnt++;
if(cnt==0)
selectedrow=undefined;
return false;
else
for(var j=0; j<trs.length; j++)
if(trs[j].id == currenttr.id)
trs[j].className='selected'
else
if (trs[j].className!='normallock')
trs[j].className='normal';
selectedrow=currenttr;
【问题讨论】:
小提琴中的代码不是 jQuery,但您已将问题标记为 jQuery。那么你在你的项目中使用 jQuery 库吗?另外,请编辑问题,详细说明您遇到的确切问题。 项目中不使用jquery...去掉jquery标签 我想要什么,我必须使用 Window shift 和 control 键选择多行。例如在 Windows PC 中选择多个文件夹。从所选行的表中,我必须获取(第一列)学生 ID 和传递到服务器端 C# 并从数据库中删除这些记录。 演示中的错误是什么?我看到一个 JavaScriptalert
但没有错误。
类名不适用于 tr on cntrl+key cntrl+shft key
【参考方案1】:
这可能不是您想要的所有功能,因为问题有点模糊,但他尝试添加 Ctrl 或 Shift+ 鼠标左键按钮 选择或取消选择多个表格行 - see demo 和下面的代码。 免责声明:只有在 Chrome 中测试并且代码几乎肯定可以优化。
JavaScript
var lastSelectedRow;
var trs = document.getElementById('tableStudent').tBodies[0].getElementsByTagName('tr');
// disable text selection
document.onselectstart = function()
return false;
function RowClick(currenttr, lock)
if (window.event.ctrlKey)
toggleRow(currenttr);
if (window.event.button === 0)
if (!window.event.ctrlKey && !window.event.shiftKey)
clearAll();
toggleRow(currenttr);
if (window.event.shiftKey)
selectRowsBetweenIndexes([lastSelectedRow.rowIndex, currenttr.rowIndex])
function toggleRow(row)
row.className = row.className == 'selected' ? '' : 'selected';
lastSelectedRow = row;
function selectRowsBetweenIndexes(indexes)
indexes.sort(function(a, b)
return a - b;
);
for (var i = indexes[0]; i <= indexes[1]; i++)
trs[i-1].className = 'selected';
function clearAll()
for (var i = 0; i < trs.length; i++)
trs[i].className = '';
HTML
<table id="tableStudent" border="1">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Class</th>
</tr>
</thead>
<tbody>
<tr onmousedown="RowClick(this,false);">
<td>1</td>
<td>John</td>
<td>4th</td>
</tr>
<tr onmousedown="RowClick(this,false);">
<td>2</td>
<td>Jack</td>
<td>5th</td>
</tr>
<tr onmousedown="RowClick(this,false);">
<td>3</td>
<td>Michel</td>
<td>6th</td>
</tr>
<tr onmousedown="RowClick(this,false);">
<td>4</td>
<td>Mike</td>
<td>7th</td>
</tr>
<tr onmousedown="RowClick(this,false);">
<td>5</td>
<td>Yke</td>
<td>8th</td>
</tr>
<tr onmousedown="RowClick(this,false);">
<td>6</td>
<td>4ke</td>
<td>9th</td>
</tr>
<tr onmousedown="RowClick(this,false);">
<td>7</td>
<td>7ke</td>
<td>10th</td>
</tr>
</tbody>
</table>
CSS
.selected
background: lightBlue
我还会查看addEventListener vs onclick 并将事件处理程序绑定移出HTML 并移入JavaScript。这被称为Unobtrusive Javascript。
您可能想阅读的资源:
Retrieve Table Row Index of Current Row disable text selection while pressing 'shift' https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort【讨论】:
andyb 感谢您的回复,当我使用 ctrl+click 单击第一行并使用 ctrl+shift 单击第 7 行然后选择 1 到 7 所有行但在您的小提琴中选择第一个和最后一个时,我遇到了一个问题只有 我复制了 Windows 的工作方式。要选择一个范围,请单击一次左键,然后按住 shift 键并单击第二个范围。在这种情况下,您不需要 ctrl。如果您希望用户使用 ctrl+shift+click 选择范围,我怀疑我的逻辑需要调整。如果您调试代码,您应该确切地看到问题所在。 提示:与lastSelectedRow
变量有关。
你能帮我做吗?调试后我没有得到确切的原因
一个简单的调试会发现lastSelectedRow
在第二次单击时被覆盖,因此“范围”索引实际上是相同的。另外,正如我已经说过的,使用 ctrl+shift+click 选择范围 不 复制 Windows。如果您真的无法解决,只需将第一个 if
条件更改为 if (window.event.ctrlKey && !window.event.shiftKey)
即可。【参考方案2】:
我使它适用于所有 Windows 7 资源管理器行为和 jquery 鼠标事件。
http://jsfiddle.net/ubershmekel/nUV23/6/
注意:
当您单击时,您为下一次按住 shift 键设置一个轴 使用 Ctrl-Shift 可扩展当前选择,而不是像单独使用 Shift 那样进行旋转。 使用 Ctrl 键单击添加枢轴,然后您可以使用 Ctrl-Shift 围绕新枢轴展开该选择。js:
var selectionPivot;
// 1 for left button, 2 for middle, and 3 for right.
var LEFT_MOUSE_BUTTON = 1;
var trs = document.getElementById('tableStudent').tBodies[0].getElementsByTagName('tr');
var idTds = $('td:first-child');
idTds.each(function(idx, val)
// onselectstart because IE doesn't respect the css `user-select: none;`
val.onselectstart = function() return false; ;
$(val).mousedown(function(event)
if(event.which != LEFT_MOUSE_BUTTON)
return;
var row = trs[idx];
if (!event.ctrlKey && !event.shiftKey)
clearAll();
toggleRow(row);
selectionPivot = row;
return;
if (event.ctrlKey && event.shiftKey)
selectRowsBetweenIndexes(selectionPivot.rowIndex, row.rowIndex);
return;
if (event.ctrlKey)
toggleRow(row);
selectionPivot = row;
if (event.shiftKey)
clearAll();
selectRowsBetweenIndexes(selectionPivot.rowIndex, row.rowIndex);
);
);
function toggleRow(row)
row.className = row.className == 'selected' ? '' : 'selected';
function selectRowsBetweenIndexes(ia, ib)
var bot = Math.min(ia, ib);
var top = Math.max(ia, ib);
for (var i = bot; i <= top; i++)
trs[i-1].className = 'selected';
function clearAll()
for (var i = 0; i < trs.length; i++)
trs[i].className = '';
还有 CSS:
.selected
background: #bdf;
td:first-child
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-o-user-select: none;
user-select: none;
td,th
padding: 3px;
border: 2px solid #aaa;
table
border-collapse: collapse;
【讨论】:
我觉得这个很有用,做了一个版本给可能在这里遇到的人! jsfiddle.net/BerkerYuceer/cry26oja非常感谢!【参考方案3】:这是我最近为一个项目编写的 jQuery 插件。思想交流...
完全按照您的习惯工作,+ 它非常快,因为它在数组上操作而无需检查属性、类等,并且 add/removeClass 仅在选定元素上触发:
// Use like:
// $("table").selekt();
//
// Available options:
$("table").selekt(
children: "tr", // Elements to target (default: "tbody tr")
className: "selected", // Desired CSS class (default: "selected")
onSelect: function(sel) // Useful callback
$("span").text(sel.length + ' in ' + this.id);
);
.selected background: #0bf;
table border: 1px solid #555;display: inline-block; vertical-align: top;
<p>Seleceted: <span id="info">0</span></p>
<table id="table_1">
<tr><td>1 SELECT ME</td></tr>
<tr><td>2 SELECT ME</td></tr>
<tr><td>3 SELECT ME</td></tr>
<tr><td>4 SELECT ME</td></tr>
<tr><td>5 SELECT ME</td></tr>
<tr><td>6 SELECT ME</td></tr>
</table>
<table id="table_2">
<tr><td>1 SELECT ME</td></tr>
<tr><td>2 SELECT ME</td></tr>
<tr><td>3 SELECT ME</td></tr>
<tr><td>4 SELECT ME</td></tr>
</table>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
;(function($)
// selekt jQuery plugin // http://***.com/a/35813513/383904
$.fn.selekt = function()
var settings = $.extend(
children: "tbody tr",
className: "selected",
onSelect: function()
, arguments[0] || );
return this.each(function(_, that)
var $ch = $(this).find(settings.children),
sel = [],
last;
$ch.on("mousedown", function(ev)
var isCtrl = (ev.ctrlKey || ev.metaKey),
isShift = ev.shiftKey,
ti = $ch.index(this),
li = $ch.index(last),
ai = $.inArray(this, sel);
if (isShift || isCtrl) ev.preventDefault();
$(sel).removeClass(settings.className);
if (isCtrl)
if (ai > -1) sel.splice(ai, 1);
else sel.push(this);
else if (isShift && sel.length > 0)
if (ti > li) ti = [li, li = ti][0];
sel = $ch.slice(ti, li + 1);
else
sel = ai < 0 || sel.length > 1 ? [this] : [];
last = this;
$(sel).addClass(settings.className);
settings.onSelect.call(that, sel);
);
);
;
(jQuery));
</script>
【讨论】:
在 Mac 上的 Safari 上工作,但你应该检查元 ||控制,以便命令键起作用。 Ctrl +shift 单击以向现有选择添加范围也很好。 我继承了使用此插件的代码,发现只要网格未排序,它就可以很好地工作。排序后选择多行似乎使用原始排序顺序。该数组来自哪里,我在哪里可以找到排序后的数组? @flipdoubt 如果您正在对 DOM 元素数组进行排序,则应该扩展上述脚本以便能够将其销毁并使用新排序的元素对其进行重新定义。像$myList.selekt('destroy')
这样的东西,然后再做一次$myList.selekt(mySelektoptionsObject)
要销毁上面的插件,只需在var settings....
之前放置这个:if(arguments[0] === 'destroy') return this.find('*').off('.selekt');
还要确保用适当的命名空间替换mousedown:$ch.on("mousedown.selekt", function(ev)
【参考方案4】:
检查这个例子:
JSFiddle: Highlight list with shift and ctrl
部分代码:
switch(e.type)
case "keydown" :
console.log('k_down');
keysPressed.push(e.keyCode);
break;
case "keyup" :
console.log('k_up');
var idx = keysPressed.indexOf(e.keyCode);
if (idx >= 0)
keysPressed.splice(idx, 1);
break;
来源可以在这里找到: Source files github
【讨论】:
【参考方案5】:我知道这个问题已经得到解答,而且已经很老了,但我发现 andyb 的答案非常有帮助。也许是因为 andyb 的答案现在可能已经过时了,但我最终不得不稍微改变他的解决方案以适应我的项目,所以我想我会分享我的更新版本。这是我使用少量 jQuery 得到的结果。
$(document).ready(function()
//put all the table rows in a variable after page load to pass in to RowClick
var trs = $('#tableStudent tr')
//bind the click handler to all the table rows
$('tr').on('click', function()
//call the RowClick function on click event
RowClick($(this),false,trs)
)
)
//declare variable to store the most recently clicked row
var lastSelectedRow;
// disable text selection
document.onselectstart = function()
return false;
function RowClick(currentrow, lock, rows)
//if control is held down, toggle the row
if (window.event.ctrlKey)
toggleRow(currentrow);
//if there are no buttons held down...
if (window.event.button === 0)
//if neither control or shift are held down...
if (!window.event.ctrlKey && !window.event.shiftKey)
//clear selection
clearAll(rows);
//toggle clicked row
toggleRow(currentrow);
//if shift is held down...
if (window.event.shiftKey)
//pass the indexes of the last selected row and currently selected row along with all rows
selectRowsBetweenIndexes([lastSelectedRow.index(), currentrow.index()], rows)
function toggleRow(row)
//if the row is not the header row...
if (!row.hasClass('header-row'))
//if the row is selected...
if (row.hasClass('selected'))
//deselect it
row.removeClass('selected')
else
//otherwise, select it
row.addClass('selected')
//reassign the most recently selected row
lastSelectedRow = row;
function selectRowsBetweenIndexes(indexes,rows)
//sort the indexes in ascending order
indexes.sort(function(a, b)
return a - b;
);
//for every row starting at the first index, until the second index...
for (var i = indexes[0]; i <= indexes[1]; i++)
//select the row
$(rows[i+1]).addClass('selected');
function clearAll(rows)
//for all rows...
for (var i = 0; i < rows.length; i++)
//deselect each row
$(rows[i]).removeClass("selected");
【讨论】:
【参考方案6】:以下代码是从 Robo C Buljan 修改的,因为我想使用复选框和 shift 键进行多选
<includeScript value="/jquery-3.2.0.min.js" />
<script>
;(function($)
// selekt jQuery plugin // http://***.com/a/35813513/383904
$.fn.selekt = function()
var settings = $.extend(
children: "td input[type='checkbox'][name='ids']",
onSelect: function()
, arguments[0] || );
return this.each(function(_, that)
var $ch = $(this).find(settings.children),
sel = [],
last;
$ch.on("mouseup", function(ev)
/* Note 1: Remember this code is run when a checkbox is clicked and is run before checbox's state changes because of click
i.e. to say if the checkbox was checked and we clicked it to uncheck, then this event handler (mouse up)code is called before the unchecing happens */
if(ev.shiftKey || ev.ctrlKey)
ev.preventDefault();
ev.stopPropagation();
var self = this;
var ti = $ch.index(this), // index of current element in the matching elements
li = $ch.index(last), // index of last element in the matching elements
ai = $.inArray(this, sel); // index of this in the sel array
if(ev.ctrlKey)
if(ai > -1) sel.splice(ai, 1);
else sel.push(this);
else if(ev.shiftKey && sel.length > 0)
if(ti > li) ti = [li, li=ti][0];
sel = $ch.slice(ti, li+1);
else
sel = ai < 0 || sel.length > 1 ? [this] : [];
last = this;
/* purpose 2
code to check checkboxes inside the array*/
$(sel).each(function(index, checkbox)
/* see/search Note 1 in comments, if the checkbox is already checked/unchecked then uncheck/check all the elements straight from the last element correspondingly */
if(self.checked)
if( checkbox != self)
checkbox.checked = false;
else
if( checkbox != self)
checkbox.checked = true;
)
/*end of purpose 2*/
// settings.onSelect.call(that, sel); // this is defined just in case we want to call some function after the select/deselect operation
);
);
;
(jQuery));
setTimeout(function()
$("table.list").selekt();
,500)
</script>
【讨论】:
以上是关于使用 Ctrl+单击和 Shift+单击选择多个 HTML 表格行的主要内容,如果未能解决你的问题,请参考以下文章