灏天阁

脚本化CSS

· Yin灏

css 脚本化基础

使用 style 对象

/*
  
  1. cssText: 返回 style 的 css 样式字符串。
  2. length: 返回 style 的声明 CSS 样式的数量。
  3. parentRule: 返回 style 所属的 CSSRule 对象。
  4. getPropertyCSSValue(): 返回包含指定属性的 CSSValue 对象。
  5. getPropertyPriority(): 返回包含指定属性是否附加了 !important 命令。
  6. item(): 返回指定下标位置的 CSS 属性名称。
  7. getPropertyValue(): 返回指定属性的字符串值。
  8. removeProperty(): 从样式中删除给定属性。
  9. setProperty(): 为了指定属性设置值,也可以附加优先权标志

*/
  • getPropertyValue() 方法
// <div id="box" style="width: 300px;height: 200px;border:solid 1px red;">
window.onload = function() {
  var box = document.getElementById('box');
  var width = box.style.getPropertyValue('width');
  box.innerHTML = "盒子宽度:" + width; // '300px'
}
  • setProperty() 方法
// <div id="box" style="border:solid 1px red;">
window.onload = function() {
  var box = document.getElementById('box');
  box.style.setProperty("width", "400px", "");
  box.style.setProperty("height", "200px", "");
}
  • removeProperty()方法
e.style.removeProperty(propertyName);
  • item() 方法:返回 style 对象中指定索引位置的 css 属性名称。
var name = e.style.item(index);
  • getPropertyPriority()方法:获取指定 css 属性汇总是否附加了 !important 优先级命令,如果存在则返回 important 字符串,否则返回空字符串。
// <div id="box" style="width:100px;height:100px;background-color:red;border:solid 50px blue;">
window.onload = function() {
  var box = document.getElementById('box');
  box.onmouseover = function() {
    box.style.setProperty("background-color", 'blue', '');
    box.style.setProperty("border", 'solid 50px red', '')
  }
  box.onclick = function() {
    box.innerHTML = (box.style.item(0) + ":" + box.style.getPropertyValue('width'));
    box.innerHTML = box.innerHTML + "<br>" + (box.style.item(1) + ":" + box.style.getPropertyValue('height'));
  }
  box.onmouseout = function() {
    box.style.setProperty("background-color", "red", "");
    box.style.setProperty("border", "solid 50px blue", "");
  }
}

使用 styleSheets 对象

DOM2 级别规范中,使用 styleSheets 对象可以访问页面中所有样式表,包括用 <style> 标签定义在内部样式表,以及使用<link> 标签或 @import 命令导入的外部样式表。

cssRules 对象中包含了指定样式表中的所有跪着,IE 支持 rules 对象表示样式表中的规则,可以使用下面的兼容写法:

var cssRules = document.styleSheets[0].cssRules || document.styleSheets[0].rules;
/*
  通过 <style> 标签定义一个内部样式表,然后再脚本中使用 styleSheets 访问这个内部样式表,把样式表中的第一个样式的所有规则读取出来。
*/
/*
  <div id="box"></div>
  
  #box {
    width: 400px;
    height: 200px;
    background-color: #BFFB8F;
    border: solid 1px blue;
}

*/
window.onload = function() {
    var box = document.getElementById('box');
    // 需要在域名中才能访问
    var cssRules = document.styleSheets[0].cssRules || document.styleSheets[0].rules;
    console.log(cssRules);
    box.innerHTML = "<h3>盒子样式</h3>";
    box.innerHTML += "<br>边框:" + cssRules[0].style.border;
    box.innerHTML += "<br>背景:" + cssRules[0].style.backgroundColor;
    box.innerHTML += "<br>高度:" + cssRules[0].style.height;
    box.innerHTML += "<br>宽度:" + cssRules[0].style.width;
}

使用 selectorText 对象

使用 selectorText 对象可以获取样式的选择器字符串表示。

/*
<style>
    #box { color: green; }
    .red { color: red; }
    .blue { color: blue; }
</style>
*/
window.onload = function() {
    var box = document.getElementById('box');
    var cssRules = document.styleSheets[0].cssRules || document.styleSheets[0].rules;
    console.log(cssRules[2].selectorText); // .blue
}

编辑样式

window.onload = function() {
    var box = document.getElementById('box');
    var cssRules = document.styleSheets[0].cssRules || document.styleSheets[0].rules;
    cssRules[2].style.color = "#999";
}

添加样式

使用 addRule() 方法可以为样式表增加一个样式:

styleSheet.addRule(selecor, sytle, [index]);
/*
  selecor: 样式选择符,以字符串形式传递。
  style: 表示具体的声明,以字符串形式传递。
  index: 表示一个索引号,表添加样式在样式表中索引位置,默认为 -1,表示位于样式表的末尾,可选。
*/

