跳至主要內容

4. 元素样式

Harry Xiong大约 10 分钟Web 前端DOMBOM

元素样式

4.1 修改元素CSS样式

4.1.1 通过style属性修改元素样式

通过 元素.style.样式名="样式值" 的方式设置修改CSS样式

注意:

  • 如果CSS的样式名中含有-(也就是减号),这种名称在JS中是不合法的,比如background-color,需要将这种样式名修改为驼峰命名法,去掉-,然后将-后的字母大写,如:background-color写作backgroumdColor,border-top-width写作borderTopWidth

  • 因为float样式是JS中的保留字,所有在修改元素浮动属性的时候不能够直接写作 元素.style.float="样式值" 的形式,需要**用styleFloat(兼容IE6~8)或cssFloat(IE9以上使用)**来代替使用

  • 通过style属性设置的样式都是内联样式,而内联样式有较高的优先级,所以通过JS修改的样式往往会立即重置,但是如果在样式中用了!important则样式会拥有最高优先级,导致JS修改样式失效,所以尽量不要使用important

  • 通过JS的style属性设置和读取的都是内联样式,无法读取CSS样式表中的样式(外部样式和嵌套样式)

简写方式

通过 元素.style.cssText="样式值" 的方式可以将多个CSS属性同时写入,右边的值的写法和内联的CSS样式一样的,并不用遵循驼峰命名法,也不用在意JS的保留字问题

4.1.2 通过类修改元素样式

通过**修改类(class)**来修改CSS样式

  • 修改className属性 通过修改元素的className属性(在JS中的class是保留字,所以用className来代替)来间接修改样式,这样一来,只需要修改一次,即可同时修改多个样式,浏览器只需要重新渲染页面一次,性能比较好 用className属性添加一个类元素.className+=" 类名",记得在类名前面加上空格

  • 通过classList属性 每个标签元素都有classList属性,这个属性和当中的一些方法可以让我们修改类时更加简便

    • classList属性返回元素的类名,该属性只读,只能通过该属性的一些方法来修改元素的类
    • classList属性有length属性,该属性返回元素类的属性,并且该属性只读
    • classList属性的方法

      方法描述
      add(class1, class2, ...)在元素中添加一个或多个类名。 如果指定的类名已存在,则不会添加
      contains(class)返回布尔值,判断指定的类名是否存在。可能值:true - 元素包已经包含了该类名false - 元素中不存在该类名
      item(index)返回元素中索引值对应的类名。索引值从 0 开始。 如果索引值在区间范围外则返回 null
      remove(class1, class2, ...)移除元素中一个或多个类名。注意: 移除不存在的类名,不会报错。
      toggle(class, true|false)在元素中切换类名。 第一个参数为要在元素中移除的类名,并返回 false。 如果该类名不存在则会在元素中添加类名,并返回 true。 第二个是可选参数,是个布尔值用于设置元素是否强制添加或移除类,不管该类名是否存在。也就是说如果写了第二个参数那么该方法就变成了add()或remover()方法

4.2 获取元素样式

4.2.1 通用样式

  • 在IE了浏览器中通过currentStyle属性来获取当前元素正在显示的样式,如果获取的是没有设置的样式,就会返回该样式的默认值,并且如果默认是以px为单位来返回的 **如:**没有设置width就会返回默认值auto **语法:**元素.currentStyle.样式名

  • 在其他浏览器可以使用getComputedStyle()方法来获取元素样式(IE8以下不支持,)这个方法是window的方法,可以直接进行调用

    该方法

    有两个参数,

    第一个参数传入一个元素,第二个参数传入一个伪类,第二个参数可选,当不查询伪类元素的时候可以忽略或者传入null。该方法会

    返回一个对象

    ,对象中封装了当前元素对应的样式,可以通过样式名来读取样式,如果获取的样式没有设置,与currentStyle属性不同,会获取真实的值,而不是默认值,同时值也是默认以

    px为单位

    来返回的

    如:

    没有设置width,不会返回auto,而是返回一个长度

    var div=document.getElementById("box");
    var obj=getComputedStyle(Odiv,null);
    
    console.log(obj.width);
    console.log(getComputedStyle(box1,null).width);//也可以直接输出
    

**注意:**通过currentStyle属性和getComputedStyle()方法读取到的样式都是只读的,不能修改,如果要修改必须通过style属性

兼容写法

/*
参数:obj 要获取样式的元素
    name 要获取的样式名
*/
function getStyle(obj,name){

if(window.getComputedStyle){   //因为getComputedStyle函数实质上是一个对象,所以如果有就返回true,这里必须要用window,因为这是要在全局范围类寻找,但是IE8全局里没有这个变量,肯定会报错,必须加上window,如果没有这个window里的属性就会返回undefined

return getComputedStyle(obj,null)[name]//因为是变量必须使用[]的方法

}else{
return obj.currentStyle[name]
}
//当然if的对象也可以反过来,但是如果判断obj.currentStyle有问题在于IE8以上的IE浏览器两种方法都有,这样它就会优先使用第一个方法,但是我们推荐优先使用getComputedStyle()
}

