如何检查元素是否在屏幕外

Max*_*Max 74 jquery zk

如果DIV元素没有脱离屏幕,我需要检查jQuery.这些元素是可见的,并根据CSS属性显示,但它们可以通过以下方式有意放置在屏幕外:

position: absolute; 
left: -1000px; 
top: -1000px;
Run Code Online (Sandbox Code Playgroud)

我无法使用jQuery :visible选择器,因为该元素的高度和宽度都不为零.

我没有做任何幻想.这个绝对位置放置是我的Ajax框架实现某些小部件的隐藏/显示的方式.

scu*_*ker 122

取决于你对"屏幕外"的定义.是在视口内,还是在页面的已定义边界内?

使用Element.getBoundingClientRect(),您可以轻松检测元素是否在视口的边界内(即屏幕上或屏幕外):

jQuery.expr.filters.offscreen = function(el) {
  var rect = el.getBoundingClientRect();
  return (
           (rect.x + rect.width) < 0 
             || (rect.y + rect.height) < 0
             || (rect.x > window.innerWidth || rect.y > window.innerHeight)
         );
};
Run Code Online (Sandbox Code Playgroud)

然后,您可以通过以下几种方式使用它:

// returns all elements that are offscreen
$(':offscreen');

// boolean returned if element is offscreen
$('div').is(':offscreen');
Run Code Online (Sandbox Code Playgroud)

  • 请注意,目前(2017年1月)至少在Chrome上不起作用,因为Element.getBoundingClientRect()具有top,right,bottom和left属性而不是x和y. (6认同)
  • 我喜欢这个,但是如果您的元素位于可滚动容器内,它就会中断——2 屏幕高 DIV 底部的元素将始终处于“屏幕外”,因为窗口高度小于元素的 offsetTop。 (2认同)

Sam*_*ert 18

这里有一个jQuery插件,允许用户测试元素是否属于浏览器的可见视口,并考虑浏览器的滚动位置.

$('#element').visible();
Run Code Online (Sandbox Code Playgroud)

您还可以检查部分可见性:

$('#element').visible( true);
Run Code Online (Sandbox Code Playgroud)

一个缺点是它只适用于垂直定位/滚动,尽管它应该很容易在混合中添加水平定位.


小智 8

无需插件检查是否在视口外.

var w = Math.max(document.documentElement.clientWidth, window.innerWidth || 0)
var h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0)
var d = $(document).scrollTop();

$.each($("div"),function(){
    p = $(this).position();
    //vertical
    if (p.top > h + d || p.top > h - d){
        console.log($(this))
    }
    //horizontal
    if (p.left < 0 - $(this).width() || p.left > w){
        console.log($(this))
    }
});
Run Code Online (Sandbox Code Playgroud)


ade*_*hox 8

尽管原始发帖人要求使用 JQuery 解决方案,但他们还在问题上添加了一个 JavaScript 标签,这也允许添加这个更现代的解决方案:

TLDR: 使用IntersectionObserver API

以下是我用普通 JavaScript 和 React 制作的两个沙箱,以在工作示例中展示这一点:

  1. Vanilla JavaScript 示例沙箱
  2. React 示例沙箱(使用react-intersection-observer NPM 模块)

更长一点的答案: 自从提出这个问题以来已经过去了 10 多年,当时使用这些 JQuery 解决方案是有意义的,但今天我们不再需要 JQuery 来满足这样的需求:

Intersection Observer API 提供了一种观察目标元素与祖先元素或顶级文档视口的交集变化的方法。

它非常容易使用,首先创建一个观察者并传递它在触发时想要执行的操作(回调函数),并且还可以选择传递一个选项对象,例如,在这个问题的情况下,我们需要值为 1 的阈值选项,以确保元素完全在视口内,如果不是,那么我们就会知道它是“屏幕外”的:

const doable = () => {
  //do something
}
const observer = new IntersectionObserver(doable, { threshold: 1 });
Run Code Online (Sandbox Code Playgroud)

现在调用observe()它的方法并将您想要观察的元素传递给它:

observer.observe(observee)
Run Code Online (Sandbox Code Playgroud)


pie*_*e6k 5

好吧...我在这里提出的每个解决方案中都发现了一些问题。

  • 您应该能够选择是要在屏幕上显示整个元素还是仅显示其中的任何一部分
  • 如果元素比窗口高/宽,并且覆盖了浏览器窗口,建议的解决方案将失败

这是我的解决方案,其中包括jQuery .fn实例函数和expression。我在函数中创建了更多的变量,但是对于复杂的逻辑问题,我喜欢将其分为较小的,命名明确的部分。

我正在使用getBoundingClientRect相对于视口返回元素位置的方法,所以我不需要关心滚动位置

使用方法

$(".some-element").filter(":onscreen").doSomething();
$(".some-element").filter(":entireonscreen").doSomething();
$(".some-element").isOnScreen(); // true / false
$(".some-element").isOnScreen(true); // true / false (partially on screen)
$(".some-element").is(":onscreen"); // true / false (partially on screen)
$(".some-element").is(":entireonscreen"); // true / false 
Run Code Online (Sandbox Code Playgroud)

资料来源

$.fn.isOnScreen = function(partial){

    //let's be sure we're checking only one element (in case function is called on set)
    var t = $(this).first();

    //we're using getBoundingClientRect to get position of element relative to viewport
    //so we dont need to care about scroll position
    var box = t[0].getBoundingClientRect();

    //let's save window size
    var win = {
        h : $(window).height(),
        w : $(window).width()
    };

    //now we check against edges of element

    //firstly we check one axis
    //for example we check if left edge of element is between left and right edge of scree (still might be above/below)
    var topEdgeInRange = box.top >= 0 && box.top <= win.h;
    var bottomEdgeInRange = box.bottom >= 0 && box.bottom <= win.h;

    var leftEdgeInRange = box.left >= 0 && box.left <= win.w;
    var rightEdgeInRange = box.right >= 0 && box.right <= win.w;


    //here we check if element is bigger then window and 'covers' the screen in given axis
    var coverScreenHorizontally = box.left <= 0 && box.right >= win.w;
    var coverScreenVertically = box.top <= 0 && box.bottom >= win.h;

    //now we check 2nd axis
    var topEdgeInScreen = topEdgeInRange && ( leftEdgeInRange || rightEdgeInRange || coverScreenHorizontally );
    var bottomEdgeInScreen = bottomEdgeInRange && ( leftEdgeInRange || rightEdgeInRange || coverScreenHorizontally );

    var leftEdgeInScreen = leftEdgeInRange && ( topEdgeInRange || bottomEdgeInRange || coverScreenVertically );
    var rightEdgeInScreen = rightEdgeInRange && ( topEdgeInRange || bottomEdgeInRange || coverScreenVertically );

    //now knowing presence of each edge on screen, we check if element is partially or entirely present on screen
    var isPartiallyOnScreen = topEdgeInScreen || bottomEdgeInScreen || leftEdgeInScreen || rightEdgeInScreen;
    var isEntirelyOnScreen = topEdgeInScreen && bottomEdgeInScreen && leftEdgeInScreen && rightEdgeInScreen;

    return partial ? isPartiallyOnScreen : isEntirelyOnScreen;

};

$.expr.filters.onscreen = function(elem) {
  return $(elem).isOnScreen(true);
};

$.expr.filters.entireonscreen = function(elem) {
  return $(elem).isOnScreen(true);
};
Run Code Online (Sandbox Code Playgroud)