Javascript 转换css单位

Javascript 转换css单位,javascript,css,Javascript,Css,我正在尝试以所有有效的“长度”和“百分比”单位从该属性的原始值集转换回来一个样式属性 e、 例如,如果我有一个将style.width设置为20%的div,我希望返回一个对象,该值以百分比(当然是20%)、像素(不管实际像素宽度是多少)、em、pt、ex等为单位 我意识到“百分比”不是“长度”值,并且不是所有接受长度值的属性都接受百分比,但也希望包括百分比 当然,某些值将具体取决于元素,并且可能取决于元素在DOM中的位置(例如,获取em值也需要元素的父计算字体大小) 我可以假设样式是为元素显式设

我正在尝试以所有有效的“长度”和“百分比”单位从该属性的原始值集转换回来一个样式属性

e、 例如,如果我有一个将style.width设置为20%的div,我希望返回一个对象,该值以百分比(当然是20%)、像素(不管实际像素宽度是多少)、em、pt、ex等为单位

我意识到“百分比”不是“长度”值,并且不是所有接受长度值的属性都接受百分比,但也希望包括百分比

当然,某些值将具体取决于元素,并且可能取决于元素在DOM中的位置(例如,获取em值也需要元素的父计算字体大小)

我可以假设样式是为元素显式设置的——我知道如何检索元素的当前计算样式——我只是希望不要重复其他人可能已经完成的工作。我也知道,但它依赖于style.pixelWidth或node.clientWidth,在Chrome中失败(我假设它在Safari中也失败了……可能还有其他)

我已经计算出了颜色值(rgb、rgba、十六进制、名称)-这当然要简单得多。我使用的值在数学上是可变的,因此实际上只需要“length”和“percent”值(如果对具有非长度、非percent值的属性集(如“font size:larger”)调用,函数可能会失败或抛出错误)

如果按程序编写,这样的内容将是理想的:

function getUnits(target, prop){
  var value = // get target's computed style property value
  // figure out what unit is being used natively, and it's values - for this e.g., 100px
  var units = {};
  units.pixel = 100;
  units.percent = 50;  // e.g., if the prop was height and the parent was 200px tall
  units.inch = 1.39;  // presumably units.pixel / 72 would work, but i'm not positive
  units.point = units.inch / 72;
  units.pica = units.point * 12;
  // etc...
  return units;
}
我不是要求有人为我写代码,但我希望有人以前已经做过,并且它可以在一些开源库、框架、博客文章、图坦卡蒙(tut)中找到。如果失败了,如果有人有一个聪明的想法如何简化流程,那也太好了(上面链接的作者创建了一个临时div,并计算了一个值来确定其他单位的比率——这是一个方便的想法,但不是一个我完全相信的想法,而且肯定需要补充逻辑来处理我希望接受的一切)

提前感谢您提供的任何见解或建议。

可以做到这一点,特别是在其
解析
功能中:

function parse(prop){
    var p = parseFloat(prop), q = prop.replace(/^[\-\d\.]+/,'');
    return isNaN(p) ? { v: q, f: color, u: ''} : { v: p, f: interpolate, u: q };
}
prop
参数是某个元素的computedStyle。返回的对象有一个
v
属性(值)、一个
f
方法(以后仅用于动画)和一个
u
属性(值的单位,如有必要)


这并不能完全回答这个问题,但这可能是一个开始。

编辑:更新以允许用户选择要返回的单个单元(例如,存在为%,返回px)-当这足够时,性能会有很大的提高-可能最终会将其更改为只接受一个单位进行转换,并消除循环。多亏了Epileless的帮助。/EDIT

这就是我所想到的——经过初步测试,它似乎起了作用。我从原始问题中提到的链接中借用了临时div的概念,但这就是从另一个类中获得的全部内容