4.2.2 获取特殊样式

注:以下获取的样式都是只读的,不能够修改

属性

  • clientWidth和clientHeight属性获取元素的可见宽度和高度(内容区和内边距),这些属性都是返回纯数值,不带单位,可以直接进行计算

  • offsetWidth和offsetHeight属性获取元素的整个宽度和高度(内容区,内边距和边框),返回值也是纯数值

  • offsetLeft和offsetTop属性获取当前元素相对于其定位父元素的水平偏移量和垂直偏移量 **注意:**偏移量的原点是父元素的左上角(left top),和背景图片的原点相同

  • window.innerWidthwindow.innerHeight属性可以获取window窗口的内部宽高

    注意:

    不包括页面的导航栏以及页面滚动条和控制台

    console.log(window.innerHeigth);
    console.log(window.innerWidth);
    
  • document.documentElement.clientWidth和document.documentElement.clientWidth属性获取文档可视区域

    ,该属性的值虽然与window,innerWidth和window.innerHeight的值相同,但是对象的调用者不同,内部的含义也不同

    console.log(document.documentElement.clientHeith);
    console.log(document.documentElement.clientWidth);
    
  • scrollWidth和scrollHeight属性可以获取元素整个滚动区域的宽度和高度,如果没有隐藏的部分则等于clientWidth和clientHeight

  • scrollLeft和scrollTop属性可以获取水平和垂直滚动条滚动的距离

    浏览器滚动条问题

    chrome认为浏览器的滚动条是body元素的,可以通过body.scrollTopl来获取,而火狐和IE浏览器认为浏览器的滚动条是html元素的,所以在用到浏览器滚动条的时候就会出现兼容问题(现在的chrome版本已经和火狐与IE统一都是通过html元素获取了,通过body获取反而值为0)

    兼容代码

    var st=document.body.scrollTop||document.documentElement.scrollTop;
    var sl=document.body.scrollLeft||document.documentElement.scrollLeft;
    //该兼容代码可以在计算页面的滚动条距离的时候使用
    

注:当满足scrollHeight-ScrollTop===clientHeight 这个表示式时说明垂直滚动条到底了,同理水平滚动条也一样

自制滚动条

/*
    一个最大的容器box,一个装滚动条的div容器,一个滚动条div,一个文字div
    滚动条的高/装滚动条div的高=box的高/文字的高-->滚动条的高=装滚动条div的高*box的高/文字div的高
*/
//bar为滚动条,scroll为包裹滚动条的层,content为装文字的盒子
var box=document.getElementById("box");
var scroll=document.getElementById("scroll");
var content=document.getElementById("content");
var bar=document.getElementById("bar");

var height=scroll.offsetHeight*box.offsetHeight/content.offsetHeight;
bar.style.height=height+"px";
//移动滚动条
bar.onmousedowm=function(e){
    //鼠标在滚动条上的位置
    var spaceY=e.clientY-bar.offsetTop;
    document.onmousemove=function(e){
        //滚动条纵坐标
        var y=e.clientY-spaceY;
        y=y<0?0:y;//最小值
        y=y>(scroll.offsetHeight-bar.offsetHeight)?(scroll.offsetHeight-bar.offsetHeight):y;
        bar.style.top=y+"px";
        //设置鼠标移动时文字不被选中
        window.getSelection?window.getSelection().removeAllRanges():document.selection.empty();
        
        //文字div的移动距离=滚动条的移动距离*文字div的最大移动距离/滚动条的最大移动距离
        //文字的最大移动距离是content盒子的高度减去最外层盒子的高度
        var moveY=y*(content.offsetHeight-box.offsetHeight)/(scroll.offsetHeight-bar.offsetHeight);
        content.style.marginTop=-moveY+"px";
    }
}