Firefox 支持使用 insertRule() 方式添加样式:

styleSheet.insertRule(rule, [index]);
/*
  rule: 表示一个完整的样式字符串
  index: 表示一个索引号,表添加样式在样式表中索引位置,默认为 0,表示位于样式表的末尾,可选。
*/
// 演示
window.onload = function() {
    var styleSheets = document.styleSheets[0];
    var index = styleSheets.length; // 获取样式表中包含样式的个数
    if (styleSheets.insertRule) {
        styleSheets.insertRule("p{background-color: red;color:#fff;padding:1em;}", index)
    } else {
        styleSheets.addRule("P", "background-color: red;color:#fff;padding:1em;", index)
    }
}

读取显示样式

css 样式具有重叠特性,因此定义的样式与最终显示的样式并非完全相等。IEDOM 之间标准不同。

  • IE 浏览器

IE 使用 currentStyle 对象读取元素的最终显示样式,是只读对象。currentStyle 对象包含元素的 style 属性,以及浏览器预定义的默认 style 属性。

/*
<style>
    #box {
        color: green;
    }

    .red {
        color: red;
    }

    .blue {
        color: blue;
        background-color: #ffffff;
    }
</style>
*/
window.onload = function() {
    var styleSheets = document.styleSheets[0];
    var index = styleSheets.length; // 获取样式表中包含样式的个数
    if (styleSheets.insertRule) {
        styleSheets.insertRule("p{background-color: red;color:#fff;padding:1em;}", index)
    } else {
        styleSheets.addRule("P", "background-color: red;color:#fff;padding:1em;", index)
    }
    // 只支持 IE
    var p = document.getElementsByTagName('p')[0];
    console.log(p.currentStyle);
    console.log(p.currentStyle.backgroundColor); // #ffffff
    console.log(p.currentStyle.color); // blue
}
  • IE 浏览器

DOM 使用 getComputedStyle() 获取目标对象的显示样式,但是它属于 document.defaultView 对象。

window.onload = function() {
    var styleSheets = document.styleSheets[0];
    var index = styleSheets.length; // 获取样式表中包含样式的个数
    if (styleSheets.insertRule) {
        styleSheets.insertRule("p{background-color: red;color:#fff;padding:1em;}", index)
    } else {
        styleSheets.addRule("P", "background-color: red;color:#fff;padding:1em;", index)
    }
    // 只支持 IE
    var p = document.getElementsByTagName('p')[0];
    if (document.defaultView && document.defaultView.getComputedStyle) {
        console.log(document.defaultView.getComputedStyle(p, null));
        console.log(document.defaultView.getComputedStyle(p, null).backgroundColor); // rgb(255, 255, 255)
        console.log(document.defaultView.getComputedStyle(p, null).color); // rgb(0, 0, 255)
    } else if (p.currentStyle) {
        console.log(p.currentStyle);
        console.log(p.currentStyle.backgroundColor); // #ffffff
        console.log(p.currentStyle.color); // blue
    }
}

读取媒体查询

使用 window.matchMedia() 可以访问 cssmedia query 语句。这个方法接收一个 mediaQuery 语句的字符串作为参数,返回一个 MediaQueryList 对象,该对象有两个参数:

  • media: 返回所查询的 mediaQuery 语句字符串。
  • matches: 返回一个布尔值,表示当前环境是否匹配查询语句。
var result = window.matchMedia('(min-width: 600px)');
result.media; // (min-width: 600px)
result.matches; // true,当前页面的宽度在 600px 以上,匹配要求
// 根据 mediaQuery 是否匹配当前环境,执行不同的 js 代码
var result = window.matchMedia("(max-width: 768px)");
if (result.matches) {
    console.log('页面宽度小于等于 768px');
} else {
    console.log('页面宽度大于 768px');
}
// 根据 mediaQuery 是否匹配当前环境,加载不同的 css 样式表
var result = window.matchMedia("(max-width: 768px)");
if (result.matches) {
    var linkElm = document.createElement("link");
    linkElm.setAttribute("rel", "stylesheet");
    linkElm.setAttribute("type", "text/css");
    linkElm.setAttribute("href", "small.css");
    document.head.appendChild(linkElm);
}

如果 window.matchMedia 无法解析 mediaQuery 参数,返回的总是 false,而不是报错,如:

window.matchMedia('bad string').matches; // false

window.matchMedia 方法返回的 MediaQueryList 对象有两个方法用来监听事件:addListener 方法和 removeListener 方法。如果 matchMedia 查询结果发生了变化,就调用指定的回调函数。

var mql = window.matchMedia("(max-width: 768px)");
// 执行回调函数
mql.addListener(mqCallback);
// mql.removeListener(mqCallback) // 取消监听

