字符串内联样式转对象(看开源项目学一招半式)

1,131 阅读2分钟

parseStyles

输入:

'padding-left:20; display: flex; flex-direction: row; margin-right:20'

输出:

{
  display: "flex"
  flexDirection: "row"
  marginRight: "20"
  paddingLeft: "20"
}

代码如下

const parseStyles = (styles: string = ''): { [key: string]: string } => {
  return styles
    .split(';')
    .filter((style) => style.split(':').length === 2)
    .map((style) => [
      style.split(':')[0].trim().replace(/-./g, c => c.substr(1).toUpperCase()),
      style.split(':')[1].trim()
    ])
    .reduce((styleObj, style) => ({
      ...styleObj,
      [style[0]]: style[1],
    }), {})
}

使用的是TypeScript, 其中parseStyles函数传入一个参数styles, 类型是字符串string, 函数的返回值是一个对象, 对象的属性名key类型属于字符串, 对象属性值类型为string

(styles: string = ''): { [key: string]: string }

其中styles默认值是''空字符串

执行过程

  • 把字符串切割成数组
styles
  .split(';')  
  
// ["padding-left:20", " display: flex", " flex-direction: row", " margin-right:20"]
  • 过滤掉不成双成对的
styles
  .split(';')
  .filter((style) => style.split(':').length === 2)
  
// ["padding-left:20", " display: flex", " flex-direction: row", " margin-right:20"]
  • 转换成2层嵌套数组, 并把属性名中横线转驼峰
styles
  .split(';')
  .filter((style) => style.split(':').length === 2)
  .map((style) => [
    style.split(':')[0].trim().replace(/-./g, c => c.substr(1).toUpperCase()),
    style.split(':')[1].trim()
  ])
  
[
  ['paddingLeft', '20'],
  ['display', 'flex']
  ['flexDirection', 'row'],
  ['marginRight', '20']
]
  • 转换为对象输出
styles
  .split(';')
  .filter((style) => style.split(':').length === 2)
  .map((style) => [
    style.split(':')[0].trim().replace(/-./g, c => c.substr(1).toUpperCase()),
    style.split(':')[1].trim()
  ])
  .reduce((styleObj, style) => ({
    ...styleObj,
    [style[0]]: style[1],
  }), {})
  

{
  display: "flex"
  flexDirection: "row"
  marginRight: "20"
  paddingLeft: "20"
}

reduce函数,2个参数,第一个是函数,第二个默认值。

其中函数有4个参数,第一个参数是累积器, 第二个参数遍历的当前值, 第三个参数是当前索引, 第四个参数是源数组

最重要的是第一个参数累积器, 当第一次循环的时候,参数值为['paddingLeft', '20'], 第二次循环的时候,参数值是什么,取决于函数返回值,如果返回值是累加,即跟第二个参数累加,那第二次循环,值为累加值。

这里用到reduce函数的第二个参数,默认值,即第一次循环的时候,函数的第一个参数的值为你设置的默认值,而不是数组里的第0

回过头来看这段代码

  reduce((styleObj, style) => ({
    ...styleObj,
    [style[0]]: style[1],
  }), {})

1次循环时styleObj为默认值{}, 函数返回的是

{
  display: "flex"
}

2次循环时styleObj为默认值{display: "flex"}, 函数返回的是

{
  display: "flex",
  flexDirection: "row"
}

...

以此类推最后返回

{
  display: "flex"
  flexDirection: "row"
  marginRight: "20"
  paddingLeft: "20"
}

在编写react-native应用会有这样的需求

开源项目链接地址

GITHUB仓库,欢迎Star~!