JS 盒子模型

2,497 阅读7分钟

JS盒子模型13个属性

  • 在JS中通过相关的属性可以获取(设置)元素的样式信息,这些属性就是盒子模型属性,基本上都是有关样式的
  • CSS中内容的宽高:不含padding/border。设置box-sizing:border-bor,宽高代指是整个盒子的宽高(内容+padding+border)
  • 在JS盒子模型13个属性中,只有scrollTop/scrollLeft是“可读写”属性,其余都是“只读”属性

client

  • clientTop:上边框
  • clientLeft:左边框
  • clientWidth:内容宽度 + padding(左右),是否溢出不影响,是否设置overflow:hedden无关
  • clientHeight:内容高度 + padding(上下),是否溢出不影响,是否设置overflow:hedden无关

offset

  • offsetTop:上偏移值:元素上边框距离 父级参照物上边的距离 (x轴)
  • offsetLeft:左偏移值:元素左边框距离 父级参照物左边距离(y轴)
  • offstWidth:内容宽度 + padding(左右) + border(左右)
  • offsetHeight:内容高度 + padding(上下) + border(上下)
  • offsetParent:父级参照物默认是body,是可以修改的 通过position:absolute/relative/fixed

scroll

  • scrollTop:纵向卷去距离
  • scrollLeft:横向卷去距离
  • scrollWidth:真实内容的宽度,溢出时只含padding(左),不溢出+padding(左右)。是否设置overflow:hidden不影响
  • scrollHeight:真实内容的高度,溢出时致函padding(上),不溢出+padding(上下)。是否设置overflow:hidden不影响

兼容写法:前面为true执行,为false时执行后面

document.documentElement.clientWidth||document.body.clientWidth 
document.doucmentElement.clientHeigth||docuemnt.body.clientHeight

获取当前页面的真实宽高(包含溢出的部分)

document.documentElement.scrollWidth||document.body.scrollWidth 
document.doucmentElement.scrollHeigth||docuemnt.body.scrollHeight

需求任意元素距离body的便宜(不管参照物)

不管父级参照物是谁,都要获取当前元素距离Body的偏移量(左偏移和上偏移),不能修改既定的样式,不能基于position方式改它的参照物了

1、首先获取当前元素的左偏移
2、在这个基础上累加
A:父级参照物的边框
B:父级参照物的偏移
累加完父级,在找父级的父级(A),加上A的左边框和左偏移...,一直加到父级参照物是body位置

  function offset(ele) {
    let left = ele.offsetLeft; // 左偏移
    let top = ele.offsetTop; // 上偏移
    let parent = ele.offsetParent; //父级参照物

    // 只要找到的父级参照物不是body 就继续往上查找(一直循环下去 一直到body为止)
    //parent为true并转小写,不等于body时累计,等于body时不成立
    while (parent && parent.nodeName.toLowerCase() !== "body") {
      left += parent.offsetLeft + parent.clientLeft;
      top += parent.offsetTop + parent.clientTop;
      parent = parent.offsetParent;
    }
    return {
      left,
      top
    }
  }

通过JS盒模型属性获取值的特点

  • 1、获取的都是数字不带单位
  • 2、获取的都是整数,不会出现小数,一般都会四舍五入,尤其是获取的偏移量
  • 3、获取的结果都是复合样式值,好几个元素样式组合在一起的值,如果只想获取单一样式值(例如:只想获取padding),盒子的模型属性获取不了(这不能说没有用,真实项目中,有时候我们就是需要获取组合的值来完成一些操作)

获取元素具体的某个样式值

  • 1、元素.style.xxx操作获取。

弊端:只能获取所有写在元素行内上的样式,不写在行内上,不管你写没写都获取不到返回空,真实项目中我们很少会把样式写在行内上

  • 2、获取当前元素所有经过浏览器计算的样式

经过计算的样式:只要当前元素可以在页面中呈现(或者浏览器渲染它了),那么它的样式都是被计算过的
不管当前样式写在哪
不管你是否写了(浏览器会给元素设置一些默认样式)

getAttribute获取属性值

  • getAttribute()方法不能通过document对象调用,只能通过一个元素节点对象调用它。
<p title='1'>djdjdj</p>
var text=document.getElementsByTagName("p")
    for (var i=0;i<text.length;i++){
        alert(text[i].getAttribute("title"));//无返回null,有返回属性值
    }

setAttribute设置修改添加属性名属性值

  • setAttribute()方法只能通过元素节点对象调用的函数,需要传递两个参数
<p title='1'>djdjdj</p>

var text=document.getElementsByTagName("p");
        text[0].setAttribute("title",'5');//行间属性有则是修改,无则是添加

默认JS封装CSS方法

公共方法库:项目中常用的一些方法,封装在这里(使用高级单例模式,把需要用的方法return暴露出去)

