浅谈节点与视图层的关系

222 阅读3分钟

「这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战」。


前言

在业务场景中,我们不乏会碰到各种奇奇怪怪的关于节点和视图关系的逻辑。譬如:节点是否在可视区域内,节点是否已经滚动到底部等。这里我们就这些问题,分享一下一些在写代码时经常用到的方法

节点与视图

判断元素是否在可视区域内

在判断元素是否在可视区域内,我们需要做的,肯定是将元素所处坐标位置与当前窗口位置进行比对

这里我们需要用到一个比较新的api Element.getBoundingClientRect() (官方文档在这里)

getBoundingClientRect() 返回的是对象,其包含:

x,y:表示元素左上角距离视窗的坐标
width、height:表示元素的框和高(= text 的高度 + border + padding)

`注意:下面 4 个属性的值在页面滚动时会发生改变`
top:元素上边框距离视窗顶部的的距离
bottom:元素下边框距离视窗顶部的的距离
left:元素左边框距离视窗左边的的距离
right:元素右边框距离视窗左部的的距离

然后我们只需要拿元素自身的上边界与视窗距离,元素自身下边界与视窗距离,同当前窗口高度比对一下,即可获知元素是否在可视区域内,代码如下:

// 获取浏览器高度,做了兼容
getWindowHeight() {
    var windowHeight = 0;
    if (document.compatMode === 'CSS1Compat') {
        windowHeight = document.documentElement.clientHeight;
    } else {
        windowHeight = document.body.clientHeight;
    }
    return windowHeight;
}

isView(dom) {
    // 这里传入dom的id  当然可以自定义为传入节点
    if (!dom) {
        // 做非空校验
        return false;
    }
    
    // 获取节点
    let ele = document.getElementById(dom);
    if (!ele) {
        return false;
    }
    
    let windowHeight = getWindowHeight();
    let pos = ele.getBoundingClientRect();
    // 这里将元素自身位置与窗口视图进行比对
    return (pos.y > 0 && pos.y < windowHeight) || (pos.bottom > 0 && pos.bottom < windowHeight);
    }

判断元素是否滚动到底部

在业务中,我们为了提高渲染速度,优化用户体验,还有一个经常遇到的场景,那便是滚动到底部加载更多内容。

这里的判断逻辑其实和判断元素是否在可视区域相近,但是有时候我们为了提前加载数据,往往会给触底事件一个临界值。也就是说,让元素距离底部多少像素时,我们就视为已经触底了,这里只需入参临界值,然后在判断的时候,将临界值累加到窗口高度上即可

getWindowHeight() {
    var windowHeight = 0;
    if (document.compatMode === 'CSS1Compat') {
        windowHeight = document.documentElement.clientHeight;
    } else {
        windowHeight = document.body.clientHeight;
    }
    return windowHeight;
}

isViewEnd(ele, endNum = 0) {
    if (!ele) {
        return;
    }
    let windowHeight = getWindowHeight();
    let pos = ele.getBoundingClientRect();

    if (pos.bottom < windowHeight + endNum) {
        return true;
    }
    return false;
}

需要注意的是:我们上面的两个方法都是默认你的应用不是运行在ie浏览器下的,因为getBoundingClientRect方法对ie不友好

说在后面

如果在项目中还有遇到其他元素和视图相关的比较频繁的功能,欢迎留言,笔者有空一定会补充!