zoukankan      html  css  js  c++  java
  • jacascript 偏移量offset、客户区client

    前言:这是笔者学习之后自己的理解与整理。如果有错误或者疑问的地方,请大家指正,我会持续更新!

    偏移量

      偏移量(offset dimension)是 javascript 中的一个重要的概念。涉及到偏移量的主要是offsetLeft、offsetTop、offsetHeight、offsetWidth这四个属性,还有一个偏移参照,定位父级 offsetParent。

     

    定位父级

      定位父级 offsetParent 的意思是:与当前元素最近的拥有 position 不等于 static 的父级元素,主要分为下列几种情况:

    • 元素自身有 fixed 固定定位时,我们知道固定定位的元素相对于视口进行定位,此时没有定位父级,offsetParent的结果为 null;firefox浏览器有兼容性问题,返回body
    • 元素自身无 fixed 定位,且父级元素都没有 position 定位过,offsetParent 的结果为<body>;
    • 元素自身无 fixed 定位,且父级元素存在拥有 position 不等于 static 的元素,offsetParent 的结果为就是这个元素;
    • <body>元素自身的 parentNode 是null;
            <div id="wrapper" style="position: fixed;">
                <div id="testa"></div>
            </div>
            
            <div id="outer" style="position: relative;">
                <div id="inner" style="position: absolute;">
                    <div id="testb"></div>
                </div>
            </div>
            
            <div id="testc"></div>
            <script type="text/javascript">
                var oWrapper = document.getElementById('wrapper');
                var oTestA = document.getElementById('testa');
                
                //元素自身有 fixed 固定定位时,offsetParent的结果为 null;firefox浏览器返回body
                console.log(oWrapper.offsetParent);//null
                //元素自身无 fixed 定位,且父级元素存在拥有 position 不等于 static 的元素,offsetParent 的结果为就是这个元素;
                console.log(oTestA.offsetParent);//<div id="wrapper" style="position: fixed;">...</div>
                
                var oOutter = document.getElementById('outer');
                var oInner = document.getElementById('inner');
                var oTestB = document.getElementById('testb');
                
                //元素自身无 fixed 定位,且父级元素都没有 position 定位过,offsetParent 的结果为<body>;
                console.log(oOutter.offsetParent);//body
                //元素自身无 fixed 定位,且父级元素存在拥有 position 不等于 static 的元素,offsetParent 的结果为就是这个元素;
                console.log(oInner.offsetParent);//<div id="outer" style="position: relative;">...</div>
                console.log(oTestB.offsetParent);//<div id="inner" style="position: absolute;">...</div>
                
                var oTestC = document.getElementById('testc');
                //元素自身无 fixed 定位,且父级元素都没有 position 定位过,offsetParent 的结果为<body>;
                console.log(oTestC.offsetParent);//body
                
                var oBody = document.getElementsByTagName('body')[0];
                //<body>元素自身的 parentNode 是null;
                console.log(oBody.offsetParent);//null
            </script>

    偏移量大小

      偏移量共包括 offsetWidth、offsetHeight、offsetLeft、offsetTop 这四个属性;

    offsetWidth

      offsetWidth 表示元素在水平方向上占用的空间大小(不包括margin),无单位(以像素px计);

      offsetWidth = border + width + padding

    offsetHeight

      offsetHeight 表示元素在垂直方向上占用的空间大小(不包括margin),无单位(以像素px计);

      offsetHeight = border + Height+ padding

      如果存在滚动条,offsetWidth/offsetHeight 也包括滚动条的距离;

      浏览器一般把垂直滚动条的宽度从width宽度中移出,把水平滚动条的高度从height高度中移出,则滚动条宽度为17px,width 宽度和 height 高度为剩下的83px,

      IE8及以下浏览器将垂直滚动条的宽度计算在 width 宽度和 height 高度中;

    offsetTop 与 offsetLeft

      offsetTop/offsetLeft 表示当前元素与 offsetParent 元素的 border 之间的像素距离(当前元素的 margin + offsetParent 元素的 padding);

      如果当前元素设置了 position 与 left/top ,那么 offsetTop/offsetLeft = 当前元素的left/top + 当前元素的margin

      position 与 left/right/top/bottom 方位属性配合,显示的是当前元素的 margin 外侧到 offsetParent 元素的 border 内侧之间的距离

      如果父级都没有定位则以 body 为准

      IE7及以下浏览器在 offsetTop 属性的处理上存在bug:

    1. 若父级设置 position: relative,则在IE7及以下浏览器下,offsetTop 值为 offsetParent 元素的 padding-bottom 值;
    2. 若父级设置 position: aboslute(或其他触发 haslayout 的条件),offsetTop 值为 offsetParent 元素的 padding-bottom 值和当前元素的 margin-top 值的较大值;
            <style type="text/css">
                *{padding: 0;margin: 0;}
                #wrapper{
                    position: relative;
                    width: 400px;
                    height: 400px;
                    padding: 30px;
                    border-width: 10px;
                    margin: 20px;
                    border-color: #ff0;
                    border-style: solid;
                    background-color: #333;
                }
                #test{
                    position: absolute;
                    left: 100px;
                    top: 100px;
                    width: 100px;
                    height: 150px;
                    padding: 20px 30px 40px 50px;/*上右下左*/
                    border-width: 50px 30px 40px 20px;
                    margin: 30px 50px 20px 40px;
                    border-color: #f0f;
                    border-style: solid;
                    background-color: #0ff;
                }
            </style>
            <div id="wrapper">
                <div id="test"></div>
            </div> 
            <script>
                var oTest= document.getElementById('test');
                
                //offsetWidth = border-left + border-right + width + padding-left + padding-right
                //230=30+20+100+30+50
                console.log(oTest.offsetWidth);//230
                
                //offsetHeight = border-top + border-bottom + width + padding-top + padding-bottom 
                //300=50+40+150+20+40
                console.log(oTest.offsetHeight);//300
                
                //offsetTop 表示元素的上外边距至 offsetParent 元素的上内边距之间的像素距离;
                //60=30+100
                console.log(oTest.offsetTop);//  130
                
                //offsetLeft 表示元素的左外边距至 offsetParent 元素的左内边距之间的像素距离;
                //70=40+100
                console.log(oTest.offsetLeft);//  140
            </script>

    页面偏移

      要知道某个元素在页面上的偏移量,将这个元素的 offsetLeft/offsetTop 与其 offsetParent 的 offsetLeft/offsetTop 相加,并加上 offsetParent 的相应方向的边框border,如此循环直到根元素,就可以得到元素到页面的偏移量;

      在默认情况下,IE8及以下浏览器下如果使用 currentStyle() 方法获取<html>和<body>(甚至普通div元素)的边框宽度都是medium,而如果使用 clientLeft/clientTop 获取边框宽度,则是实际的数值;

            <style type="text/css">
                *{padding: 0;margin: 0;}
                #wrapper{
                    position: relative;
                    width: 400px;
                    height: 400px;
                    padding: 30px;
                    border-width: 10px;
                    margin: 20px;
                    border-color: #ff0;
                    border-style: solid;
                    background-color: #333;
                }
                #test{
                    position: absolute;
                    width: 100px;
                    height: 150px;
                    padding: 20px 30px 40px 50px;/*上右下左*/
                    border-width: 50px 30px 40px 20px;
                    margin: 30px 50px 20px 40px;
                    border-color: #f0f;
                    border-style: solid;
                    background-color: #0ff;
                }
            </style>
            <div id="wrapper">
                <div id="test"></div>
            </div> 
            <script>
                function getElementLeft(obj){
                    var actualLeft = obj.offsetLeft;
                    var current = obj.offsetParent;
                    while(current != null){
                        actualLeft += current.offsetLeft + current.clientLeft;
                        current = current.offsetParent;
                    }
                    return actualLeft + 'px';
                }
                function getElementTop(obj){
                    var actualTop = obj.offsetTop;
                    var current = obj.offsetParent;
                    while(current != null){
                        actualTop += current.offsetTop + current.clientTop;
                        current = current.offsetParent;
                    }
                    return actualTop + 'px';
                }
            
                var oWrapper= document.getElementById('wrapper');
                var oTest= document.getElementById('test');
                
                console.log(oWrapper.offsetLeft);//20
                console.log(oTest.offsetLeft);//70
                //100=70+20+10
                console.log(getElementLeft(oTest));//100px
                
                console.log(oWrapper.offsetTop);//20
                console.log(oTest.offsetTop);//60
                //90=60+20+10
                console.log(getElementTop(oTest));//90px
            </script>

    客户区

      客户区大小 client 指的是元素内容及其内边距所占据的空间大小;

      盒子调用,指盒子本身;body/html调用,指可视区域大小。

      clientWidth 属性返回元素节点的客户区宽度;clientWidth = padding + width

      clientHeight 属性返回元素节点的客户区高度;clientHeight = padding + height

      滚动条宽度不计算在内;

      clientLeft 属性返回左边框的宽度

      clientTop 属性返回上边框的宽度

      如果 display 为 inline 时,clientHeight、clientWidth、clientLeft 和 clientTop 属性都返回0;

            <div id="divTest" style=" 100px;height: 100px;padding: 10px;margin: 10px;border: 1px solid black;"></div>
            <span id="spanTest" style=" 100px;height: 100px;padding: 10px;margin: 10px;border: 1px solid black;"></span>
            <script>
                var oDivTest = document.getElementById('divTest');
                var oSpanTest = document.getElementById('spanTest');
                //120(10+100+10)
                console.log(oDivTest.clientHeight);//120
                console.log(oDivTest.clientWidth);//120
                
                console.log(oDivTest.clientLeft);//1
                console.log(oDivTest.clientTop);//1
                
                //如果 display 为inline 时,clientHeight、clientWidth、clientLeft和clientTop属性属性都返回0
                console.log(oSpanTest.clientHeight);//0
                console.log(oSpanTest.clientWidth);//0
                console.log(oSpanTest.clientLeft);//0
                console.log(oSpanTest.clientTop);//0
            </script>

    页面大小

      常用 document.documentElement.clientWidth/clientHeight 属性来表示可视区域页面大小(不包含滚动条宽度);

      另一个对常用的表示页面大小的属性是 window.innerHeight/innerWidth 属性(包含滚动条宽度);

      innerHeight 和 innerWidth 表示的是浏览器窗口大小减去菜单栏、地址栏等剩余的页面尺寸,由于滚动条是属于页面的,所以包含滚动条;

      IE8及以下浏览器不支持 innerHeight 和 innerWidth 属性;

      如果没有滚动条(页面最大化),这两类属性在电脑端表示同样的值,但是却表示不同的含义。在移动端,innerWidth 和 innerHeight 表示的是视觉视口,即用户正在看到的网站的区域;而document.documentElement.clientWidth 和 clientHeight 表示的是布局视口,指CSS布局的尺寸。

        <body style="overflow:scroll">
            <script>
            //1349=1366-17
            console.log(document.documentElement.clientWidth);
            //621=638-17
            console.log(document.documentElement.clientHeight);
            
            console.log(window.innerWidth);//1366
            console.log(window.innerHeight);//638
            </script>
        </body>

    clientX 和 clientY

      event 对象是 JavaScript 中最重要的对象之一,它代表了各种事件的状态,在各种事件的事件处理中经常用到,比如键盘活动、鼠标活动等等;

      clientX,鼠标指针位置相对于窗口客户区域的 x 坐标,(event调用); 其中客户区域不包括窗口自身的控件和滚动条;

      clientY,鼠标指针位置相对于窗口客户区域的 y 坐标,(event调用); 其中客户区域不包括窗口自身的控件和滚动条;

      offsetX,鼠标指针位置相对于触发事件的对象的 x 坐标;

      offsetY,鼠标指针位置相对于触发事件的对象的 y 坐标;

      screenX,鼠标指针位置相对于用户屏幕的 x 坐标;

      screenY,鼠标指针位置相对于用户屏幕的 y 坐标;

        <style type="text/css">
            *{padding: 0;margin: 0;}
            body{height: 1000px;}
            p{height: 300px;width: 300px;background: #f0f;}
        </style>
        <body>
            <p>请在文档中点击。控制台会提示出鼠标指针的 x 和 y 坐标。</p>
            
            <script type="text/javascript">
                var oBody = document.getElementsByTagName('body')[0];
                var oP = document.getElementsByTagName('p')[0];
                oBody.onmousedown = function(ev){
                    ev = ev || event;
                    
                    clX = ev.clientX;
                    clY = ev.clientY;
                    console.log("鼠标clientX的值是: " + clX + ", 鼠标clientY的值是: " + clY);
                    
                    scX = ev.screenX;
                    scY = ev.screenY;
                    console.log("鼠标screenX的值是: " + scX + ", 鼠标screenY的值是: " + scY);
                }
                
                oP.onmousedown = function(ev){
                    ev = ev || event;
                    
                    ofX = ev.offsetX;
                    ofY = ev.offsetY;
                    console.log("鼠标相对于p标签的offsetX的值是: " + ofX + ", 鼠标相对于p标签的offsetY的值是: " + ofY);
                }
            </script>
        </body>
  • 相关阅读:
    WPF进阶技巧和实战03-控件(3-文本控件及列表控件)
    WPF进阶技巧和实战08-依赖属性与绑定03
    WPF进阶技巧和实战08-依赖属性与绑定02
    WPF进阶技巧和实战08-依赖属性与绑定01
    WPF进阶技巧和实战07--自定义元素02
    WPF进阶技巧和实战07--自定义元素01
    Codeforces Round #730 Div. 2
    Codeforces Round #701 Div. 2
    Codeforces Round #700 Div. 2
    Codeforces Round #699 Div. 2
  • 原文地址:https://www.cnblogs.com/sspeng/p/6736699.html
Copyright © 2011-2022 走看看