如果有人有任何意见或改进,我很乐意听到

   (function(){

    // pass to string.replace for camel to hyphen
    var hyphenate = function(a, b, c){
        return b + "-" + c.toLowerCase();
    }

    // get computed style property
    var getStyle = function(target, prop){
        if(prop in target.style){  // if it's explicitly assigned, just grab that
            if(!!(target.style[prop]) || target.style[prop] === 0){
                return target.style[prop];
            }
        }
        if(window.getComputedStyle){ // gecko and webkit
            prop = prop.replace(/([a-z])([A-Z])/, hyphenate);  // requires hyphenated, not camel
            return window.getComputedStyle(target, null).getPropertyValue(prop);
        }
        if(target.currentStyle){ // ie
            return target.currentStyle[prop];
        }
        return null;
    }

    // get object with units
    var getUnits = function(target, prop, returnUnit){

        var baseline = 100;  // any number serves 
        var item;  // generic iterator

        var map = {  // list of all units and their identifying string
            pixel : "px",
            percent : "%",
            inch : "in",
            cm : "cm",
            mm : "mm",
            point : "pt",
            pica : "pc",
            em : "em",
            ex : "ex"
        };

        var factors = {};  // holds ratios
        var units = {};  // holds calculated values

        var value = getStyle(target, prop);  // get the computed style value

        var numeric = value.match(/\d+/);  // get the numeric component
        if(numeric === null) {  // if match returns null, throw error...  use === so 0 values are accepted
            throw "Invalid property value returned";
        }
        numeric = numeric[0];  // get the string

        var unit = value.match(/\D+$/);  // get the existing unit
        unit = (unit == null) ? "px" : unit[0]; // if its not set, assume px - otherwise grab string

        var activeMap;  // a reference to the map key for the existing unit
        for(item in map){
            if(map[item] == unit){
                activeMap = item;
                break;
            }
        }
        if(!activeMap) { // if existing unit isn't in the map, throw an error
            throw "Unit not found in map";
        }

        var singleUnit = false;  // return object (all units) or string (one unit)?
        if(returnUnit && (typeof returnUnit == "string")) {  // if user wants only one unit returned, delete other maps
            for(item in map){
                if(map[item] == returnUnit){
                    singleUnit = item;
                    continue;
                }
                delete map[item];
            }
        }

        var temp = document.createElement("div");  // create temporary element
        temp.style.overflow = "hidden";  // in case baseline is set too low
        temp.style.visibility = "hidden";  // no need to show it

        target.parentNode.appendChild(temp);    // insert it into the parent for em and ex  

        for(item in map){  // set the style for each unit, then calculate it's relative value against the baseline
            temp.style.width = baseline + map[item];
            factors[item] = baseline / temp.offsetWidth;
        }

        for(item in map){  // use the ratios figured in the above loop to determine converted values
            units[item] = (numeric * (factors[item] * factors[activeMap])) + map[item];
        }

        target.parentNode.removeChild(temp);  // clean up

        if(singleUnit !== false){  // if they just want one unit back
            return units[singleUnit];
        }

        return units;  // returns the object with converted unit values...

    }

    // expose           
    window.getUnits = this.getUnits = getUnits;

})();
tyia

签出,一个进行这些转换的JavaScript库


作者描述代码。

晚会迟到了,我认为这不一定能完全回答这个问题,因为我没有包括百分比的转换。但是,我确实认为这是一个很好的开始,可以根据您的具体用途轻松修改

Javascript函数

/**
*将绝对CSS数值转换为像素。
*
*@linkhttps://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units#numbers_lengths_and_percentages
*
*@param{string}cssValue
*@param{null | HTMLElement}目标用于相对单位。
*@return{*}
*/
window.convertCssUnit=函数(CSS值,目标){
target=target | | document.body;
const supportedUnits={
//绝对尺寸
“px”:值=>value,
“cm”:值=>值*38,
“mm”:值=>值*3.8,
“q”:值=>值*0.95,
“in”:值=>值*96,
“pc”:值=>值*16,
“pt”:值=>值*1.333333,
//相对尺寸
“rem”:value=>value*parseFloat(getComputedStyle(document.documentElement.fontSize),
“em”:value=>value*parseFloat(getComputedStyle(target).fontSize),
“vw”:值=>value/100*window.innerWidth,
“vh”:值=>value/100*window.innerHeight,
//时代
'ms':值=>value,
“s”:值=>值*1000,
//角度
“度”:值=>值,
“rad”:value=>value*(180/Math.PI),
“梯度”:值=>值*(180/200),
“转动”:值=>值*360
};
//将正数和负数(包括小数)与以下单位匹配
const pattern=new RegExp(`^([\-\+]?(?:\\d+(?:\\\.\\d+)))(${Object.keys(supportedUnits.join('\-\+')})$`i');
//如果是匹配项,则返回示例:[“-2.75rem”、“-2.75”、“rem”]
const matches=String.prototype.toString.apply(cssValue.trim().match(pattern);
如果(匹配){
常量值=数量(匹配[1]);
const unit=匹配[2]。toLocaleLowerCase();
//健全性检查,确保单位转换功能存在
if(支持单元中的单元){
返回支持的单位[单位](值);
}
}
返回css值;
};
示例用法

//将rem值转换为像素
const remExample=convertCssUnit('2.5rem');
//将时间单位(秒)转换为毫秒
const speedExample=convertCssUnit('2s');
//将角度单位(梯度)转换为度
常量emExample=convertCssUnit('200grad');
//将vw值转换为像素
const vw示例=convertCssUnit('80vw');
//将css变量转换为像素
康斯特瓦
10rem
10.2em
-0.34cm
+10.567s