DOM-文档几何与滚动

当浏览器在窗口中渲染HTML文档时,它会创建文档的一个视觉表示,其中每个元素都有自己的位置和大小。有时候我们需要某个元素精确的几何位置,比如,要使用CSS动态把一个元素定位到某个常规定位的元素旁边,必须要先知道这个常规定位元素的位置。

也就意味着我们需要在基于树的抽象文档模型和基于几何坐标系的文档视图之间切换。

文档坐标与视口坐标

文档元素的位置以CSS像素度量,其中x坐标向右表示增大,y坐标向下表示增大。有两个点可以作为坐标系的原点:文档的左上角和显示文档视口(viewport)的左上角。在顶级窗口和标签页中,"视口"就是浏览器窗口中实际显示文档内容的区域。

如果文档比视口小,比如浏览器窗口可以完整的显示所有文档内容,或者文档没有被滚动过,那么文档左上角就位于视口左上角。但通常情况下,要实现两种坐标系的转换们都必须加上或减去滚动位移。

滚动

Element.scroll()方法 接收一个点的x和y坐标(文档坐标),并据以设置滚动条的位置。

当我们用window去调用时,那就是浏览器窗口的滚动条进行滚动。

xml 复制代码
<br>......<br> // <br>*100
<script>
    window.scrollTo(200, 200);
</script>

当我们使用元素去调用这个方法时,就是元素本身的滚动条进行滚动,比如<textarea>

xml 复制代码
<textarea name="" id="" cols="30" rows="10">
    helloworld
    // helloworld*100
    helloworld
</textarea>
<script>
    var oArea = document.getElementsByTagName('textarea')[0];
    oArea.scrollTo(200, 200);
</script>

如果一个元素没有滚动条,那我们需要给它设置overflow: scroll;,然后调用这个方法。

css 复制代码
div{
    width: 100px;
    height: 100px;
    border: 1px solid red;
    overflow: scroll;
}
xml 复制代码
<div>
    helloworld
    helloworld
    helloworld
    helloworld
    helloworld
    helloworld
</div>
<script>
    var oDiv = document.getElementsByTagName('div')[0];
    oDiv.scrollTo(50, 50);
</script>

Element.scrollBy()方法 和scrollTo()类似,但是它的参数是个相对值,会加在当前滚动位置上。

所以我们可以使用定时器实现自动滚动的效果。

javascript 复制代码
setInterval(function(){
    window.scrollBy(100, 100);
}, 1000);

视口尺寸

前面说过,浏览器窗口和一些HTML元素可以显示滚动的内容。我们有时候需要知道视口大小、内容大小和视口中内容的滚动位移。

对于浏览器而言,视口大小可以通过window.innerWidth/innerHeight属性获得。

window.innerWidth/innerHeight属性 获得浏览器窗口的水平/垂直尺寸(IE9的一些版本/IE8及以下不兼容)。

IE9/IE8及以下的写法如下,以下两种方法组合在一起可以解决IE浏览器中的兼容性问题,涉及怪异模式和标准模式。

  • 标准模式:document.documentElement.clientWidth/clientHeight
  • 怪异模式:document.body.clientWidth/clientHeigh

所以我们可以对以上方法进行封装,解决兼容性问题。

javascript 复制代码
// 获取可是窗口的尺寸
function getViewportSize(){
    console.log(document.compatMode);
    if(false && window.innerWidth){
        return {
            width: window.innerWidth,
            height: window.innerHeight
        }
    }else{
        if(document.compatMode === 'BackCompat'){
            return {
                width: document.body.clientWidth,
                height: document.body.clientHeight
            }
        }else{
            return {
                width: document.documentElement.clientWidth,
                height: document.documentElement.clientHeight
            }
        }
    }
}

文档尺寸与滚动

文档尺寸

document.documentElement.offsetwidth/offsetHeight属性 返回文档的宽度与高度,这个值是包含滚动区域的。

针对兼容性问题,有时也需要使用document.body.scrollWidth/Height属性。

javascript 复制代码
// 获取整个文档的尺寸
function getScrollSize(){
    if(document.body.scrollWidth){
        return {
            width: document.body.scrollWidth,
            height: document.body.scrollHeight
        }
    }else{
        return {
            width: document.documentElement.scrollWidth,
            height: document.documentElement.scrollHeight
        }
    }
}

文档滚动

当我们要获取文档的滚动距离时,看的不是滚动条的物理移动距离,而是要看页面移动的距离。因为考虑到可用性,滚动条的物理移动距离是按比例缩放。

window.pageXOffset/pageYoffset属性 获得页面移动的水平/垂直距离(IE9的一些版本/IE8及以下不兼容)。

