Spiga

自制原生js工具库——CSS篇

2008-05-08 12:28:02

源码

/* ******************************************************************* */
/*   CSS FUNCTIONS                                                     */
/* ******************************************************************* */
var CSS = (function() {
    var css = {};
​
    // 转换的RGB字符串的形式“的RGB ( 255 , 255 , 255 ) ”到“ #ffffff ”
    css.rgb2hex = function(rgbString) {
        if (typeof (rgbString) != "string" || !defined(rgbString.match)) { return null; }
        var result = rgbString.match(/^\s*rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*/);
        if (result == null) { return rgbString; }
        var rgb = +result[1] << 16 | +result[2] << 8 | +result[3];
        var hex = "";
        var digits = "0123456789abcdef";
        while (rgb != 0) {
            hex = digits.charAt(rgb & 0xf) + hex;
            rgb >>>= 4;
        }
        while (hex.length < 6) { hex = '0' + hex; }
        return "#" + hex;
    };
​
    // 转换字符样式
    css.hyphen2camel = function(property) {
        if (!defined(property) || property == null) { return null; }
        if (property.indexOf("-") < 0) { return property; }
        var str = "";
        var c = null;
        var l = property.length;
        for (var i = 0; i < l; i++) {
            c = property.charAt(i);
            str += (c != "-") ? c : property.charAt(++i).toUpperCase();
        }
        return str;
    };
​
    // 获取元素的真实、最终的css样式属性
    css.getStyle = function(elem, name) {
        //如果属性存在于style[]中,那么它已经被设置了
        if (elem.style[name])
            return elem.style[name];
​
        // 否则尝试使用IE的方法
        else if (elem.currentStyle)
            return elem.currentStyle[name];
​
        // 或者W3C的方法,如果存在的话
        else if (document.defaultView && document.defaultView.getComputedStyle) {
            // 使用的是通用的‘text_aligh’的样式规则或非‘textAligh’
            name = name.replace(/([A-Z])/g, "-$1");
            name = name.toLowerCase();
​
            //获取样式对象并获取属性值
            var s = document.defaultView.getComputedStyle(elem, "");
            return s && s.getPropertyValue(name);
​
            //否则用户使用的是其他浏览器
        } else
            return null;
    };
    css.get = css.getStyle;
​
    // 获取元素的css样式属性
    css.setStyle = function(o, property, value) {
        if (o == null || !defined(o.style) || !defined(property) || property == null || !defined(value)) { return false; }
        if (property == "float") {
            o.style["cssFloat"] = value;
            o.style["styleFloat"] = value;
        }
        else if (property == "opacity") {
            o.style['-moz-opacity'] = value;
            o.style['-khtml-opacity'] = value;
            o.style.opacity = value;
            if (defined(o.style.filter)) {
                o.style.filter = "alpha( opacity=" + value * 100 + " )";
            }
        }
        else {
            o.style[css.hyphen2camel(property)] = value;
        }
        return true;
    };
    css.set = css.setStyle;
​
    // 获取元素的x位置
    css.pageX = function(elem) {
        var p = 0;
​
        //查看我们是否位于根元素
        while (elem.offsetParent) {
            // 如果我们能继续得到上一个元素,增加当前的偏移量并继续向上递归
            p += elem.offsetLeft;
​
            //否则获取当前的偏移量
            elem = elem.offsetParent;
        }
​
        return p;
    };
​
    //获取元素的y位置
    css.pageY = function(elem) {
        var p = 0;
​
        //查看我们是否位于根元素
        while (elem.offsetParent) {
            // 如果我们能继续得到上一个元素,增加当前的偏移量并继续向上递归
            p += elem.offsetTop;
​
            //否则获取当前的偏移量
            elem = elem.offsetParent;
        }
​
        return p;
    };
​
    //获取元素相对于父亲的水平位置
    css.parentX = function(elem) {
        // 如果 offsetParent 是元素的父亲,那么提前退去
        return elem.parentNode == elem.offsetParent ? elem.offsetLeft :
​
        // 否则我们需要找到元素和元素的父亲相对于整个页面位置,并计算它们之间的距离
            css.pageX(elem) - css.pageX(elem.parentNode);
    };
​
    //获取元素相对于父亲的垂直位置
    css.parentY = function(elem) {
        // 如果 offsetParent 是元素的父亲,那么提前退去
        return elem.parentNode == elem.offsetParent ? elem.offsetTop :
​
        // 否则我们需要找到元素和元素的父亲相对于整个页面位置,并计算它们之间的距离
            css.pageY(elem) - css.pageY(elem.parentNode);
    };
​
    // 查找元素的左端位置
    css.posX = function(elem) {
        // 获取最终样式并得到数值
        return parseInt(css.getStyle(elem, "left"));
    };
​
    // 查找元素的顶端位置
    css.posY = function(elem) {
        // 获取最终样式并得到数值
        return parseInt(css.getStyle(elem, "top"));
    };
​
    //设置元素水平位置
    css.setX = function(elem, pos) {
        // 使用像素单位设置CSS的‘left’属性
        elem.style.left = pos + "px";
    };
​
    //设置元素垂直位置
    css.setY = function(elem, pos) {
        // 使用像素单位设置CSS的’top‘属性
        elem.style.top = pos + "px";
    };
​
    // 在元素的水平位置上增加像素距离
    css.addX = function(elem, pos) {
        // 获取当前水平位置,然后增加偏移量
        css.setX(elem, css.posX(elem) + pos);
    };
​
    // 在元素的垂直位置上增加像素距离
    css.addY = function(elem, pos) {
        // 获取当前垂直位置,然后增加偏移量
        css.setY(elem, css.posY(elem) + pos);
    };
​
    // 获取元素真实的高度
    css.getHeight = function(elem) {
        // 获取CSS最终值并解析出可用的数值
        return parseInt(css.getStyle(elem, "height"));
    };
​
    // 获取元素的真实宽度
    css.getWidth = function(elem) {
        // 获取CSS最终值并解析出可用的数值
        return parseInt(css.getStyle(elem, "width"));
    };
​
    // 查找元素完整的、可能的高度
    css.fullHeight = function(elem) {
        // 如果元素是显示的,那么使用offsetHeight就能得到高度
        if (css.getStyle(elem, "display") != "none")
            return elem.offsetHeight || css.getHeight(elem);
​
        //否则我们必须处理display为none的元素,所有重置它的CSS属性以获得更精确的读数
        var old = resetCSS(elem, {
            display: '',
            visibility: 'hidden',
            position: 'absolute'
        });
​
        // 使用clientHeight找出完整高度,如果还不生效使用getHeight
        var h = elem.clientHeight || css.getHeight(elem);
​
        // 最后不要忘了恢复css原有属性
        css.restoreCSS(elem, old);
​
        // 并返回元素的完整高度
        return h;
    };
​
    // 查找元素完整的、可能的宽度
    css.fullWidth = function(elem) {
        // 如果元素是显示的,那么使用offsetWidth就能得到宽度
        if (css.getStyle(elem, "display") != "none")
            return elem.offsetWidth || css.getWidth(elem);
​
        //否则我们必须处理display为none的元素,所有重置它的CSS属性以获得更精确的读数
        var old = resetCSS(elem, {
            display: "",
            visibility: "hidden",
            position: "absolute"
        });
​
        // 使用clientWidth找出完整高度,如果还不生效使用getWidth
        var w = elem.clientWidth || css.getWidth(elem);
​
        // 最后不要忘了恢复css原有属性
        css.restoreCSS(elem, old);
​
        // 并返回元素的完整高度
        return w;
    };
​
    // 设置css一组属性的函数,它可以恢复到原有设置
    css.resetCSS = function(elem, prop) {
        var old = {};
​
        // 遍历每一个属性
        for (var i in prop) {
            // 记录旧的属性值
            old[i] = elem.style[i];
​
            // 设置新的值
            elem.style[i] = prop[i];
        }
​
        // 返回已经变化的值的集合,预留给restoreCSS函数使用
        return old;
    };
​
    // 恢复css原有属性值,防止resetCSS函数的副作用
    css.restoreCSS = function(elem, prop) {
        // 重置所有属性,恢复它们的原有值
        for (var i in prop)
            elem.style[i] = prop[i];
    };
​
    // 使用display隐藏元素
    css.hide = function(elem) {
        // 使用display隐藏元素
        var curDisplay = css.getStyle(elem, 'display');
​
        // 记录它的display状态
        if (curDisplay != 'none')
            elem.$oldDisplay = curDisplay;
​
        // 设置display为none
        elem.style.display = 'none';
    };
​
    // 使用display显示元素
    css.show = function(elem) {
        // 设置display属性为它原始值,如果没有记录则设置成‘block’
        elem.style.display = elem.$oldDisplay || 'block';
    };
​
    // 调节元素透明度
    css.setOpacity = function(elem, level) {
        // 如果存在filters这个属性,则它是IE,所以设置元素的alpha滤镜
        if (elem.filters)
            elem.style.filters = 'alpha(opacity=' + level + ')';
        // 否则使用W3C的opacity属性
        else
            elem.style.opacity = level / 100;
    };
​
    //通过短时间内增加高度逐步显示隐藏元素
    css.slideDown = function(elem) {
        // 从0高度开始滑动
        elem.style.height = '0px';
​
        // 先显示元素(但是它看不到,因为高度为0)
        css.show(elem);
​
        // 找到元素的完整的潜在高度
        var h = css.fullHeight(elem);
​
        // 我们1秒内执行一个20帧的动画
        for (var i = 0; i <= 100; i += 5) {
            // 保证我们能够保持正确的'i'的闭包函数
            (function() {
                var pos = i;
​
                // 设置timeout以让它能在指定的时间点运行
                setTimeout(function() {
​
                    // 设置元素的新高度
                    elem.style.height = (pos / 100) * h + "px";
​
                }, (pos + 1) * 10);
            })();
        }
    };
​
    //通过在短时间内增加透明度逐步显示隐藏元素
    css.fadeIn = function(elem) {
        // 从0透明度开始
        css.setOpacity(elem, 0);
​
        // 先显示元素(但是它看不到,因为透明度为0)
        css.show(elem);
​
        // 我们1秒内执行一个20帧的动画
        for (var i = 0; i <= 100; i += 5) {
            // 保证我们能够保持正确的'i'的闭包函数
            (function() {
                var pos = i;
​
                // 设置timeout以让它能在指定的时间点运行
                setTimeout(function() {
​
                    // 设置元素的新透明度
                    css.setOpacity(elem, pos);
​
                }, (pos + 1) * 10);
            })();
        }
    };
​
    // 获取光标的水平位置
    css.getX = function(e) {
        // 标准化事件对象
        e = e || window.event;
​
        // 先检查非IE浏览器的位置,再检查IE的位置
        return e.pageX || e.clientX + document.body.scrollLeft || 0;
    };
​
    // 获取光标的垂直位置
    css.getY = function(e) {
        // 标准化事件对象
        e = e || window.event;
​
        // 先检查非IE浏览器的位置,再检查IE的位置
        return e.pageY || e.clientY + document.body.scrollTop || 0;
    };
​
    // 获取鼠标相对于当前元素的x位置
    css.getElementX = function(e) {
        // 获取鼠标相对于当前元素的x位置
        return (e && e.layerX) || window.event.offsetX;
    };
​
    // 获取鼠标相对于当前元素的y位置
    css.getElementY = function(e) {
        // 获取鼠标相对于当前元素的x位置
        return (e && e.layerY) || window.event.offsetY;
    };
​
    // 获取页面的高度
    css.pageHeight = function() {
        return document.body.scrollHeight;
    };
​
    // 获取页面的宽带
    css.pageWidth = function() {
        return document.body.scrollWidth;
    };
​
    // 确定浏览器水平滚动位置
    css.scrollX = function() {
        // 一个快捷方式,用在IE6/7的严格模式中
        var de = document.documentElement;
​
        // 如果浏览器存在pageXOffset,则使用它
        return self.pageXOffset ||
​
        //否则尝试获取根节点的左端滚动的偏移量
            (de && de.scrollLeft) ||
​
        // 最后尝试取body元素的左端滚动的偏移量
            document.body.scrollLeft;
    };
​
    // 确定浏览器垂直滚动位置
    css.scrollY = function() {
        // 一个快捷方式,用在IE6/7的严格模式中
        var de = document.documentElement;
​
        // 如果浏览器存在pageYOffset,则使用它
        return self.pageYOffset ||
​
        //否则尝试获取根节点的顶端滚动的偏移量
            (de && de.scrollTop) ||
​
        // 最后尝试取body元素的顶端滚动的偏移量
            document.body.scrollTop;
    };
​
    // 获取视口的高度
    css.windowHeight = function() {
        // 一个快捷方式,用在IE6/7的严格模式中
        var de = document.documentElement;
​
        // 如果浏览器存在innerHeight,则使用它
        return self.innerHeight ||
​
        //否则尝试获取根节点高度偏移量
            (de && de.clientHeight) ||
​
        // 最后尝试取body元素的高度偏移量
            document.body.clientHeight;
    };
​
    // 获取视口的宽度
    css.windowWidth = function() {
        // 一个快捷方式,用在IE6/7的严格模式中
        var de = document.documentElement;
​
        // 如果浏览器存在innerWidth,则使用它
        return self.innerWidth ||
​
        //否则尝试获取根节点宽度偏移量
            (de && de.clientWidth) ||
​
        // 最后尝试取body元素的宽度偏移量
            document.body.clientWidth;
    };
​
    // 判断对象是否包含一个类
    css.hasClass = function(obj, className) {
        if (!defined(obj) || obj == null || !RegExp) { return false; }
        var re = new RegExp("(^|\\s)" + className + "(\\s|$)");
        if (typeof (obj) == "string") {
            return re.test(obj);
        }
        else if (typeof (obj) == "object" && obj.className) {
            return re.test(obj.className);
        }
        return false;
    };
​
    // 给对象添加一个类
    css.addClass = function(obj, className) {
        if (typeof (obj) != "object" || obj == null || !defined(obj.className)) { return false; }
        if (obj.className == null || obj.className == '') {
            obj.className = className;
            return true;
        }
        if (css.hasClass(obj, className)) { return true; }
        obj.className = obj.className + " " + className;
        return true;
    };
​
    // 给对象删除一个类
    css.removeClass = function(obj, className) {
        if (typeof (obj) != "object" || obj == null || !defined(obj.className) || obj.className == null) { return false; }
        if (!css.hasClass(obj, className)) { return false; }
        var re = new RegExp("(^|\\s+)" + className + "(\\s+|$)");
        obj.className = obj.className.replace(re, ' ');
        return true;
    };
​
    // 给对象替换一个类
    css.replaceClass = function(obj, className, newClassName) {
        if (typeof (obj) != "object" || obj == null || !defined(obj.className) || obj.className == null) { return false; }
        css.removeClass(obj, className);
        css.addClass(obj, newClassName);
        return true;
    };
​
    return css;
})();

