【问题标题】:Get element at point in entire page (even if it's not visible)在整个页面中获取元素(即使它不可见)
【发布时间】:2012-01-25 22:58:37
【问题描述】:

我有一个页面,上面有一些小部件。有 2 列。如果左侧(或右侧)没有小部件,小部件将自动调整大小。

我正在使用document.elementFromPoint(在获取小部件的偏移量之后)来检测它旁边是否有小部件。

document.elementFromPoint 有问题。

如果指定点在文档的可见范围之外...结果为null

仅当元素在视口中时才有效。即使不可见,如何检测某个位置的元素是什么?

编辑:这是一个例子:

红线是视口,灰色框(有红色文字)是Widget D的原始位置(另一个Widget D是页面加载完成时的位置)。当页面加载时,它会检查小部件 B、C 和 D。它会获取它们的偏移量,然后使用 document.elementFromPoint 来查看小部件 A 是否在它们的右侧。如果 Widget A 在其右侧,则 Widget 为半宽,否则为全宽。

小部件 D 是全宽的,因为 document.elementFromPoint 返回 null 因为它在视口之外。我如何检测到 Widget A 在 Widget D 的右侧,即使它在视口之外?

【问题讨论】:

  • 如果您的代码不经常执行,您可以将htmlbody 元素移动到左/右/上/下,以便该元素在视口内是临时的。另一种选择:如果您知道必须比较哪些元素,请使用$('selector').offset().top.left)加上.height()/.outerHeight().width()/.outerWidth() 来计算元素。
  • @RobW:我试图用一个糟糕的模型来解释我的问题。
  • 那么,您知道哪些元素必须相对于彼此调整大小吗?
  • @RobW:基本上。此页面是可定制的。加载时,每个小部件会根据其右侧的内容检查它是半宽还是全宽。
  • 通过说“每个小部件”,您暗示必须检查固定数量的元素。您可以遍历每个元素,并结合我第一条评论中的方法来检查当前元素的右侧/左侧是否存在元素。

标签: javascript jquery


【解决方案1】:

以下代码将元素的边界保存在两个列表中:x 和 y 位置。然后,您可以使用for-loop 从给定的偏移量开始,然后遍历列表。在答案的底部,显示了一个实现。

// These arrays are going to contain many empty elements ;)
var xAxis = [];
var yAxis = [];

// Our storage. Each element looks like: [$element, top, right, bottom, left]
// Beware of cross-references! Deleted elements cannot be GCed if they're here!
var allElements = [];

/*
 * @param   $elem jQuery object
 * @returns Object containing the jQuery object and the floored border offsets
 */
function getBorders($elem) {
    $elem = $elem instanceof jQuery ? $elem.first() : $($elem);
    var offset = $elem.offset();           // Properties: top, left

    var width = $elem.outerWidth();        // Includes padding, border.
    var leftBorder = offset.left;          // Position of the left border ->|
    var rightBorder = leftBorder + width;  // Position of the right border  |<-

    var height = $elem.outerHeight();      // Includes padding, border
    var topBorder = offset.top;            // Position of the top border    _v_
    var bottomBorder = offset.top + height;// Position of the bottom border  ^

    // Turn all numbers in integers, so that they can be used as indexes
    //   for arrays
    // See also: http://stackoverflow.com/a/8112802/938089
    return {
        $elem: $elem,
        top: ~~topBorder,
        right: ~~rightBorder,
        bottom: ~~bottomBorder,
        left: ~~leftBorder
    };
}

$('.widget').each(function() {
    var $this = $(this);

    var info = getBorders($this);
    allElements.push(info);
    // The positions are floored, so that they can be used as a quick reference
    xAxis[info.left] = xAxis[info.right] = info;
    yAxis[info.top] = yAxis[info.bottom] = info;
});

创建的列表现在可以用来检查是否有任何元素发生碰撞。例如,考虑以下函数:

function doesItCollide($elem) {
    // WeakMaps are useful. For compatibility, I don't use them.
    var info$elem = getBorders($elem);
    // info$elem properties: $elem, top, right, bottom, left
    // Y-oriented
    for (var y=info$elem.top; y<yAxis.length; y++) {
        var candidate = yAxis[y];
        // Not undefined, and not iself
        if (candidate && candidate.$elem[0] !== info$elem.$elem[0]) {
            // Check whether the element is inside the range
            if (candidate.top >= info$elem.bottom &&
                candidate.bottom >= info$elem.bottom) continue;
            // It's here, so the top / bottom are possibly in the same range
            // Check whether the x-positions are also colliding
            if (candidate.left >= info$elem.left && /* Left within range? */
                candidate.left <= info$elem.right || /* OR */
                candidate.right <= info$elem.right && /* Right within range? */
                candidate.right >= info$elem.left) {
                return candidate;
            }
        }
    }
    return null;
}

示例(演示:http://jsfiddle.net/LtJsM/):

$('.widget').each(function() {
    var $this = $(this);
    var overlapping = doesItCollide($this);
    if (overlapping) {
        alert('Current element:  '+this.className +
           '\nColliding element: ' + overlapping.$elem[0].className);
    }
});

【讨论】:

  • 谢谢你,我需要稍微调整一下,但是元素位置数组是个好主意:-)
猜你喜欢
  • 2022-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-09
  • 1970-01-01
  • 2012-01-20
  • 2018-06-04
相关资源
最近更新 更多