DOM盒子模型(28)

 JS盒子模型属性

 * JS盒子模型属性

 *   =>在JS中通过相关的属性可以获取(设置)元素的样式信息,这些属性就是盒子模型属性(基本上都是有关于样式的)

 *

 *   client

 *      top

 *      left

 *      width

 *      height

 *

 *   offset

 *      top

 *      left

 *      width

 *      height

 *      parent

 *

 *   scroll

 *      top

 *      left

 *      width

 *      height

 //=>clientTop/Left/Width/Height

//1.clientWidth & clientHeight:获取当前元素可视区域的宽高(内容的宽高+左右/上下PADDING)

//=>和内容是否有溢出无关(和是否设置了OVERFLOW:HIDDEN也无关),就是我们自己设定的内容的宽高+PADDING

//=>不设置高度则按照撑开的计算

//=>获取当前页面一屏幕(可视区域)的宽度和高度

// document.documentElement.clientWidth || document.body.clientWidth

// document.documentElement.clientHeight || document.body.clientHeight

//2.clientTop & clientLeft:获取(上/左)边框的宽度

//3.offsetWidth & offsetHeight:在client的基础上加上border(和内容是否溢出也没有关系)

//4、scrollWidth & scrollHeight:真实内容的宽高(不一定是自己设定的值,因为可能会存在内容溢出,有内容溢出的情况下,需要把溢出的内容也算上)+ 左/上PADDING,而且是一个约等于的值 (没有内容溢出和CLIENT一样)

//=>在不同浏览器中,或者是否设置了OVERFLOW:HIDDEN都会对最后的结果产生影响,所以这个值仅仅做参考,属于约等于的值

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

// document.documentElement.scrollWidth || document.body.scrollWidth

// document.documentElement.scrollHeight || document.body.scrollHeight

 获取元素的具体样式

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

//1.获取的都是数字不带单位

//2.获取的都是整数,不会出现小数(一般都会四舍五入,尤其是获取的 偏移量)

//3.获取的结果都是复合样式值(好几个元素的样式组合在一起的值),如果只想获取单一样式值(例如:只想获取PADDING),我们的盒子模型属性就操作不了了(这不能说没有用,真实项目中,有时候我们就是需要获取组合的值来完成一些操作)

//===========[获取元素具体的某个样式值]

//1.[元素].style.xxx 操作获取

//> 只能获取所有写在元素行内上的样式(不写在行内上,不管你写没写都获取不到,真实项目中我们很少会把样式写在行内上)

//=>outer.style.width =>'' (width是写在样式表中的)

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

//> 经过计算的样式:只要当前元素可以在页面中呈现(或者浏览器渲染它了),那么它的样式都是被计算过的

//=>不管当前样式写在哪

//=>不管你是否写了(浏览器会给元素设置一些默认样式)

/*

 * 标准浏览器(IE9+)

 *   window.getComputedStyle([元素],[伪类,一般都写null]) 获取到当前元素所有被浏览器计算过的样式(对象)

 *

 * IE6~8

 *   [元素].currentStyle 获取经过计算的样式

 */

/*
 * getCss:获取当前元素某一个样式属性值
 *
 * @param
 *    curEle[object]:当前要操作的元素
 *    attr[string]:当前要获取的样式属性名
 *
 * @return
 *    获取的样式属性值
 */
let getCss = function getCss(curEle, attr) {
    if ('getComputedStyle' in window) {
        let val = window.getComputedStyle(curEle, null)[attr];
        //=>把获取的结果去除单位(不是所有的值都能去单位的,例如:display\一些复合值都去不掉单位),只有符合 数字+单位 这种模式的结果才能基于PARSE-FLOAT去单位
        let reg = /^-?\d+(\.\d+)?(px|rem|em|pt)?$/i;
        reg.test(val) ? val = parseFloat(val) : null;
        return val;
    }
    //=>throw new SyntaxError:抛出一个错误(语法错误),让浏览器崩溃,不在继续执行JS
    throw new SyntaxError('您的浏览器版本过低,请升级到最新版本,谢谢配合!!');
};
console.log(getCss(outer, 'width'));

