css variable 解析2.0

上一版实在过于又臭又长,循环嵌套太多了,在大佬的指点下进行了一下代码重构.

整体思路

这一版其实压缩了一多半的代码量,底层思路其实也改动了很多.因为css variable最多只会有一层嵌套,而且一单匹配到正确值可以立刻退出,所以在没必要像上一版那样过多用for循环嵌套. 为了代码的整体性,新版设计成了只穿一个css key参数的版本,而整体的mostSpecificRule通过闭包获取. 因为用了递归的实现思路,而一个程序同时进行 实际cssKey 实际cssvalue css variable 以及_css variable fallback_等多种数据进行处理,所以乍一看其实还是有些吃力的.

具体逻辑

color: var(--varOne,var(--varTwo,red)) 首先我们要明确函数的入参都会有什么

  • color:具体的css key 要进行 getPropertyValue拿取值,

  • --varOne:cssVar key要进行 getPropertyValue拿真实值,

  • var(--varTwo,red): 查不到值时的fallback 不需要进行getPropertyValue,

  • red:真实的css value 或者fallback后的实际备选值,不需要进行getPropertyValue

函数处理的最一开始,通过是否包含var( 判断,来条件执行getPropertyValue方法

但实际上我们只能通过 var( 的检查判断出第三种情况不执行getPropertyValue方法,第四种情况还是会进行getPropertyValue操作,这是错误的

还好这里我们可以在函数返回的时候进行补救判断

return propertyValue || propertyCss.startsWith('--') ? propertyValue : propertyCss

成功查值则肯定返回查询结果,对应情况一 和 情况二(有对应值的时候)

查值不成功,则需要进一步判断是否以- -开头,

不是就返回自身代表它是真实css value.(第四种情况)

是那就返回查询结果 代表为情况二(无对应值的时候)

递归构建

最后在函数递归入口进行退回处理,

查到v.key直接替换,

查不到则用getPropertyCssValue(v.fallback)替换,完善整个递归流程

    const value = getPropertyCssValue(v.key)
    // Detect the need for fallback
    propertyValue = propertyValue.replace(
      v.text,
      value ? value : getPropertyCssValue(v.fallback)
    )

完整代码:

const getPropertyCssValue = (propertyCss: string): string => {
  //Screening fallback
  let propertyValue =
    propertyCss.indexOf(‘var(‘) == -1
      ? mostSpecificRule.style.getPropertyValue(propertyCss.trim()) // mostSpecificRule is a CSSStyleRule for DOM, comes from the Lexical Closure
      : propertyCss
  const cssVariables: {
    text: string //Varlables text
    fallback: string // Varlables fallback
    key: string //Varlables key
  }[] = []
  for (
    let index = propertyValue.indexOf(‘var(‘), left = index + 4, bracketsLevels = 0;
    index < propertyValue.length;

  ) {
    // not found
    if (index < 0) {
      break
    }
    if (propertyValue.charAt(index) === ‘)’) bracketsLevels—
    else if (propertyValue.charAt(index) === ‘(‘) bracketsLevels++
    if (bracketsLevels == 0 && index > left) {
      const text = propertyValue.substring(left - 4, index + 1)
      const inner = text.substring(4, text.length - 1)
      const separator = inner.indexOf(',')
      const length = inner.length
      const sp = separator < 0 ? length : separator
      cssVariables.push({
        text, //var(—one,var(—two,rgb(1,1,1)))
        fallback: inner.substring(sp + 1), //var(--two,rgb(1,1,1))
        key: inner.substring(0, sp).trim() //--one
      })
      //Process the next css Varlables
      index = propertyValue.indexOf('var(', index)
      left = index + 4
      continue
    }
    index++
  }
  if (cssVariables.length === 0) {
    //propertyCss is a  normal cssValue return itself
    //propertyCss is a cssVariable key return getPropertyValue()
    return propertyValue || propertyCss.startsWith('--') ? propertyValue : propertyCss
  }
  cssVariables.map(v => {
    const value = getPropertyCssValue(v.key)
    // Detect the need for fallback
    propertyValue = propertyValue.replace(
      v.text,
      value ? value : getPropertyCssValue(v.fallback)
    )
  })
  return propertyValue
}

最后更新于