function mqCallback(mql) {
    if (mql.matches) {
        console.log('宽度小于等于768px');
    } else {
        console.log('宽度大于768px');
    }
}

使用 css 事件

  • transitionEnd 事件

css 过渡结束后,触发该事件。

el.addEventListener('transitionend', onTransitionEnd, false);
function onTransitionEnd() {
    console.log("Transition end");
}
/*
  
  transitionEnd 的事件对象具有一下属性:
  1. propertyName: 发生 transition 效果的 css 属性名。
  2. elapsedTime: transition 效果持续的秒数,不含 transition-delay 的时间
  3. pseudoElement: 如果 transition 效果发生在伪元素上,会返回该伪元素的名称,以 :: 开头,如果没有发生在伪元素上,则返回一个空字符串。

*/

// 实际使用 transitionend 事件时,可能需要添加浏览器前缀。
el.addEventListener('webkitTransitionEnd', function() {
    e.style.transition = "none";
}, false);
  • animationstartanimationendanimationiteration 事件

css 动画有以下 3 个事件:

  1. animationstart: 动画开始时触发。
  2. animationend:动画结束时触发。
  3. animationiteration:开始新一轮动画循环时触发。如果 animation-iteration-count = 1 ,该事件不会触发。
/*
  这 3 个事件的事件对象,都有 animationName 属性 和 elapsedTime 属性(动画已经运行的秒数),对于 animationstart 事件,elapsedTime 属性等于 0 ,除非 animation-deley 属性等于负值。
*/
var el = document.getElementById('animation');
el.addEventListener('animationstart', listener, false);
el.addEventListener('animationend', listener, false);
el.addEventListener('animationiteration', listener, false);

function listener(e) {
    var li = document.createElement('li');
    switch (e.type) {
        case "animationstart":
            li.innerHTML = "Started: elapsed time is " + e.elapsedTime;
            break;
        case "animationend":
            li.innerHTML = "Ended: elapsed time is " + e.elapsedTime;
            break;
        case "animationiteration":
            li.innerHTML = "New loop started at time " + e.elapsedTime;
            break;
    }
    document.getElementById('output').appendChild(li);
}

animation-play-state 属性可以控制动画的状态(暂停/播放),该属性需要加上浏览器前缀。

element.style.webkitAnimationPlayState = "paused";
element.style.webkitAnimationPlayState = "running";

设计大小

使用 offsestWidth 和 offsetHeight

使用 offsestWidth 和 offsetHeight 属性可以获取元素的尺寸,其中 offsetWidth 表示元素在页面中所占的总宽度,offsetHeight 表示元素在页面中占的总高度。

/*
  <div id="div" style="width:100px;height:100px;background-color:red;"></div>
*/
var div = document.getElementById("div");
var w = div.offsetWidth;
var h = div.offsetHeight;
console.log(w, h); // 100 100

/*
   offsestWidth 和 offsetHeight 是获取元素尺寸最好的方式,但是无法获取被隐藏的元素的尺寸,返回的都是 0。
*/

使用 scrollLeft 和 scrollTop

它们可以读写出可视区域外面的宽度和高度。

/*
<div id="div" style="width: 200px;height: 200px;border: red 50px solid;padding: 50px;overflow: auto;">
    <div id="info" style="width: 400px;height: 400px;border: 1px solid blue;"></div>
</div>
*/
var div = document.getElementById('div');
div.scrollLeft = 200; // 设置盒子左边滚动区域宽度为 200 像素
div.scrollTop = 200; // 设置盒子左边滚动区域宽度为 200 像素
div.onscroll = function() {
    var log = "scrollLeft=" + div.scrollLeft + "\n" + "scrollTop=" + div.scrollTop + "\n" + "scrollWidth=" + div.scrollWidth + "\n" + "scrollHeight=" + div.scrollHeight;
    console.log(log)
}
/*
    scrollLeft=121
    scrollTop=162
    scrollWidth=452
    scrollHeight=502
*/

获取元素大小