封装SET-CSS设置元素的样式

//=>设置当前元素的某一个具体样式的属性值
//JS中给元素设置样式只有两种
//1.设置元素的样式类名(前提:样式类及对应的样式已经处理完成)
//2.通过行内样式设置 xxx.style.xxx=xxx
let setCss = function (curEle, attr, value) {
    /*
     * 细节处理
     *   1.如果需要考虑IE6~8兼容,透明度这个样式在低版本浏览器中不是使用opacity,而是filter(我们两套都要设置)
     *   2.如果传递进来的VALUE值没有带单位,我们根据情况设置PX单位
     *     ->某些样式属性才会加单位:WIDTH/HEIGHT/PADDING(LEFT...)/MARGIN(LEFT...)/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)) {
        //=>IS-NaN检测的结果是FALSE:说明VALUE是纯数字没单位
        let reg = /^(width|height|fontSize|((margin|padding)?(top|left|right|bottom)?))$/i;
        reg.test(attr) ? value += 'px' : null;
    }
    curEle['style'][attr] = value;
};

封装SET-GROUP-CSS批量设置元素的样式

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

FOR-IN循环

/*
 * FOR-IN循环
 *   =>遍历一个对象中的键值对的,有多少组键值对,我们就遍历多少次
 */
// let obj = {name: 'xxx', age: 27, 0: 0, sex: 0, score: 100, 1: 1};

/*for (let key in obj) {
    // console.log(key);//=>KEY存储的是每一次循环获取的属性名
    // console.log(obj[key]);//=>每一次循环基于KEY获取属性值

    // if(key==='age'){
    //     break;  也支持BREAK和CONTINUE等关键词
    // }
    // console.log(key);
}*/

/*//=>FOR-IN遍历的时候有自己的顺序:先遍历数字属性名(按照小->大),再遍历字符串属性名(按照书写顺序)
for (let attr in obj) {
    console.log(attr);//=>0 1 name age sex score
}*/

/*//=>obj.__proto__===Object.prototype : obj是Object这个类的一个实例
//=>大括号中的是OBJ的私有属性,Object.prototype上的是OBJ公有属性
Object.prototype.bbbb = 1000;
for (let key in obj) {
    //=>FOR-IN循环只遍历当前对象可枚举(可遍历)的属性
    //1.对象的私有属性(自己写的)是可枚举的
    //2.浏览器内置的属性一般都是不可枚举的
    //3.自己在类的原型上设置的属性也是可枚举的,FOR-IN循环的时候也会被遍历出来(一般情况下我们是不想遍历到原型上的公有属性的)
    if (obj.hasOwnProperty(key)) {//=>一般使用FOR-IN在遍历对象的时候,我们加一个私有属性的验证,只有是私有的属性,我们才做操作
        console.log(key);
    }
}*/

封装UTILS库实现CSS方法统一操作样式

//=>CSS:集合GET/SET/SET-GROUP为一体的方法
let css = function (...arg) {
    //=>ARG:传递的实参集合
    let len = arg.length;
    if (len >= 3) {
        //=>单一设置:SET-CSS
        // arg=[outer, 'width', 500];
        // setCss(outer, 'width', 500);
        // setCss.apply(null,arg);
        setCss(...arg);
        return;
    }

    if (len === 2 && typeof arg[1] === 'object' && arg[1] !== null) {
        //=>传递两个参数,第二个参数是一个对象(不是NULL),说明想要操作的是批量设置
        setGroupCss(...arg);
        return;
    }
    //=>剩下的代表获取样式
    return getCss(...arg);
};
let css = function (...arg) {
    let len = arg.length,
        fn = getCss;
    len >= 3 ? fn = setCss : null;
    len === 2 && (arg[1] instanceof Object) ? fn = setGroupCss : null;
    return fn(...arg);
};

公共方法库

//=>公共方法库:项目中常用的一些方法,我们都封装到这里
let utils = (function () {
    //=>获取元素的样式
    let getCss = function (curEle, attr) {
        if (typeof window.getComputedStyle === 'undefined') {
            return;
        }
        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) {
        if (attr === 'opacity') {
            curEle.style.opacity = value;
            curEle.style.filter = `alpha(opacity=${value * 100})`;
            return;
        }
        if (!isNaN(value)) {
            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 = {}) {
        for (let attr in options) {
            if (!options.hasOwnProperty(attr)) break;
            setCss(curEle, attr, options[attr]);
        }
    };

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

    //=>offset:获取当前元素距离BODY的偏移(左偏移和上偏移)
    let offset = function (curEle) {
        //1.先获取当前元素本身的左/上偏移
        let curLeft = curEle.offsetLeft,
            curTop = curEle.offsetTop,
            p = curEle.offsetParent;

        //2.累加父参照物的边框和偏移(一直向上找,找到BODY为止,每当找到一个父参照物都把它的边框和偏移累加起来,根据元素不一样,具体找几次也不知道)
        //TAG-NAME获取当前元素的标签名(大写的)
        while (p.tagName !== 'BODY') {//=>当找到的父参照物是BODY结束查找和累加操作
            //3.把找到的父参照物的边框和偏移值累加起来
            curLeft += p.clientLeft;
            curLeft += p.offsetLeft;
            curTop += p.clientTop;
            curTop += p.offsetTop;
            p = p.offsetParent;//=>基于当前找到的父参照物继续向上查找
        }

        return {
            top: curTop,
            left: curLeft
        };
    };

    //=>操作浏览器盒子模型属性的
    let winHandle = function (attr, value) {
        if (typeof value !== 'undefined') {
            //=>设置盒子模型属性值:SCROLL-TOP/LEFT
            document.documentElement[attr] = value;
            document.body[attr] = value;
            return;
        }
        return document.documentElement[attr] || document.body[attr];
    };

    return {
        css, //=>在ES6中直接这样写相当于 css:css
        offset,
        winHandle
    }
})();

盒子偏移量和OFFET

 * offsetParent:当前盒子的父级参照物

//=>“参照物”:同一个平面中,元素的父级参照物和结构没有必然联系,默认他们的父级参照物都是BODY(当前平面最外层的盒子) BODY的父级参照物是NULL
// center.offsetParent  //=>BODY
// inner.offsetParent   //=>BODY
// outer.offsetParent   //=>BODY

//=>“参照物可以改变”:构建出不同的平面即可(使用zIndex,但是这个属性只对定位有作用),所以改变元素的定位(position:relative/absolute/fixed)可以改变其父级参照物

// utils.css(outer, {
//     position: 'relative' //=>把OUTER脱离原有的平面,独立出一个新的平面,后代元素的父级参照物都会以它为参考
// });
// console.log(center.offsetParent);//=>OUTER
// console.log(inner.offsetParent);//=>OUTER
// console.log(outer.offsetParent);//=>BODY
// utils.css(inner, {position: 'absolute'});
// console.log(center.offsetParent);//=>INNER
// console.log(inner.offsetParent);//=>OUTER
// console.log(outer.offsetParent);//=>BODY
// console.log(document.body.offsetParent);//=>NULL

  * offsetTop / offsetLeft:获取当前盒子距离其父级参照物的偏移量(上偏移/左偏移)  当前盒子的外边框开始~父级参照物的内边框

//=>不管你的父级参照物是谁,我都要获取当前元素距离BODY的偏移量(左偏移和上偏移)

//1.不能修改既定的样式(不能基于POSITION方式改它的参照物了)  ===>详情见上方

滚动条卷去的宽度和高度

 * scrollTop / scrollLeft:滚动条卷去的宽度或者高度

 *

 *   最小卷去值:0

 *   最大卷去值:真实页面的高度 - 一屏幕的高度   document.documentElement.scrollHeight-document.documentElement.clientHeight

 *

 *   在JS盒子模型13个属性中,只有scrollTop/scrollLeft是“可读写”属性,其余都是“只读”属性

 *

 *   操作浏览器的盒子模型属性,我们一般都要写两套,用来兼容各种模式下的浏览器

*    ===>详情见上方代码

上一篇:2021-07-08


下一篇:CSS学习日记1——CSS各种选择器