如果在鼠标移动速度较快时未执行条件

时间:2013-08-14 06:38:08

标签: javascript jquery

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选择了类,则鼠标移动停止。 如果鼠标快速移动时条件不执行

Demo

6 个答案:

答案 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;
    });

这与您之前的代码相同,除非您注意到两个不同之处:

  1. 我在$table而不是document设置点击事件处理程序;这可以防止在收到表外的点击时产生一些开销。

  2. 由于不推荐使用.live(),因此应使用.on()

  3. 让我们转到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');
        });
    });
    

    该功能的最后一部分标志着选择;它通过计算上次调用之间的差异来实现,这样您就不必再次标记单元格了。

    Demo

答案 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
    });

});