元素尺寸属性 说明
clientWidth 获取元素可视区域的宽度,即 CSS 的 width 和 padding 的属性之和,元素边框和滚动条不包括在内,也不包含任何可能的滚动区域。
clientHeight 获取元素可视区域的高度,即 CSS 的 height 和 padding 的属性之和,元素边框和滚动条不包括在内,也不包含任何可能的滚动区域。
offsetWidth 元素在页面中占据的宽度总和,包括 width、padding、border 以及滚动条的宽度。
offsetHeight 元素在页面中占据的高度总和,包括 height、padding、border 以及滚动条的高度。
scrollWidth 当元素设置了 overflow:visible 样式属性时,元素的总宽度,也称滚动宽度。在默认状态下,如果该属性值大于 clientWidth,则元素显示滚动条。
scrollHeight 当元素设置了 overflow:visible 样式属性时,元素的总高度,也称滚动高度。在默认状态下,如果该属性值大于 clientHeight,则元素显示滚动条。
/*
    <div id="div" style="width: 200px;height: 200px;border: red 50px solid;padding: 50px;overflow: auto;">
        <div id="info" style="width: 400px;height: 400px;border: 1px solid blue;"></div>
    </div>
*/
var div = document.getElementById('div');
var hc = div.clientHeight; // 可视区域高度为 283px
var ho = div.offsetHeight; // 占据页面总高度为 400px
var hs = div.scrollHeight; // 展开滚动内容总高度为 452px
console.log(hc, ho, hs);

计算公式:

clientHeight = padding-top + height + border-bottom-width - 滚动条的宽度;

offsetHeight = border-top-width + padding-top + height + padding-bottom + border-bottom-width;

scrollHeight = padding-top + 包含内容的完全高度 + padding-bottom;

获取窗口大小

获取 标签的 clientWidth 和 clientHeight 属性,就可以知道浏览器窗口的可视宽度和高度,而 标签在脚本中表示为 document.documentElement。

var w = document.documentElement.clientWidth; // 返回值不包含滚动条的宽度
var h = document.documentElement.clientHeight; // 返回值不包含滚动条的宽度

在怪异模式下,body 是最顶层的可视元素,而 html 元素保持隐藏,所有只有通过 body 标签的 clientWidth 和 clientHeight 属性才可以知道浏览器窗口的可视宽度和高度。

var w = document.body.clientWidth;
var h = document.body.clientHeight;

两种方法兼容起来:

var w = document.documentElement.clientWidth || document.body.clientWidth;
var h = document.documentElement.clientHeight || document.body.clientHeight;

如果窗口包含内容超出了窗口的可视区域,则应该使用 scrollWidth 和 scrollHeight 属性来获取窗口的实际宽度的和高度。

设计位置

  • 使用 offsetLeft 和 offsetTop

offsetLeft 和 offsetTop 属性返回当前元素的偏移位置。IE 怪异模式以父元素为参照进行偏移位置,DOM标准模式以最近定位元素为参照进行偏移位置。

<!doctype html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <title>title</title>
    <meta name="description" content="">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <style>
        div {
            width: 200px;
            height: 100px;
            border: solid 1px red;
            padding: 50px;
        }
        
        #wrap {
            position: relative;
            border-width: 20px;
        }
    </style>
</head>

<body>
    <div id="wrap">
        <div id="sub">
            <div id="box"></div>
        </div>
    </div>
</body>

</html>
  • 使用 offsetParent

offsetParent 属性表示最近的上级定义元素。要获取相对父级元素的位置,可以先判断 offsetParent 属性是否指向父元素,如果是,则直接使用 offsetLeft 和 offsetTop 属性获取元素相对于父元素的距离;否则分别获取当前元素和父元素距离窗口的坐标,然后求差即可。

<!doctype html>
<html>

<head>
    <meta charset="utf-8">
    <script>
        // 获取指定元素距离窗口左上角偏移坐标
        // 参数:e表示获取位置的元素
        // 返回值:返回对象直接量,其中属性x表示x轴偏移距离,属性y表示y轴偏移距离
        function getPoint(e) {
            var x = y = 0; // 初始化临时变量
            while (e.offsetParent) {
                // 如果存在offsetParent指代的元素,则获取它的偏移坐标
                x += e.offsetLeft; // 累计总的x轴偏移距离
                y += e.offsetTop; // 累计总的y轴偏移距离
                e = e.offsetParent;
                // 把当前元素的offsetParent属性值传递给循环条件表达式
            }
            return {
                // 遍历到body元素后,将停止循环,把叠加的值赋值给对象直接量,并返回该对象
                "x": x,
                "y": y
            };
        }

        // 获取指定元素距离父元素左上角的偏移坐标
        // 参数:e表示获取位置的元素
        // 返回值:返回对象直接量,其中属性x表示x轴偏移距离,属性y表示y轴偏移距离
        function getP(e) {
            if (e.parentNode == e.offsetParent) {
                // 判断offsetParent属性是否指向父级元素
                var x = e.offsetLeft; // 如果是,则直接读取offsetLeft属性值
                var y = e.offsetTop; // 读取offsetTop属性值
            } else {
                // 否则调用getW()扩展函数获取当前元素和父元素的x轴坐标,并返回它们的差值
                var o = getPoint(e);
                var p = getPoint(e.parentNode);
                var x = o.x - p.x;
                var y = o.y - p.y;
            }
            return { // 返回对象直接量,对象包含当前元素距离父元素的坐标
                "x": x,
                "y": y
            };
        }
    </script>
    <style type="text/css">
        div {
            width: 200px;
            height: 100px;
            border: solid 1px red;
            padding: 50px;
        }
        
        #wrap {
            position: relative;
            border-width: 20px;
        }
    </style>
