DOM元素的scrollXXX与offsetXXX

374 阅读3分钟

这是我参与8月更文挑战的第21天,活动详情查看:8月更文挑战

问题起源

最近在做一个类似聊天界面的Web页面,如下图所示:

动画.gif

聊天窗口的特点是:

  1. 最新的消息总是在最下面:

这个特点很容易实现,只要我们将所有数据聊天消息列为数组Array,每次在数组Array尾部添加新消息即可:

....
    <message v-for="(m, index) in messages" :key="index"></message>

....

data() {
    return {
        messages: []
    }
},
methods: {
    addNewMessage(message) {
        messages.push(new_message)
    }
}


....
  1. 窗口总是默认显示在最下面。

这一点需要我们在页面加载时,以及每次有新消息产生时,滚动组件到底部,即总是显示最新的消息。

解决思路

在前几天的文章中,我们曾经碰到过类似的问题。 在文章“JavaScript控制页面滚动位置”中,我们通过Javascript达到控制其滚动位置的目的。

如图,我们做了一个简单的小窗口,内部又一个渐变色的滚动DOM:

动画.gif

上述样式的源码:

<!DOCTYPE html>
<title>滚动控制</title>
<script>
    window.onload=function() {
        console.log('加载完成')
    };
</script>
<body>
    <div id="outer" class="outer-box">
        <div id="inner" class="inner-box">
        </div>
    </div>
</body>
<style>
    .outer-box {
        height: 300px;
        width: 300px;
        overflow: auto;
        border: 1px solid red;
    }

    .inner-box {
        height: 800px;
        width: 100%;
        background: linear-gradient(white, black);
    }
    
</style>
</html>

我们通过在window.onload获取相关值的大小:

window.onload=function() {
        console.log('加载完成')
        const outer = document.getElementById("outer")
        console.log('outer.offsetHeight=' + outer.offsetHeight)
        console.log('outer.offsetTop=' + outer.offsetTop)
        console.log('outer.scrollHeight=' + outer.scrollHeight)
        console.log('outer.scrollTop=' + outer.scrollTop)
        console.log('outer.clientHeight=' + outer.clientHeight)
        console.log('outer.clientTop=' + outer.clientTop)
    };

执行结果:

image.png

我们一个定义一个定义的去拆分理解:

offsetXXX

offsetHeight

通过上述测试,我们大概了解到:offsetHeight等于两边的边框高度 + 元素高度。

MDN官方文档解释:

offsetHeight 是一个只读属性,它返回该元素的像素高度,高度包含该元素的垂直内边距和边框,且是一个整数。

offsetTop

为什么offsetTop等于8呢? MDN官方文档解释:

offsetTop 为只读属性,它返回当前元素相对于其 offsetParent 元素的顶部内边距的距离。

offsetParent这里可以理解为body元素。我们尝试打印出inner元素的offsetTop看一下:

image.png

scrollXXX

scrollHeight

上述打印结果,我们来看一下scrollHeight的释义:

outer.scrollHeight=800

scrollHeight 这个只读属性是一个元素内容高度的度量,包括由于溢出导致的视图中不可见内容。

scrollHeight 的值等于该元素在不使用滚动条的情况下为了适应视口中所用内容所需的最小高度。 没有垂直滚动条的情况下,scrollHeight值与元素视图填充所有内容所需要的最小值clientHeight相同。包括元素的padding,但不包括元素的border和margin。scrollHeight也包括 ::before 和 ::after这样的伪元素。

换句话说,scrollHeight就是子元素的整体高度。

scrollTop

这是目前为止,唯一的一个可读可写的属性。

这是目前为止,唯一的一个可读可写的属性。

这是目前为止,唯一的一个可读可写的属性。

scrollTop 属性可以获取或设置一个元素的内容垂直滚动的像素数。

一个元素的 scrollTop 值是这个元素的内容顶部(卷起来的)到它的视口可见内容(的顶部)的距离的度量。当一个元素的内容没有产生垂直方向的滚动条,那么它的 scrollTop 值为0

clientHeight、clientTop与滚动无关,不多说。

scrollTop的变化

动画.gif

可以看到当向下滑动时,scrollTop的值逐渐增大,其最大值为500。

解决问题

回到我们开始的问题,在页面加载时,需要让元素保持在底部,则需要设置DOMouterscrollTop值为(内容高度-框架高度)即可。

经过测试,当设置值超过500,即超过最大允许的scrollTop时,会将其设置为500,即如果想默认滑动到底部,而相关值又不太容易计算时,可以直接设置一个超大的值也可以达到目的。