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
}

  

posted @ 2021-10-10 15:47  卷叶小树  阅读(285)  评论(0)    收藏  举报