let utils = (function () {
    //获取元素的样式
    let getCss = function (curEle, attr) {
        if (typeof window.getComputedStyle === 'undefined') {
            //当前浏览器不兼容getComputedStyle,return,停止执行
            return;
        }
        //抛出一个错误(语法错误),让浏览器崩溃,不在继续执行JS
        throw new SyntaxError('您的浏览器版本过低,请升级到最新版本,谢谢配合')
        let val = window.getComputedStyle(curEle, null)[attr];
        reg = /^-?\d+(\.\d+)(px|rem|em|pt)$/i;
        reg.test(val) ? val = parseFloat(val) : null;

        return val;
    };

    //设置元素的样式
    let setCss = function (curEle, attr, value) {
        //如果需要考虑IE6~8兼容
        //1、透明度这个样式在低版本浏览器中不是使用opacity,而是filter(我们两套都要设置)
        //2、如果传递进来的value值没有带单位,我们根据情况设置px单位
        //3、某些样式属性才会加单位:width/height/padding(4个方向)/margin(4个方向)/font-size/top/left/bottom/right...)。用户自己传递的value值中是没有单位的
        //    if(attr==='opacity'){
        //    curEle.style.opacity=value;
        //    curEle.style.filter=`alpha(opacity=${value*100})`;
        //    return;}
        if (!isNaN(value)) {
            //isNaN检测的结果是false:说明value是纯数字没单位,取反后为true执行块级作用域
            let reg = /^(width|height|fontSize|((margin|padding)?(top|left|right|bottom)?))$/i;
            reg.test(attr) ? value += 'px' : null;
        }
        curEle['style'][attr] = value;
    };

    //批量设置元素样式
    let setGroupCss = function (curEle, options = {}) {
        //遍历传递的options,有多少键值对,就循环多少次,每一次都调取setCss方法逐一设置即可
        for (let attr in options) {
            if (!options.hasOwnProperty(attr))break;
            //options:传递进来的需要修改样式对象(集合)
            //attr:每一次遍历到的集合中的某一项(要操作的样式属性名)
            //options[attr]:传递的要操作的样式属性值
            setCss(curEle, attr, options[attr]);
        }
    };

    //CSS操作汇总
    let CSS = function (...arg) {
        let len = arg.length;
        let fn = getCss;
        len >= 3 ? fn = setCss : null;
        len === 2 && (arg[1] instanceof Object) ? fn = setGroupCss : null;
        return fn(...arg);
    };

    //把需要用的方法return暴露出去
    return {
        CSS //在ES6中直接这样写相当于CSS:CSS
}
})();

offsetParent/offsetTop/offsetLeft

  • offsetTop/offsetLeft:获取当前盒子距离其父级参照物的偏移量(上偏移/左偏移)
  • offsetparent:当前盒子的父级参照物
  • 参照物:同一个平面中(同一层级中),元素的父级参照物和结构没有必然联系,默认他们的父级参照物都是body(当前平面最外层的盒子),body的父级参照物是null
  • 参照物可以改变:构建出不同的平面即可,设置定位后元素脱离文档流,使用Zindex,但是这个属性只对定位有作用,所以改变元素的定位(position:relative/absolute/fixed),可以改变其父级参照物
        <div id="outer">
            <div id="inner">
                <div id="center"></div>
            </div>    
        </div>
        outer.offsetParent;//body
        inner.offsetParent;//body
        center.offsetParent;//body
        
        
        utils.css(outer,{
            position:'relative';//把outer脱离原有的平面,独立出一个新的平面,后代元素的父级参照物都会以它为参考
        });
        console.log(outer.offsetParent);//body
        console.log(inner.offsetParent);//outer
        console.log(center.offsetParent);//outer
        
        
        utils.css(inner,{
            position:'relative';
        })
        console.log(outer.offsetParent);//body
        console.log(inner.offsetParent);//outer
        console.log(center.offsetParent);//inner
        console.log(document.body.offsetParent);//null

offsetTop/offsetLeft

  • offsetTop/offsetLeft:获取当前盒子距离其父级参照物的偏移量(上偏移/左偏移),当前盒子的外边框开始~父级参照物的内边框
        <div id="outer">
            <div id="inner">
                <div id="center"></div>
            </div>    
        </div>
  
        utils.css(outer,{
            position:'relative';////把outer脱离原有的平面,独立出一个新的平面,后代元素的父级参照物都会以它为参考
        });
        
        console.log(center.offsetLeft)//center的外边框开始~outer的内边框值(outer是父级参照,因为设置了定位后独立了一个新的平面)
        console.log(inner.offsetLeft)//inner的外边框开始~outer的内边框值
        cnosole.log(outer.offsetLeft)//outer的外边框开始~body的内边框值,因为它的参照物是body

scrollTop/scrollLeft

  • scrollTop/scrollLeft:滚动条卷去的宽度和高度
  • 最小卷去值:0
  • 最大卷去值:真实页面的高度减去-屏幕的高度
  • document.doucmentElement.scrollHeight-document.documentElemetn.clientHeight
  • 操作浏览器的盒子模型属性,我们一般都要写两套,用来兼容各种模式下的浏览器
    //操作浏览器盒子模型属性的,现在基本用不上
    let winHandle=function(attr,value){
        if(typeof value!=='undefined'){
            //设置盒子模型属性值:scrollTop/scrollLeft
            document.documentElement[attr]=value;
            document.body[attr]=value;
            return;
        }
        return document.documentElement[attr]||document.body[attr];
    };