sass嵌套格式字符串转css对象
问题场景
monaco-editor编辑器获取嵌套css样式,图示(左边格式的string转右边格式),需要将其转换成css格式,并以<style>标签格式动态添加到dom里

代码实现
cssjson.js
/** * css转json对象 * author:liupeng * githubUrl: https://github.com/search?q=css+js&type=Repositories */ class Cssjson { // String functions // String.prototype.trim = function() { // return this.replace(/^\s+|\s+$/g, '') // } // String.prototype.repeat = function(n) { // return new Array(1 + n).join(this) // } // var selX = /([^\s\;\{\}][^\;\{\}]*)\{/g // var endX = /\}/g // var lineX = /([^\;\{\}]*)\;/g /** * Input is css string and current pos, returns JSON object * * @param cssString * The CSS string. * @param args * An optional argument object. ordered: Whether order of * comments and other nodes should be kept in the output. This * will return an object where all the keys are numbers and the * values are objects containing "name" and "value" keys for each * node. comments: Whether to capture comments. split: Whether to * split each comma separated list of selectors. */ toJSON(cssString, args) { if (!cssString.endsWith(';')) cssString = cssString + ';' var commentX = /\/\*[\s\S]*?\*\//g var lineAttrX = /([^\:]+):([^\;]*);/ // This is used, a concatenation of all above. We use alternation to // capture. var altX = /(\/\*[\s\S]*?\*\/)|([^\s\;\{\}][^\;\{\}]*(?=\{))|(\})|([^\;\{\}]+\;(?!\s*\*\/))/gmi // Capture groups var capComment = 1 var capEnd = 3 var capAttr = 4 var isEmpty = function(x) { return typeof x == 'undefined' || x.length == 0 || x == null } var node = { attributes: {} } var match = null var count = 0 if (typeof args == 'undefined') { args = { ordered: false, comments: false, stripComments: false, split: false } } if (args.stripComments) { args.comments = false cssString = cssString.replace(commentX, '') } while ((match = altX.exec(cssString)) != null) { if (!isEmpty(match[capComment]) && args.comments) { // Comment var add = match[capComment].trim() node[count++] = add } else if (!isEmpty(match[capEnd])) { // Node has finished return node } else if (!isEmpty(match[capAttr])) { var line = match[capAttr].trim() var attr = lineAttrX.exec(line) if (attr) { // Attribute let name = attr[1].trim() var value = attr[2].trim() if (args.ordered) { let obj = {} obj['name'] = name obj['value'] = value obj['type'] = 'attr' node[count++] = obj } else { if (name in node.attributes) { var currVal = node.attributes[name] if (!(currVal instanceof Array)) { node.attributes[name] = [currVal] } node.attributes[name].push(value) } else { node.attributes[name] = value } } } else { // Semicolon terminated line node[count++] = line } } } return node } } export default new Cssjson()
nested2Css.js
/** * 嵌套的语句转css * author:jqCheng */ import cssjson from './cssjson' function nested2Css(nestedStr) { const allRes = {} parseSass(nestedStr) return allRes function parseSass(cssContent) { let cssStr = cssContent.replace(/\s+/g, ' ').replace(/\s+?\{\s+?/g, '{').replace(/\s+?\}/g, '}') // 递归 let obj = cutStr2Obj(cssStr) loopStrObj(obj) } function loopStrObj(obj, pName) { const reg = /\S+?\{(.*)\}/ for (let key in obj) { let cssStr = obj[key] const result = cssStr.match(reg) const cssObj = getCssObj(result, pName) if (cssObj) { const { elemName, attr } = cssObj allRes[elemName] = attr cssStr = result?.[1] // 循环 let pName1 = elemName let obj1 = cutStr2Obj(cssStr) loopStrObj(obj1, pName1) } } } function cutStr2Obj(cssStr) { const obj = {} while (cssStr) { const elemName = getElemName(cssStr) const { start, end } = getBracketIndex(cssStr) const str = elemName + cssStr.substring(start, end) if (elemName && str)obj[elemName] = str cssStr = cssStr.slice(end) } return obj } function getCssObj(result, pName) { if (result && result[1]) { const elemName = getElemName(result['input']) const cssContent = result[1].replace(/\S+?\{(.*)\}/g, ' ') const attr = cssjson.toJSON(cssContent).attributes return { elemName: pName ? `${pName} ${elemName}` : elemName, attr } } } function getBracketIndex(str) { const start = str.indexOf('{') let fs = 1 let flag = true let newstr = str.slice(start + 1) let end = start + 1 let k = 0 while (flag && k < 1000) { const i = newstr.indexOf('{') const j = newstr.indexOf('}') if (i !== -1 && i < j) { fs++ newstr = newstr.slice(i + 1) end += i + 1 } else if (j !== -1 && j < i) { fs-- newstr = newstr.slice(j + 1) end += j + 1 } else if (i === -1 && j !== -1) { fs-- newstr = newstr.slice(j + 1) end += j + 1 } if (fs <= 0)flag = false k++ // 放置错误格式造成死循环 } return { start, end: end + 1 } } function getElemName(str) { const end = str.indexOf('{') const newStr = str.substring(0, end) const start = newStr.lastIndexOf('}') !== -1 ? newStr.lastIndexOf('}') : (newStr.lastIndexOf(';') !== -1 ? newStr.lastIndexOf(';') : -1) const name = str.substring(start + 1, end).trim() return name } } export default nested2Css /* // 测试demo function test() { let cssContent = `:root{ border:1px solid deeppink; background:deeppink; div{ border:1px solid deepblue; text-decoration:underline; p{ font-size:14px; color:red; span{ padding:10px; } } } ul{ display:flex; align-items:center; li{ margin:10px; img{ width:10px; height:10px; } b{ color:black; } } .item{ margin-right:1px; } } } body{ font-family:'微软雅黑' *{ padding:0; margin:0 } }` console.log(nested2Css(cssContent)) } test() */
git地址
https://github.com/jiaqichengzhang/jsmodules/CssToJson
其它
项目中获取css字符串格式化用于monaco.editor显示 图示

function replaceStr(str) {
let str = '{".title":{"color":"red","font-size":"14px"},".text":{"font-weight":"bold","background-color":"red"},".text .radio-name":{"color":"#333"},".text .p":{"line-height":"30px"},".text span,.text b":{"color":"pink"},"span,b":{"color":"springgreen"}}'
str = str.replace(/",/g, '"¥').replace(/},/g, '}¥') // 为了和 span,b 字符串里面的逗号区分开,将json结构里面都还提换为¥
str = str.replace(/"}/g, '"¥}') // 最后一项加 '#'
str = str.replace(/"/g, '')
str = str.replace(/^\{/gi, '') // 提换开头{
str = str.replace(/\}$/gi, '') // 提换结尾{
str = str.replace(/{/g, '{\n\t')
str = str.replace(/¥}/g, ';\n}')
str = str.replace(/}¥/g, '}\n')
str = str.replace(/¥/g, ';\n\t')
str = str.replace(/\:\{/g, '{')
str = str.replace(/{\n\t}/g, '{\n}') // 空的{/n/t}提换
console.log(str)
return str
}

浙公网安备 33010602011771号