CSS
.selected
{
background-color: Red;
color: #ffffff;
}
的jQuery
$(document).on('mousemove', '#mytable tr', function (e)
{
var currentColoumn = $(e.target).closest('td').index();
if ($(this).find("td").eq(currentColoumn).hasClass('selected') == true) {
e.preventDefault();
return false;
}
});
HTML
<table border="1" id="mytable ">
<tr>
<td>
9:30 AM
</td>
<td>
30
</td>
<td>
</td>
<td class="selected">
SELECTED
</td>
<td>
</td>
</tr>
</table>
我必须检查tr鼠标移动中的条件,如果td选择了类,则鼠标移动停止。 如果鼠标快速移动时条件不执行
答案 0 :(得分:3)
您在此处使用on
的方式是将事件侦听器附加到文档,并将回调应用于mousemove
元素中的行上的任何#mytable
事件。这意味着在内部,对on
的调用会转换为对delegate
的调用
通常情况下,我都是为了事件授权,原因很明显(性能最明显)。但是,在委派鼠标事件时,每次触发事件时都会调用处理程序。什么时候鼠标移动到document
的某个地方?当客户端正在阅读时,窗口被最小化或无法聚焦。
虽然jQuery隐藏了这一点,但您的代码实际上是这样做的:
document.body.addEventListener('mousemove',function(e)
{
var parent, target = (e = e || window.event).target || e.srcElement;
if (target.tagName.toLowerCase() === 'tr')
{//this reverse DOM lookup is probably cached, but anyway
parent = target;
while(parent = parent.parentNode)
{//or something
if (parent.getAttribute('id') === 'myTable')
{
break;
}
if (parent === document.body)
{//not child of #myTable
return e;
}
}
if (yourCallbackFunction.apply(target, [e]) === false)
{//remember: return false in jQ == preventDefault + stopPropagation:
e.preventDefault();
e.stopPropagation();
}
}
}, false);
只有当元素是#myTable
的子元素时才会调用您的回调,但每次鼠标移动时,都会调用事件处理程序 !
在委托这样的事件时,这样做会更明智:
$('#myTable').on('mousemove', 'tr', function()
{
//your code here
});
这样,只有当mousemove事件发生在里面 #myTable
元素时,才会调用事件处理程序。既然你对此感兴趣,那就是你应该做的。
您链接到的小提琴也是打包并且live
次来电。 live
现已弃用年,其中一个原因是:它是slooow。
如果速度是个问题,另一个需要考虑的问题是:例如,通过使用闭包来避免过多的DOM调用。 DOM调用很慢!
如果速度仍然是一个问题,请不要使用jQuery:使用VanillaJs,如果做得正确...它总是比lib快
答案 1 :(得分:1)
我认为这种方法只需要一些调整。可以在单击单元格时计算约束;当鼠标移动时,你知道何时停止着色细胞。
以下是细分:
jQuery(function($) {
document.onselectstart = function () { return false; }
var $table = $('#contentPlaceHolderMain_tableAppointment'),
columns = [],
dragInfo = null;
$table.find('td').each(function() {
var i = $(this).index();
(columns[i] = columns[i] || []).push(this);
});
这将创建一个透视数组,以便您可以更轻松地引用每个列。这会在以后派上用场。
$table.on('mouseup', function() {
// reset selection
dragInfo = null;
});
这与您之前的代码相同,除非您注意到两个不同之处:
我在$table
而不是document
设置点击事件处理程序;这可以防止在收到表外的点击时产生一些开销。
由于不推荐使用.live()
,因此应使用.on()
。
让我们转到mousedown
处理程序。
$table.on('mousedown', 'td', function() {
var $this = $(this),
columnIndex = $this.index();
if ($this.is('.selected') || columnIndex < 2) {
return;
}
var thisRow = $this.parent().index(),
selectionRowAbove = -Infinity,
selectionRowBelow = Infinity;
$.each(columns[columnIndex], function(rowIndex) {
if ($(this).is('.selected')) {
if (rowIndex < thisRow && rowIndex > selectionRowAbove) {
selectionRowAbove = rowIndex;
} else if (rowIndex > thisRow && rowIndex < selectionRowBelow) {
selectionRowBelow = rowIndex;
}
}
});
通过在td
而不是tr
添加监听器,您无需找到最近的单元格;它会为你计算。函数的这一部分计算出当前单元格上方和下方的红色单元格。
// unmark cells
$table.find(".csstdhighlight").removeClass("csstdhighlight");
dragInfo = {
column: columnIndex,
enclosure: {
above: selectionRowAbove,
below: selectionRowBelow
},
min: thisRow,
max: thisRow
};
$this.addClass('csstdhighlight');
});
该函数的最后一部分保存了稍后您需要的所有拖动信息。
$table.on('mousemove', 'td', function() {
if (!dragInfo) {
return;
}
var $this = $(this),
columnIndex = $this.index(),
rowIndex = $this.parent().index();
if (columnIndex != dragInfo.column || rowIndex == 0 || rowIndex <= dragInfo.enclosure.above || rowIndex >= dragInfo.enclosure.below) {
dragInfo = null;
return;
}
这些条件确保选择保持在我们之前确定的范围内。
// mark cells
var cells = [columns[columnIndex][rowIndex]];
while (dragInfo.min > rowIndex) {
cells.push(columns[columnIndex][dragInfo.min--]);
}
while (dragInfo.max < rowIndex) {
cells.push(columns[columnIndex][dragInfo.max++]);
}
$(cells).addClass('csstdhighlight');
});
});
该功能的最后一部分标志着选择;它通过计算上次调用之间的差异来实现,这样您就不必再次标记单元格了。
答案 2 :(得分:0)
然而,有一种半解决方案可以做到。
在主体上使用CSS隐藏实际鼠标光标,然后在鼠标位置显示虚假鼠标指针(只是常规图形)。
如果鼠标指针超出界限,请将假光标停在边界框上。
我不知道你的用例是什么,但是如果你不隐藏真正的鼠标指针会更好 MUCH ,但是在界限中会显示某种超大的鼠标指针框。大多数情况相同,用户友好。
答案 3 :(得分:0)
考虑一种不同的方法来确定鼠标移动应该停止突出显示一个细胞。
,而不是“当它越过选定类的单元格时停止”如果初始单元格和当前单元格之间存在选定类的单元格,请尝试停止。这可以确保如果快速移动阻止将mousemove事件委托给“选定”单元格,它仍然能够检测到您已经过了一个。
答案 4 :(得分:0)
我认为这里的主要问题是鼠标不会停留在每个单元格上。鼠标通常看起来像是连续移动,但是当我快速移动它时,它会四处跳跃,跳过它们之间的大量空间。
我想你已经看到了这种影响。因此,您要突出显示一系列单元格,而不仅仅是您指向的单元格(当前单元格)。但是,您只检查是否选择了当前单元格,而不是选择了单元格之间的任何单元格。
解决方案是检查单元格之间的所有内容,以确保它们未被选中。 jQuery有一个filter
函数可以很好地完成。我重构了你的代码以使用过滤器:
$("#contentPlaceHolderMain_tableAppointment tr").live('mousemove', function (e) {
// Compares with the last and next row index.
var currentRow = $(this).closest("tr")[0].rowIndex;
var currentColoumn = $(e.target).closest('td').index();
var allRows = $('#contentPlaceHolderMain_tableAppointment tr');
var previousRowIndex = parseInt(lastRow, 10);
var currentRowIndex = parseInt(currentRow, 10);
var traversedRows;
if (previousRowIndex < currentRowIndex)
traversedRows = allRows.slice(previousRowIndex, parseInt(currentRowIndex + 1));
else {
traversedRows = allRows.slice(currentRowIndex, previousRowIndex)
}
var affectedCells = traversedRows.children(':nth-child(' + parseInt(currentColoumn + 1) + ')');
if ($(this).find("td").eq(currentColoumn).hasClass('selected') == true ||
affectedCells.filter('.selected').length > 0) {
if (flag != false) {
flag = false;
e.preventDefault();
return false;
}
}
if (currentRow == 0) {
flag = false;
return false;
}
//cross cell selection.
if (colIndex != currentColoumn) {
flag = false;
return;
}
if (flag) {
affectedCells.addClass('csstdhighlight');
e.preventDefault();
return false;
}
});
小提琴位于:http://jsfiddle.net/Jg58G/7/
仍然存在一些问题,其中某些单元格应该突出显示,但它们不是。现在您拥有所选单元格的行,您可以重做切片逻辑以在正确的位置切片。我会把那部分留给你。
答案 5 :(得分:0)
请注意这是否正是您的目标,但它应该很容易适应。使用鼠标悬停减少了呼叫,应该有更好的性能。
小提琴:http://jsfiddle.net/VJG4F/
$(document).ready(function () {
// setup
var doc = this;
doc.checkOver = false;
doc.activeCell = {
x: -1,
y: -1
};
doc.lastCell = {
x: -1,
y: -1
};
doc.highlightClass = 'csstdhighlight';
doc.selectionClass = 'selected';
doc.selectionText = 'SELECTED';
// start checking on mousedown
$('#contentPlaceHolderMain_tableAppointment td').on('mousedown', function (e) {
doc.checkOver = true;
// set active and last cell for reference
doc.lastCell.x = doc.activeCell.x = $(this).closest('td').index();
doc.lastCell.y = doc.activeCell.y = $(this).closest("tr").index();
// highlight selected cells
var cellSelector = '#contentPlaceHolderMain_tableAppointment tr:eq(' + doc.activeCell.y + ') td:eq(' + doc.activeCell.x + ')';
$(cellSelector).addClass(doc.highlightClass);
// check for movement
$('#contentPlaceHolderMain_tableAppointment td').on('mouseover', function (e) {
if (!(doc.checkOver)) return;
// get current cell for reference
var currCell = {
x: $(e.target).closest('td').index(),
y: $(e.target).closest('tr').index()
};
// verify mouse is over a different cell
if ( !((currCell.y != doc.lastCell.y && currCell.y != -1) || (currCell.x != doc.lastCell.x && currCell.x != -1)) ) return false;
// make sure other cells are not highlighted
$('#contentPlaceHolderMain_tableAppointment td').removeClass(doc.highlightClass);
// highlight selected cells
var topLeft = {
x: Math.min(currCell.x, doc.activeCell.x),
y: Math.min(currCell.y, doc.activeCell.y)
};
var botRight = {
x: Math.max(currCell.x, doc.activeCell.x),
y: Math.max(currCell.y, doc.activeCell.y)
};
for (var x=topLeft.x;x<=botRight.x;x++) {
for (var y=topLeft.y;y<=botRight.y;y++) {
var cellSelector = '#contentPlaceHolderMain_tableAppointment tr:eq(' + y + ') td:eq(' + x + ')';
$(cellSelector).addClass(doc.highlightClass);
}
}
// update last cell
doc.lastCell.y = currCell.y;
doc.lastCell.x = currCell.x;
return false;
});
// check for mouseup
$('#contentPlaceHolderMain_tableAppointment td').on('mouseup', function (e) {
// stop checking for movement
$('#contentPlaceHolderMain_tableAppointment td').off('mouseup');
$('#contentPlaceHolderMain_tableAppointment td').off('mouseout');
// get current cell for reference
var currCell = {
x: $(this).closest("td").index(),
y: $(this).closest('tr').index()
};
// make sure cells are not highlighted
$('#contentPlaceHolderMain_tableAppointment td').removeClass(doc.highlightClass);
// select cells
var topLeft = {
x: Math.min(currCell.x, doc.activeCell.x),
y: Math.min(currCell.y, doc.activeCell.y)
};
var botRight = {
x: Math.max(currCell.x, doc.activeCell.x),
y: Math.max(currCell.y, doc.activeCell.y)
};
// single cell - toggle
if( topLeft.x == botRight.x && topLeft.y == botRight.y ) {
var cellSelector = '#contentPlaceHolderMain_tableAppointment tr:eq(' + topLeft.y + ') td:eq(' + topLeft.x + ')';
$(cellSelector).toggleClass(doc.selectionClass);
if( $(cellSelector).text() == doc.selectionText ) $(cellSelector).text('');
else $(cellSelector).text(doc.selectionText);
// multi-cell, select all
} else {
for (var x=topLeft.x;x<=botRight.x;x++) {
for (var y=topLeft.y;y<=botRight.y;y++) {
var cellSelector = '#contentPlaceHolderMain_tableAppointment tr:eq(' + y + ') td:eq(' + x + ')';
$(cellSelector).addClass(doc.selectionClass);
$(cellSelector).text(doc.selectionText);
}
}
}
// reset
doc.checkOver = false;
doc.activeCell.y = -1;
doc.activeCell.x = -1;
doc.lastCell.y = -1;
doc.lastCell.x = -1;
return false;
});
return false; // prevent default
});
});