</head>

<body>

    <div id="wrap">
        <div id="sub">
            <div id="box"></div>
        </div>
    </div>

    <script>
        var box = document.getElementById("box");
        var o = getP(box); // 调用扩展函数获取元素相对父元素的偏移坐标
        console.log(o.x); // 读取x轴坐标偏移值
        console.log(o.y); // 读取y轴坐标偏移值
    </script>

</body>

</html>
  • 获取指针的页面位置

使用事件对象的 pageX 和 pageY(兼容 Safari),或者 clientX 和 clientY (兼容 IE) 属性,同时还需要配合 scrollLeft 和 scrollYTop 属性,就可以计算出鼠标指针在页面的位置。

<!doctype html>
<html lang="en">
<head></head>
<body style="width: 2000px; height: 2000px;">
    <!-- start -->
    <textarea id="t" cols="15" rows="4" style="position:fixed;left: 50px;top: 50px;"></textarea>
    <!-- end -->
    <script>
       // 获取指针在整个页面上的位置
       function getMP(e) {
         var e = e || window.event;
         return {
           x: e.pageX || e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft),
           y: e.pageY || e.clientY + (document.documentElement.scrollTop || document.body.scrollTop)
         }
       }
       var t = document.getElementById('t');
       document.onmousemove = function(e) {
         var m = getMP(e);
         t.value = "mouseX=" + m.x + "\n" + "mouseY=" + m.y;
       }
    </script>
</body>
</html>

获取指针的相对位置

使用 offsetX 和 offsetY,或者 layerX 和 layerY 可以获取鼠标指针的相对定位包含框的偏移位置,如果使用 offsetLeft 和 offsetTop 属性获取元素在定位包含框中的偏移坐标,然后使用 layerX 属性值减去 offsetLeft 属性值,使用 layerY 属性值减去 offsetTop 属性值,即可得到鼠标指针在元素内部的位置。

// 获取数比哦啊指针在元素内的位置
// 参数:e 表示当前事件对象,o 表示当前元素,返回值:返回相对坐标对象
function getME(e, o) {
 var e = e || window.event;
 return {
   x: e.offsetX || (e.layerX - o.offsetLeft),
   y: e.offsetY || (e.layerY - o.offsetTop)
 }
}

/*
  上面的函数会存在两个问题:
    1. Mozilla 类型和 Safari 浏览器以元素边框外壁的左上角为参考点;
    2. 其他浏览器则是以元素边框内壁的左上角为坐标原点。
*/

完善上面的函数:

<!doctype html>
<html>

<head>
    <meta charset="utf-8">
    <script>
        // 获取指定元素的样式属性值
        // 参数:e表示具体的元素,n表示要获取元素的脚本样式的属性名,如"width"、"borderColor"
        // 返回值:返回该元素e的样式属性n的值
        function getStyle(e, n) {
            if (e.style[n]) {
                // 如果在Style对象中存在,说明已显式定义,则返回这个值 
                return e.style[n];
            } else if (e.currentStyle) {
                // 否则,如果是IE浏览器,则利用它的私有方法读取当前值
                return e.currentStyle[n];
            }
            // 如果是支持DOM标准的浏览器,则利用DOM定义的方法读取样式属性值
            else if (document.defaultView && document.defaultView.getComputedStyle) {
                n = n.replace(/([A-Z])/g, "-$1"); // 转换参数的属性名
                n = n.toLowerCase();
                var s = document.defaultView.getComputedStyle(e, null);
                // 获取当前元素的样式属性对象
                if (s) // 如果当前元素的样式属性对象存在
                    return s.getPropertyValue(n); // 则获取属性值
            } else // 如果都不支持,则返回null
                return null;
        }

        // 完善获取鼠标指针在元素内的位置
        // 参数:e表示当前事件对象,o表示当前元素
        // 返回值:返回鼠标相对元素的坐标对象,其中属性x表示x轴偏移距离,属性y表示y轴偏移距离
        function getME(e, o) {
            var e = e || window.event;
            // 获取元素左侧边框的宽度
            // 调用getStyle()扩展函数获取边框样式值,并尝试转换为数值,如果转换成功,则赋值。
            // 否则判断是否定义了边框样式,如果定义边框样式,且值不为none,则说明边框宽度为默认值,即为3像素。
            // 如果没有定义边框样式,且宽度值为auto,则说明边框宽度为0
            var bl = parseInt(getStyle(o, "borderLeftWidth")) || ((o.style.borderLeftStyle && o.style.borderLeftStyle != "none") ? 3 : 0);
            // 获取元素顶部边框的宽度,设计思路与获取左侧边框方法相同
            var bt = parseInt(getStyle(o, "borderTopWidth")) || ((o.style.borderTopStyle && o.style.borderTopStyle !=
                "none") ? 3 : 0);
            var x = e.offsetX || // 一般浏览器下鼠标偏移值
                (e.layerX - o.offsetLeft - bl);
            // 兼容Mozilla类型浏览器,减去边框宽度
            var y = e.offsetY || // 一般浏览器下鼠标偏移值
                (e.layerY - o.offsetTop - bt);
            // 兼容Mozilla类型浏览器,减去边框宽度
            var u = navigator.userAgent; // 获取浏览器的用户数据
            if ((u.indexOf("KHTML") > -1) ||
                (u.indexOf("Konqueror") > -1) ||
                (u.indexOf("AppleWebKit") > -1)
            ) { // 如果是Safari浏览器,则减去边框的影响
                x -= bl;
                y -= bt;
            }
            return { // 返回兼容不同浏览器的鼠标位置对象,以元素边框内壁左上角为定位原点
                x: x,
                y: y
            }
        }
    </script>