document.onmouseup=function(){
    //鼠标抬起将鼠标移动事件去除
    document.onmousemove=null;
}
<!--下面滚动条的方法与上方没有太大联系-->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>滚动条</title>
    <style>
      * {
        margin: 0;
        padding: 0;
      }
      #box {
        position: relative;
        overflow: hidden;
        margin: 50px auto;
        width: 500px;
        height: 600px;
        background-color: rgb(231, 223, 223);
        border-radius: 5px;
      }
      #content {
        position: absolute;
        float: left;
        width: 480px;
      }
      #content > div {
        text-indent: 2em;
      }
      #bar-container {
        position: relative;
        float: right;
        height: 100%;
        width: 20px;
        background-color: #ccc;
        border-radius: 5px;
        cursor: pointer;
      }
      #bar {
        position: absolute;
        top: 0;
        left: 0;
        width: 20px;
        height: 40px;
        background-color: pink;
        border-radius: 5px;
        cursor: pointer;
      }
    </style>
    <script src="js/animation.js"></script><!--装有运动函数-->
  </head>
  <body>
    <div id="box">
      <div id="content">
        code....
      </div>
      <div id="bar-container">
        <div id="bar"></div>
      </div>
    </div>
    <script>
      ///最大的包裹盒子
      let box = document.getElementById("box");
      //包裹文档的盒子
      let content = document.getElementById("content");
      //装滚动条的盒子
      let barContainer = document.getElementById("bar-container");
      //滚动条
      let bar = document.getElementById("bar");
      //计算滚动条的大小
      let barHeight =
        Math.min(box.offsetHeight / content.offsetHeight, 1) *
        barContainer.offsetHeight;
      bar.style.height = barHeight + "px";
      //滚动条最大滚动距离
      let maxScroll = barContainer.offsetHeight - bar.offsetHeight;
      //内容能滑动的最大距离
      let maxContent = content.offsetHeight - box.offsetHeight;
      //滑动时距顶部的距离
      let Top = 0;
      //判断内容长度绑定事件
      if (bar.offsetHeight / content.offsetHeight < 1) {
        mousewheel(box, function(event) {
          event = event || window.event;
          if (event.wheelDetail > 0) {
            //每次滑动的像素
            Top -= 10;
          } else {
            Top += 10;
          }
          Top = Math.max(0, Top);
          Top = Math.min(maxScroll, Top);
          bar.style.top = Top + "px";
          //文字内容滑动比例
          content.style.top = -(Top / maxScroll) * maxContent + "px";
        });
      } else {
        barContainer.style.display = "none";
        content.style.width = "100%";
      }
      barContainer.onclick = function(event) {
        Top = event.pageY - getDistance(this).top - bar.offsetHeight / 2;
        //上面也可以用event.clientY-this.getBoundingClientRect().top-bar.offsetHeight / 2
        Top = Math.max(0, Top);
        Top = Math.min(maxScroll, Top);
        if (event.target === this) {
          animation(//运动函数
            bar,
            {
              data: {
                top: Top
              }
            },
            500
          );
          animation(
            content,
            {
              data: {
                top: -(Top / maxScroll) * maxContent
              }
            },
            500
          );
        }
      };

      bar.onmousedown = function(event) {
        event = event || window.event;
        //开始时的鼠标坐标和滚动条的距离
        let startY = event.clientY;
        let startTop = bar.offsetTop;
        //清除阻止冒泡
        event.stopPropagation();
        document.onmousemove = function(event) {
          event = event || window.event;
          //拖动时的鼠标坐标和滚动距离
          let nowY = event.clientY;
          Top = startTop + nowY - startY;

          Top = Math.max(0, Top);
          Top = Math.min(maxScroll, Top);
          bar.style.top = Top + "px";
          //文字内容滑动比例
          content.style.top = -(Top / maxScroll) * maxContent + "px";
          event.preventDefault();
        };

        document.onmouseup = function() {
          this.onmousemove = null;
          this.onmouseup = null;
        };
      };

      function mousewheel(dom, callback, bool) {
        //bool为传入的一个布尔值,如果是true则阻止默认行为,默认是不阻止
        var type = "mousewheel";

        if (dom.onmousewheel === undefined) {
          //不能通过判断下面的那个,因为在火狐中dom属性也没有这个属性
          type = "DOMMouseScroll";
        }
        //真正的事件函数
        function cb(event) {
          /*
              自定义属性event.wheelDtail控制鼠标滚轮,所以在外部使用时应该用event.wheelDetail
          */
          /*外部可以传入event作为事件对象也可以不传入直接使用,也不需要进行兼容,但是不传入时应该用              event
          */
          event = event || window.event;
          //把滚动事件的方向处理一致
          event.wheelDetail = event.wheelDelta / 123 || event.detail / -3;
          //每次滚动的值为1,并且向上滚动为正值,向下滚动为负值

          //阻止默认行为
          if (!!bool) {
            if (event.preventDefault) {
              event.preventDefault();
            } else {
              event.returnValue = flase;
            }
          }
          callback.call(this, event);
        }

        if (dom.addEventListener) {
          dom.addEventListener(type, cb);
        } else {
          dom, attachEvent("on" + type, cb);
        }
      }

      //获取当前定位元素距离body顶部的距离
      function getDistance(dom) {
        let obj = {
          top: 0,
          left: 0
        };
        while (dom != document.body) {
          obj.top = dom.offsetTop;
          obj.left = dom.offsetLeft;
          dom = dom.offsetParent;
        }
        return obj;
      }
    </script>
  </body>
</html>

方法

  • getBoundingClientRect()方法获取元素节点对象到窗口的左上角(恒定为刚打开页面时的左上角为原点)的距离值以及自身的长宽等属性,该方法不用传入参数

  • scrollIntoView()方法让滚动条滚动到调用对象的可视区,一旦执行此方法调用此方法的页面就会滚动到该元素节点的位置,此方法不用传入参数