牛骨文教育服务平台(让学习变的简单)
博文笔记

js运动-offsetWidth和offsetHeight引发的血案

创建时间:2015-05-16 投稿人: 浏览次数:4257

之前说的js运动不管是单物体运动,多物体运动,还是缓冲运动。在获取元素自身宽,高的时候用的都是offsetWidth,offsetHeight,但是这会引发一些麻烦!!因为在js中offsetWidth,offsetHeight获取的不仅仅是元素样式中定义的width,height还包括给元素设置的border和padding的值

看看下面的测试例子:

<style>
        #div1{
            width:200px;height: 100px;
            background: green;
            /*border: 5px solid #c00;
            padding: 5px;*/
        }
</style>

<body>
<div id="div1" onclick="test();"></div>
<script>
    function test() {
        var oDiv = document.getElementById("div1");
        alert("offsetWidth 获取的值是:"+oDiv.offsetWidth);
        alert("offsetWidth 获取的值是:"+oDiv.offsetHeight);
    }
</script>
</body>

不加border和padding的时候,弹出的值都是200和100,加了border和padding结果就成了220和120,所以offsetWidth = width + border + padding


明白了上面的问题,接下来看看offsetWidth/Height在会带来哪些麻烦??

改一下上面的案例,当点击div的时候,让div宽度逐渐变窄

<script>
    function test() {
        var oDiv = document.getElementById("div1");
        setInterval(function () {
           oDiv.style.width = oDiv.offsetWidth-1 + "px";
        },30);
    }
</script>

如上图所示:当不加boder和padding的时候,点击div发现很正常div逐渐变窄



当我们给div加了边框或者padding的时候,神器的事情发生了,为了看的清楚给div了2px的黄色边框,当我们点击div的时候div的宽度并没有变窄,反而越变越宽???这是为什么那??仔细分析

当我们点击div的时候oDiv.offsetWidth获取的值是204,然后oDiv.style.width = 204-1即203
加上左右2px的border就成了205,所以30毫秒后,oDiv.offsetWidth取得205,然后减1变成204,再赋给oDiv.style.width,接着在加上左右2px的border就成了206,如此循环下去,导致div的宽就越变越大了。


那如何解决这个问题那??

我们只要获取div自身的宽度width,而不要包括(border和padding的宽),这样问题就解决了,那怎么获取div自身的宽度同时又不包括border和padding的宽那??不用offsetWidth来获取。

在DOM标准的API里有这样一个方法getComputedStyle,通过这个方法可以可以获取到当前对象样式规则信息,getComputedStyle(obj,null).width,就能获取到对象自身的宽度(不包括border和padding),但是IE不支持此方法,IE需要用currentStyle,不同于全局方法getComputedStyle,它是作为DOM元素属性存在的,如:obj.currentStyle.width,在IE中就获取到对象自身的宽度了.

在如:getComputedStyle(obj,null).paddingLeft和 obj.currentStyle.paddingLeft就能获取到对象的左内边距;
      getComputedStyle(obj,null).borderWidth和 obj.currentStyle.borderWidtht就能获取到对象上下左右边框的宽度。

关于更加详细可以获取和操作哪些属性参考:http://www.jb51.net/shouce/dhtml/objects/currentStyle.html


注意一点:如果要获取当前对象的颜色信息,currentStyle返回的是16进制的"#ffffff",而getComputedStyle返回的是rgb(255,255,255) 

<script>
    function test() {
        var oDiv = document.getElementById("div1");
        alert("getComputedStyle获取的宽度是:" + getComputedStyle(oDiv,false).width);
    }
</script>

测试一下,尽管我们添加了2px的border,但是弹出的结果任然是200px


 

注意:getComputedStyle获取的结果是字符串,需要用 parseInt( )转换一下;然后将之前程序中的offsetWidth换成getComputedStyle之后,在点击div就不再变宽了,而是正常的变窄了

<script>
    function test() {
        var oDiv = document.getElementById("div1");
        setInterval(function () {
           oDiv.style.width = parseInt(getComputedStyle(oDiv,false).width)-1 + "px";
        },30);
    }
</script>

把之前多物体运动中通过offsetWidht获取物体的宽度,改成getComputedStyle

为了方便,且浏览器兼容,我们封装一个函数getStyle

function getStyle(obj,attr){
            /*if(obj.currentStyle){
                return obj.currentStyle[attr];// ie
            }else{
                return getComputedStyle(obj,false)[attr];
            }*/
            return getComputedStyle?getComputedStyle(obj,false)[attr]: obj.currentStyle[attr];
        }

完整代码:

<ul>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
</ul>

样式:

<style>
        ul{list-style: none;}
        ul li{
            margin: 10px;
            width: 200px;height: 50px;
            border: 2px solid #c00;
            background: lightblue;
        }
</style>

<script>
        window.onload = function(){
            var liTags = document.getElementsByTagName("li");
            for(var i=0;i<liTags.length;i++){
                 liTags[i].timer = null;// 给每个li都添加一个timer
                 liTags[i].onmouseover = function () {
                    startMove(this,400);
                 }
                 liTags[i].onmouseout = function () {
                    startMove(this,200);
                 }
            }
        }
        function getStyle(obj,attr){
            return getComputedStyle ? getComputedStyle(obj,false)[attr] : obj.currentStyle[attr];
        }
        function startMove(obj,iTarget) {
            clearInterval(obj.timer);
            obj.timer = setInterval(function () {
                var objWidth = parseInt(getStyle(obj,"width"));//因为是通过[]调用属性,所以width必须加单引号
               // var iSpeed = (iTarget -obj.offsetWidth)/10;
               // 因为objWidth存放的就是当前对象的宽,所以直接写objWidth而不是obj.objWidth
                var iSpeed = (iTarget -objWidth)/10;
                    iSpeed = iSpeed>0 ?Math.ceil(iSpeed):Math.floor(iSpeed);
                if(objWidth == iTarget){
                    clearInterval(obj.timer);
                }else{
                    obj.style.width =  objWidth+iSpeed+"px";
                }
            },30);

        }
</script>


声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。