</head>

<body>

    <div id="box" style="width:200px;height:200px;border:solid 1px red;float:right;"></div>
    <textarea id="t" cols="15" rows="4"></textarea>

    <script type="text/javascript">
        var t = document.getElementById("t");
        var b = document.getElementById("box");

        b.onmousemove = function(e) {
            var m = getME(e, b);
            t.value = "mouseX = " + m.x + "\n" + "mouseY = " + m.y
        }
    </script>
</body>

获取滚动条的位置

使用 scrollLeft 和 scrollTop 属性也可以获取窗口滚动条的位置。

function getPS() {
    var h = document.documentElement;
    var x = self.pageXOffset || //兼容早期浏览器 selt(window对象)
        (h && h.scrollLeft) || //兼容标准浏览器
        document.body.scrollLeft; // 兼容 IE 怪异模式
    var y = self.pageYOffset || (h && h.scrollTop) || document.body.scrollTop;
    return {
        x: x,
        y: y
    }
}
window.onscroll = function() {
    console.log(getPS()) // {x: 41.818180084228516, y: 1454.54541015625}
}

设置滚动条的位置

获取某个元素的位置,让滚动条滚动到这个元素的位置。

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <script>
        // 获取指定元素距离窗口左上角偏移坐标
        // 参数:e表示获取位置的元素
        // 返回值:返回对象直接量,其中属性x表示x轴偏移距离,属性y表示y轴偏移距离
        function getPoint(e) {
            var x = y = 0; // 初始化临时变量
            while (e.offsetParent) {
                // 如果存在offsetParent指代的元素,则获取它的偏移坐标
                x += e.offsetLeft; // 累计总的x轴偏移距离
                y += e.offsetTop; // 累计总的y轴偏移距离
                e = e.offsetParent;
                // 把当前元素的offsetParent属性值传递给循环条件表达式
            }
            return {
                // 遍历到body元素后,将停止循环,把叠加的值赋值给对象直接量,并返回该对象
                "x": x,
                "y": y
            };
        }

        // 滚动到页面中指定的元素位置
        // 参数:指定的对象
        // 返回值:无
        function setPS(e) {
            window.scrollTo(getPoint(e).x, getPoint(e).y);
        }
    </script>
</head>
    
<body>
    <div style="height:1000px;border:solid 20px red"></div>
    <div style="height:1000px;border:solid 20px blue"></div>
    <script type="text/javascript">
        var d1 = document.getElementsByTagName("div")[0];
        var d2 = document.getElementsByTagName("div")[1];
        setPS(d2)
    </script>
</body>
    
</html>

设计显隐

显示和隐藏

/*
  设置或切换的显示或隐藏
  参数:
    e: 表示操作元素
    b: true 将显示元素 e,false 将隐藏元素 e
    如果省略参数 b,则根据元素 e 的状态进行切换
 */
// 获取指定元素的样式属性值
// 参数:e表示具体的元素,n表示要获取元素的脚本样式的属性名,如"width"、"borderColor"
// 返回值:返回该元素e的样式属性n的值
function getStyle(e, n) {
    if (e.style[n]) {
        // 如果在Style对象中存在,说明已显式定义,则返回这个值
        return e.style[n];
    } else if (e.currentStyle) {
        // 否则,如果是IE浏览器,则利用它的私有方法读取当前值
        return e.currentStyle[n];
    }
    // 如果是支持DOM标准的浏览器,则利用DOM定义的方法读取样式属性值
    else if (document.defaultView && document.defaultView.getComputedStyle) {
        n = n.replace(/([A-Z])/g, "-$1"); // 转换参数的属性名
        n = n.toLowerCase();
        var s = document.defaultView.getComputedStyle(e, null);
        // 获取当前元素的样式属性对象
        if (s) // 如果当前元素的样式属性对象存在
            return s.getPropertyValue(n); // 则获取属性值
    } else // 如果都不支持,则返回null
        return null;
}