xml 复制代码
<div style="height: 400px; border: 1px solid #000"></div>
<button>点击</button>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>

<script>
    var oBtn = document.getElementsByTagName('button')[0];

    oBtn.onclick = function(){
        window.scrollTo(0, 400);
        console.log(window.pageYOffset); // 400
    }
</script>

下面这张表是关于浏览器版本的兼容性的整理。

所以IE9的一些版本/IE8及以下版本的写法如下,以下两种方法组合在一起可以解决IE浏览器中的兼容性问题,涉及怪异模式和标准模式。

  • 标准模式:document.documentElement.scrollLeft/scrollTop
  • 怪异模式:document.body.scrollLfet/scrollTop

所以我们可以对以上方法进行封装,解决兼容性问题。

javascript 复制代码
// 获取滚动距离
function getScrollOffset(){
    if(window.pageXOffset){
        return {
            // 常规写法
            left: window.pageXOffset,
            top: window.pageYOffset
        }
    }else{
        return {
            // IE浏览器的写法
            left: document.body.scrollLeft + document.documentElement.scrollLeft,
            top: document.body.scrollTop + document.documentElement.scrollTop
        }
    }
}

还有一种不常见的写法window.scrollX/scrollY 属性。等同于 window.pageXOffset/pageYoffset

为了跨浏览器兼容性,请使用 window.pageXOffset/pageYoffset

元素尺寸、坐标与滚动

对于元素来说,它的尺寸和滚动要稍微复杂一点,多了一些属性。

元素尺寸

Element.offsetWidth/offsetHeight属性 返回指定元素可见宽度/高度,包含元素的内边距和边框。

Element.clientWidth/clientHeight属性 和offsetWidth/offsetHeight类似,但是不包含元素的边框。

Element.scrollWidth/scrollHeight属性 返回指定元素的内容区大小加上元素的内边距,再加上溢出内容的大小。在内容区没有溢出时,该属性等同于Element.clientWidth/clientHeight

css 复制代码
div{
    width: 500px;
    height: 500px;
    background-color: antiquewhite;
    border: 1px solid #000;
}
xml 复制代码
<div>

</div>
<script>
    var oDiv = document.getElementsByTagName('div')[0];
    console.log(oDiv.offsetHeight); // 502
    console.log(oDiv.clientHeight); // 500
    console.log(oDiv.scrollHeight); // 500
</script>

元素坐标

Element.offsetLeft/offsetTop属性 返回指定元素相对于文档或定位父元素的水平/垂直偏移量(元素的x和y坐标)。

Element.offsetParent属性 返回指定元素的定位父元素。

css 复制代码
div{
    width: 500px;
    height: 500px;
    margin-top: 200px;
    margin-left: 200px;
    background-color: antiquewhite;
    border: 1px solid #000;
}
xml 复制代码
    <div>

    </div>
    <script>
        var oDiv = document.getElementsByTagName('div')[0];
        console.log(oDiv.offsetTop); // 200
        console.log(oDiv.offsetLeft); // 208
    </script>

元素滚动

Element.scrollLeft/scrollTop属性 可以读取或设置元素滚动条的水平/垂直偏移量。

当滚动条滚到底时,满足等式 Element.offsetHeight = Element.scrollHeight - Element.scrollTop

在多数浏览器中,Element对象也跟window对象一样有scrollTo()方法和scrollBy()方法,但并非所有浏览器都支持。

相关推荐
小小小小宇4 分钟前
前端实现合并两个已排序链表
前端
yngsqq22 分钟前
netdxf—— CAD c#二次开发之(netDxf 处理 DXF 文件)
java·前端·c#
mrsk25 分钟前
🧙‍♂️ CSS中的结界术:BFC如何拯救你的布局混乱?
前端·css·面试
jonssonyan26 分钟前
我自建服务器部署了 Next.js 全栈项目
前端
A了LONE30 分钟前
h5的底部导航栏模板
java·前端·javascript
专注VB编程开发20年32 分钟前
各版本操作系统对.NET支持情况(250707更新)
开发语言·前端·ide·vscode·.net
Zsnoin能43 分钟前
AI + TailwindCSS快速搭建一个属于自己的TailwindCSS学习网站
前端·css
五号厂房43 分钟前
聊一聊Javascript 中 hasOwnProperty和in操作之间的区别
前端
轻语呢喃44 分钟前
JavaScript :事件循环机制的深度解析
javascript·后端
摆烂为不摆烂1 小时前
😁深入JS(六): 一文让你完全理解浏览器进程与线程
前端·javascript