![](/img/trans.png)
[英]Convert external and internal styles into inline styles with javascript
[英]How to convert external/internal css styles into inline style-attribute using client-side javascript
例如,如果我有包含在文档中的 CSS:
div {
color: red;
}
div.test {
border: 1px solid blue;
}
和文档正文中的 html 标签:
<div id='demo'>
<div class='test'>123</div>
<div>456</div>
</div>
我想将#demo
中的所有内容都转换为一个字符串,其中包含它使用的所有样式的标签,例如:
var parent = $('#demo');
var result = convertExternalInternalStylesToInline(parent);
// the desired result:
result = '<div style="color: red; border: 1px solid blue;">123</div>' +
'<div style="color: red">456</div>'
我需要的是convertExternalInternalStylesToInline
函数的内容,它自动获取所有后代元素,应用计算/使用的样式,然后将 css 样式添加到这些元素,然后将其全部作为 html 字符串返回。
可以仅使用客户端javascript
来完成吗? 如果是,如何?
(我需要知道如何获取标签的所有计算/使用的样式)
最小的例子:
function convertExternalInternalStylesToInline(parent) {
var parent = $(parent).clone(); // clone it before modify, is this deep clone?
parent.find('*').each(function(idx,el){ // fetch all children
var el = $(el); // convert to jquery object
// get all applied styles on this element
// el.? // --> don't know how
// apply css for each styles
el.css( css_prop, css_style );
});
// return as string, maybe:
return parent.html();
}
编辑:感谢Winchestro,我查找了window.getMatchedCSSRules
函数,该函数实际上仅在Webkit中存在,并且有一个讨论,建议不要使用它 。
您实际上应该使用的是window.getComputedStyle()
阅读MDN上的文档 。
您可能要研究的另一个非常有用的资源是CSSUtilities库集 。
您需要做的是两件事,一个库来解析CSS对象模态(CSSOM),然后将相关CSS应用于DOM元素。
我知道一个很好的nodejs库,它叫做Juice 。
我发现有一个库可能在前端工作,称为inlineresources ,它具有浏览器化的版本
再三考虑,我想您也许可以将Juice和browserify一起使用...但是您必须手动评估这种可能性...
假设你有一个数组中的 HTML(行:string[]):
我不知道为什么我花了这么多时间在这上面
let styleLines = this.getLinesInsideStyleTag(lines)
let htmlLinesSeparatedByTag = this.getLinesNotInsideStyleTag(lines)
let mapOfCSSrules = this.getMapOfCSSRuleNamesAndPropertiesFromCSSLines(styleLines)
let linesWithInlineRulesApplied = this.applyInlineStylesToLines(htmlLinesSeparatedByTag, mapOfCSSrules)
let finalString = ""
for(let v = 0; v < linesWithInlineRulesApplied.length; v++ ) {
finalString = finalString + linesWithInlineRulesApplied[v]
}
console.log(finalString)
getLinesInsideStyleTag(lines: any[]) {
let styleLines: any[] = []
let foundStylesStartTag = false
let foundStylesEndTag = false
for(let i = 0; i < lines.length; i++ ) {
if(lines[i].indexOf("<style ") != -1) {
foundStylesStartTag=true
} else if(lines[i].indexOf("</style>") != -1) {
foundStylesEndTag = true
}
if(foundStylesStartTag == true && foundStylesEndTag == false) {
if(lines[i].indexOf("<style") == -1 && lines[i].indexOf("</style") == -1) {
styleLines.push(lines[i])
}
}
// console.log("lines[i] after: ")
// console.log(lines[i])
}
return styleLines
}
getLinesNotInsideStyleTag(lines: any[]) {
let foundStylesStartTag = false
let foundStylesEndTag = false
let linesToKeep: any[] = []
for(let i = 0; i < lines.length; i++ ) {
if(lines[i].indexOf("<style ") != -1) {
foundStylesStartTag=true
} else if(lines[i].indexOf("</style>") != -1) {
foundStylesEndTag = true
}
if(foundStylesStartTag == false && foundStylesEndTag == false) {
linesToKeep.push(lines[i])
} else if(foundStylesStartTag == true && foundStylesEndTag == true) {
if(lines[i].indexOf("<style") == -1 && lines[i].indexOf("</style") == -1) {
linesToKeep.push(lines[i])
}
}
}
let actualLinesToKeep: any[] = []
for(let i = 0; i < linesToKeep.length; i++ ){
let thisLineSplitOnOpeningTag = linesToKeep[i].split("<")
let pushFullLine = false
let modifiedLine = ""
for(let y = 0; y < thisLineSplitOnOpeningTag.length; y++) {
if(thisLineSplitOnOpeningTag[0] !== "") {
pushFullLine = true
} else {
if(thisLineSplitOnOpeningTag.length > 2) {
//then the line contains nested tags (oof)
if(thisLineSplitOnOpeningTag[y].length > 0) {
if( y != thisLineSplitOnOpeningTag.length - 1) {
modifiedLine = modifiedLine + "<" + thisLineSplitOnOpeningTag[y]+"%*#"
} else {
modifiedLine = modifiedLine + "<" + thisLineSplitOnOpeningTag[y]
}
}
} else {
pushFullLine = true
}
}
}
if(pushFullLine == true) {
// console.log("3pushing full line because it doesn't have nested tags: "+linesToKeep[i])
actualLinesToKeep.push(linesToKeep[i])
} else {
actualLinesToKeep.push(modifiedLine)
}
}
// console.log("actualLinesToKeep: ")
// console.log(actualLinesToKeep)
return actualLinesToKeep
}
//e.g. you pass it
// myRule {
// color: blue;
// text-align: left;
// }
// you get back: a dictionary / map where "myRule" is the key, and "color: blue;" and "text-align: left;" are the values for that key.
getMapOfCSSRuleNamesAndPropertiesFromCSSLines(styleLines: any[]) {
// console.log("styleLines: ")
// console.log(styleLines)
//rule, properties
let CSSrules: Map<string,any[]> = new Map();
let rulesSplitOnClosingBracket = styleLines.toString().split("}")
for(let i = 0; i < rulesSplitOnClosingBracket.length; i++) {
let indexOfOpeningBracket = rulesSplitOnClosingBracket[i].indexOf("{")
let ruleName = rulesSplitOnClosingBracket[i].substring(0,indexOfOpeningBracket).trim()
ruleName = this.replaceAll(ruleName,",","").toLowerCase()
if(ruleName[0] === ".") {
ruleName = ruleName.substring(1)
}
//replace dots with a space
ruleName = ruleName.replace(/\./g,' ')
let propertiesOfThisRule = rulesSplitOnClosingBracket[i].substring(indexOfOpeningBracket+1).split(",")
let propertiesToKeep: any[] = []
for(let j = 0; j < propertiesOfThisRule.length; j++) {
propertiesOfThisRule[j] = propertiesOfThisRule[j].trim()
if(propertiesOfThisRule[j] !== undefined && propertiesOfThisRule[j].length > 0) {
propertiesToKeep.push(propertiesOfThisRule[j])
}
}
if(ruleName !== undefined && ruleName.length > 0 && propertiesToKeep !== undefined && propertiesToKeep.length > 0) {
CSSrules.set(ruleName, propertiesToKeep)
}
}
return CSSrules
}
applyInlineStylesToLines(htmlLinesSeparatedByTag: any[], mapOfCSSrules: Map<string,any[]>) {
let linesWithInlineRulesApplied: any[] = []
let ruleNames = Array.from(mapOfCSSrules.keys())
for(let r = 0; r < htmlLinesSeparatedByTag.length; r++) {
let lineSplitOnContinuationCharacter = htmlLinesSeparatedByTag[r].split("%*#")
let partsOfLineThatContainClosingTags: any[] = []
let partsOfLineThatDoNotContainClosingTags: any[] = []
for(let d = 0; d < lineSplitOnContinuationCharacter.length; d++) {
if(lineSplitOnContinuationCharacter[d].indexOf("</") != -1) {
partsOfLineThatContainClosingTags.push({orderNumber: d, line: lineSplitOnContinuationCharacter[d]})
} else if(lineSplitOnContinuationCharacter[d].indexOf("</") == -1) {
partsOfLineThatDoNotContainClosingTags.push({orderNumber: d, line: lineSplitOnContinuationCharacter[d]})
}
}
let orderNumbers1: any[number] = partsOfLineThatDoNotContainClosingTags.map(val => val.orderNumber)
let orderNumbers2: any[number] = partsOfLineThatContainClosingTags.map(val => val.orderNumber)
let maxOrderNumberFor1 = Math.max.apply(Math,orderNumbers1)
let maxOrderNumberFor2 = Math.max.apply(Math,orderNumbers2)
let maxOrderNumber: number;
if(maxOrderNumberFor1 > maxOrderNumberFor2) {
maxOrderNumber = maxOrderNumberFor1
} else {
maxOrderNumber = maxOrderNumberFor2
}
let thisActualLineWithStylesApplied = ""
for(let u = 0; u < maxOrderNumber+1; u++) {
let partOfLineWithoutClosingTag = partsOfLineThatDoNotContainClosingTags.filter(val => val.orderNumber == u)[0]?.line
let partOfLineWithClosingTag = partsOfLineThatContainClosingTags.filter(val => val.orderNumber == u)[0]?.line
if ( partOfLineWithoutClosingTag !== undefined ) {
let idxOfFirstSpace = partOfLineWithoutClosingTag.indexOf(" ")
for(let s = 0; s < ruleNames.length; s++) {
let applyThisRuleToThisLine = true
let textToCheckFor: any[] = ruleNames[s].split(" ")
for(let t = 0; t < textToCheckFor.length; t++) {
if(partOfLineWithoutClosingTag.indexOf(textToCheckFor[t]) == -1) {
applyThisRuleToThisLine = false
}
}
if(applyThisRuleToThisLine) {
let lineAfterApplyingStyle = partOfLineWithoutClosingTag.substring(0, idxOfFirstSpace) +" style=\""
for(let u = 0; u < mapOfCSSrules.get(ruleNames[s]).length; u++) {
let thisPropertyToApply = mapOfCSSrules.get(ruleNames[s])[u]
lineAfterApplyingStyle=lineAfterApplyingStyle+thisPropertyToApply
}
lineAfterApplyingStyle = lineAfterApplyingStyle +"\""
partOfLineWithoutClosingTag = lineAfterApplyingStyle + partOfLineWithoutClosingTag
let lastIndexOfLessThan = partOfLineWithoutClosingTag.lastIndexOf("<")
let lastIndexOfGreaterThan = partOfLineWithoutClosingTag.lastIndexOf(">")
partOfLineWithoutClosingTag = partOfLineWithoutClosingTag.substring(0,lastIndexOfLessThan) + partOfLineWithoutClosingTag.substring(lastIndexOfGreaterThan)
}
}
thisActualLineWithStylesApplied = thisActualLineWithStylesApplied + partOfLineWithoutClosingTag
}
if(partOfLineWithClosingTag !== undefined) {
thisActualLineWithStylesApplied = thisActualLineWithStylesApplied + partOfLineWithClosingTag
}
}
linesWithInlineRulesApplied.push(thisActualLineWithStylesApplied)
}
return linesWithInlineRulesApplied
}
编辑:感谢Kumar,我意识到我建议的方法是非标准的,并且
getComputedStyle( element );
应该改用,这会更难使用和过滤,但是具有的优点是,仅提供评估CSS后实际应用于元素的最终规则(还包括默认样式,而不是显式声明的样式,从而使其在这种情况下使用起来有点棘手)。
getMatchedCSSRules( element );
只需使用此香草javascript函数即可。 它正是您想要的。 如果有任何要解释的功能名称未暗示的内容,我将进行解释。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.