function display(e, b) {
    // 监测第二个参数的类型。如果该参数存在且不为布尔值,则抛出异常
    if (b && (typeof b != "boolean")) throw new Error("第二个参数应该是布尔值!");
    var c = getStyle(e, "display"); // 获取当前元素的显示属性值
    (c != "none") && (e._display = c);
    // 记录元素的显示性质,并存储到元素的属性中
    e._display = e._display || "";
    // 如果没有定义显示性质,则赋值为空字符串
    if (b || (c == "none")) { // 当第二个参数值为true,或者元素隐藏时
        e.style.display = e._display;
        // 则将调用元素的_display属性值恢复元素或显示元素
    } else {
        e.style.display = "none"; // 否则隐藏元素
    }
}

函数应用:

// 切换显示和隐藏
var p = document.getElementsByTagName("p")[0];
display(p); 						// 切换隐藏
display(p); 						// 切换显示
display(p); 						// 切换隐藏

// 强制显示或隐藏
display(p , true); 					// 强制显示

半透明显示

<!doctype html>
<html>

<head>
    <meta charset="utf-8">
    <script>
        // 设置元素的透明度
        // 参数:e表示要预设置的元素,n表示一个数值,取值范围为0~100,如果省略,则默认为100,即不透明显示元素
        // 返回值:无
        function setOpacity(e, n) {
            var n = parseFloat(n); // 把第二个参数转换为浮点数
            if (n && (n > 100) || !n) n = 100;
            // 如果第二个参数存在且值大于100,或者不存在该参数,则设置其为100
            if (n && (n < 0)) n = 0; // 如果第二个参数存在且值小于0,则设置其为0
            if (e.filters) { // 兼容IE浏览器
                e.style.filter = "alpha(opacity=" + n + ")";
            } else { // 兼容DOM标准
                e.style.opacity = n / 100;
            }
        }

        // 获取元素的透明度
        // 参数:e表示要预设置的元素
        // 返回值:元素的透明度值,范围在1~100之间
        function getOpacity(e) {
            var r;
            if (!e.filters) {
                if (e.style.opacity) return parseFloat(e.style.opacity) * 100;
            }
            try {
                return e.filters.item('alpha').opacity
            } catch (o) {
                return 100;
            }
        }
    </script>
</head>

<body>

    <div id="box" style="background:red; width:300px; height:200px;"></div>
    <script>
        var box = document.getElementById("box");
        setOpacity(box, 50);

        var n = getOpacity(box);

        alert(n);
    </script>

</body>

</html>

设计动画

移动动画

移动动画主要通过动态修改元素的坐标来实现:

  • 考虑元素的初始坐标、终点坐标,以及移动坐标等定位要素。
  • 移动速度、频率等问题可以借助定时器来实现。但效果的模拟涉及算法问题,不同的算法,可能会设计出不同的移动效果,如匀速运动、加速和减速运动。
<!--
  设计一个简单的元素移动效果,通过指向元素、移动的位置,以及移动的步数,可以设计按一定速度把元素从当前位置移动到指定的位置。
-->
<!doctype html>
<html>