范例

function test_css()
{
    var parentB = id("parentB");
    alert(CSS.rgb2hex("rgb(255,0,0)"));
    alert(CSS.hyphen2camel("rgb(255,0,0)"));
    alert(CSS.hyphen2camel("list-style-type"));
    CSS.setStyle(parentB, "hight", "200px");
    alert(CSS.getStyle(parentB, "hight"));
    alert(CSS.pageX(parentB));
    alert(CSS.pageY(parentB));
    alert(CSS.parentX(parentB));
    alert(CSS.parentY(parentB));
    CSS.setX(parentB, 100);
    CSS.setY(parentB, 200);
    CSS.addX(parentB, 100);
    CSS.addY(parentB, 200);
    alert(CSS.posX(parentB));
    alert(CSS.posY(parentB));
    alert(CSS.getHeight(parentB));
    alert(CSS.getWidth(parentB));
    alert(CSS.fullHeight(parentB));
    alert(CSS.fullWidth(parentB));
}
​
function test_css_result()
{
    var parentB = id("parentB");
    var arr = ['hight:500px'];
    var old = CSS.resetCSS(parentB, arr);
    CSS.hide(parentB);
    CSS.show(parentB);
    CSS.setOpacity(parentB, 50);
    CSS.slideDown(parentB);
    CSS.fadeIn(parentB);
    alert(CSS.getX());
    alert(CSS.getY());
    alert(CSS.getElementX());
    alert(CSS.getElementY());
    alert(CSS.pageHeight());
    alert(CSS.pageWidth());
    alert(CSS.scrollX());
    alert(CSS.scrollY());
    alert(CSS.windowHeight());
    alert(CSS.windowWidth());
}
​
function test_css_class()
{
    var parentB = id("parentB");
    alert(CSS.hasClass(parentB, "classB"));
    CSS.addClass(parentB, "classC");
    CSS.removeClass(parentB, "classC");
    CSS.replaceClass(parentB, "classB", "classC");
}