<head>
    <meta charset="utf-8">
    <script>
        // 获取指定元素的样式属性值
        // 参数:e表示具体的元素,n表示要获取元素的脚本样式的属性名,如"width"、"borderColor"
        // 返回值:返回该元素e的样式属性n的值
        function getStyle(e, n) {
            if (e.style[n]) {
                // 如果在Style对象中存在,说明已显式定义,则返回这个值
                return e.style[n];
            } else if (e.currentStyle) {
                // 否则,如果是IE浏览器,则利用它的私有方法读取当前值
                return e.currentStyle[n];
            }
            // 如果是支持DOM标准的浏览器,则利用DOM定义的方法读取样式属性值
            else if (document.defaultView && document.defaultView.getComputedStyle) {
                n = n.replace(/([A-Z])/g, "-$1"); // 转换参数的属性名
                n = n.toLowerCase();
                var s = document.defaultView.getComputedStyle(e, null);
                // 获取当前元素的样式属性对象
                if (s) // 如果当前元素的样式属性对象存在
                    return s.getPropertyValue(n); // 则获取属性值
            } else // 如果都不支持,则返回null
                return null;
        }

        // 获取指定元素距离定位包含框元素左上角的偏移坐标
        // 参数:e表示获取位置的元素
        // 返回值:返回对象直接量,其中属性x表示x轴偏移距离,属性y表示y轴偏移距离
        function getB(e) {
            return {
                "x": (parseInt(getStyle(e, "left")) || 0),
                "y": (parseInt(getStyle(e, "top")) || 0)
            };
        }

        // 简单的滑动函数
        // 参数:e表示元素,x和y表示要移动的最后坐标位置(相对包含块,t表示元素移动的步数
        function slide(e, x, y, t) {
            var t = t || 100; // 初始化步数,步数越大,速度越慢,移动的过程越逼真,但是中间移动的误差就越明显
            var o = getB(e); // 当前元素的绝对定位坐标值
            var x0 = o.x;
            var y0 = o.y;
            var stepx = Math.round((x - x0) / t);
            // 计算x轴每次移动的步长,由于像素点不可用小数,所以会存在一定的误差
            var stepy = Math.round((y - y0) / t); // 计算y轴每次移动的步长
            var out = setInterval(function() { // 设计定时器
                var o = getB(e); // 获取每次移动后的绝对定位坐标值
                var x0 = o.x;
                var y0 = o.y;
                e.style["left"] = (x0 + stepx) + 'px'; // 定位每次移动的位置
                e.style["top"] = (y0 + stepy) + 'px'; // 定位每次移动的位置
                if (Math.abs(x - x0) <= Math.abs(stepx) || Math.abs(y - y0) <=
                    Math.abs(stepy)) { // 如果距离终点坐标的距离小于步长,则停止循环执行,并校正元素的最终坐标位置
                    e.style["left"] = x + 'px';
                    e.style["top"] = y + 'px';
                    clearTimeout(out);
                };
            }, 2)
        };
    </script>
</head>

<body>

    <style type="text/css">
        .block {
            width: 20px;
            height: 20px;
            position: absolute;
            left: 200px;
            top: 200px;
            background-color: red;
        }
    </style>
    <div class="block" id="block1"></div>
    <script>
        temp1 = document.getElementById('block1');
        slide(temp1, 400, 400, 20);
    </script>

</body>

</html>

渐隐渐现

主要通过修改元素的透明度来实现。

<!doctype html>
<html>

<head>
    <meta charset="utf-8">
    <script>
        // 设置元素的透明度
        // 参数:e表示要预设置的元素,n表示一个数值,取值范围为0~100,如果省略,则默认为100,即不透明显示元素
        // 返回值:无
        function setOpacity(e, n) {
            var n = parseFloat(n); // 把第二个参数转换为浮点数
            if (n && (n > 100) || !n) n = 100;
            // 如果第二个参数存在且值大于100,或者不存在该参数,则设置其为100
            if (n && (n < 0)) n = 0; // 如果第二个参数存在且值小于0,则设置其为0
            if (e.filters) { // 兼容IE浏览器
                e.style.filter = "alpha(opacity=" + n + ")";
            } else { // 兼容DOM标准
                e.style.opacity = n / 100;
            }
        }

        // 获取元素的透明度
        // 参数:e表示要预设置的元素
        // 返回值:元素的透明度值,范围在1~100之间
        function getOpacity(e) {
            var r;
            if (!e.filters) {
                if (e.style.opacity) return parseFloat(e.style.opacity) * 100;
            }
            try {
                return e.filters.item('alpha').opacity
            } catch (o) {
                return 100;
            }
        }

        // 渐隐渐显动画显示函数
        // 参数:e表示渐隐渐显元素,t表示渐隐渐显的速度,值越大渐隐渐显速度越慢,io表示渐隐或渐显方式,取值true表示渐显,取值false表示渐隐
        function fade(e, t, io) {
            var t = t || 10; // 初始化渐隐渐显速度
            if (io) { // 初始化渐隐渐显方式
                var i = 0;
            } else {
                var i = 100;
            }
            var out = setInterval(function() { // 设计定时器
                setOpacity(e, i); // 调用setOpacity()函数
                if (io) { // 根据渐隐或渐显方式决定执行效果
                    i++;
                    if (i >= 100) clearTimeout(out);
                } else {
                    i--;
                    if (i <= 0) clearTimeout(out);
                }
            }, t);
        }
    </script>
</head>

<body>

    <style type="text/css">
        .block {
            width: 200px;
            height: 200px;
            background-color: red;
        }
    </style>
    <div class="block" id="block1"></div>
    <input type="submit" id="btn" value="渐隐渐显" />
    <script>
        e = document.getElementById('block1');
        btn = document.getElementById('btn');

        btn.onclick = function() {
            fade(e, 100, true); // 应用渐隐渐显动画效果
        }
    </script>

</body>

</html>

- Book Lists -