postcss-js的基本使用

@一棵菜菜  April 20, 2018

What: 什么是postcss

PostCSS 是一个允许使用 JS 插件转换样式的工具。 这些插件可以检查(lint)你的 CSS,支持 CSS Variables 和 Mixins, 编译尚未被浏览器广泛支持的先进的 CSS 语法,内联图片,以及其它很多优秀的功能。
PostCSS 在工业界被广泛地应用,其中不乏很多有名的行业领导者,如:维基百科,Twitter,阿里巴巴, JetBrains。PostCSS 的 Autoprefixer 插件是最流行的 CSS 处理工具之一。

更多资料请查阅github项目: postcss

Why: 为什么要使用它

解决问题: 如何实现数据驱动样式?

在研究一个项目, 它需要实现一个动态样式的更改, 比如点击某元素让他的背景颜色变为#f00.

要实现这个我暂时想到2个方法:

1. 内联样式

:style="{"background":"#f00"}"

我们需要定义一个对象里面存放{"background":"xxx";"padding":"xpx"}, 然后给dom的style属性绑定上这个对象. 当用户点击这个组件的时候, 将对象值改变即可.

这样是可以实现, 但思考以下问题:

  • 如何模拟出:hover {background:#fff}, 也就是怎么模拟伪类?
  • 当属性很多的时候, 会不会影响到vue的渲染速度?
  • 全部内联是不是有点不太优雅?

可见这不是最佳方法

2. 动态生成<style>标签

我们可以动态生成一段<style>标签添加到html里, 这样就可以很方便的实现:hover效果, 也不会影响到渲染效率.

看似很完美, 我们就使用这个方法.

那么要解决的问题就是这么从一个js对象{"background":"xxx";"padding":"xpx"}转换成css代码? 对于简单的对象我们可以手拼, 但对于一个复杂的, 支持嵌套的结构我们能确定手动能拼好吗? 按照不重复造轮子原则, 我需要一个已经写好了的处理css的利器, 于是我找到了postcss.

How: 如何使用postcss

首先明确我们的目的: 将js对象解析成css

postcss说它有200多个插件, 一眼扫去不难发现一个postcss-js的插件:

postcss-js 允许你在 JS 里编写样式,或者转换成 React 的内联样式/Radium/JSS。

这个插件正是我们所需要的啊.

查阅文档发现使用方法如下:

### Compile CSS-in-JS to CSS

let style = {
   top: 10,
   '&:hover': {
      top: 5
   }
};

postcss().process(style, { parser: postcssJs }).then( (result) => {
   result.css //=> top: 10px;
              //   &:hover { top: 5px; }
})

这货还支持嵌套css? 岂不是更爽. 笑出声

各种尝试之后我封装了如下方法

// postcss-js.js
// 请先npm install 相关包

import postcss from 'postcss' // postcss
import postcssJs from 'postcss-js' // css
import autoprefixer from 'autoprefixer' // 自动前缀
import nested from 'postcss-nested' // 嵌套语法
import variables from 'postcss-css-variables' // 支持变量 如:root{--a:#333}

function processCssJs(cssJs) {
  return postcss([autoprefixer, nested, variables]).process(
    cssJs, {parser: postcssJs}).css
}

export default processCssJs

ps: 200个插件总有有用的, 多翻翻.

我们来看看这个方法可以干什么事?

input:

{
    ":root"{
      --c:#fff
    }
    "#id1": {
        "backgrounColor": var(--c),
        "&:hover": {
            "backgrounColor": "#eee"
        }
    }
}

output:

#id1{
  backgroun-color:#fff
}
#id1:hover{
  backgroun-color:#eee
}

当然我只是给定一个简单的结构举例, 实际使用中, 我们可以在js对象中写像less,sass那样复杂的嵌套,
你可以试一试.

题外话

一般来说, 一个组件会有一个js对象来表述样式. 那么针对这个js对象就要生成一个<style>标签.

一个组件一段<style>是不是有不太优雅? 我们想把style统一放在一个地方. 有以下两个方案。

方案1: vuex, 每个组件emit自己的cssjs, 然后用统一一个组件去渲染这些cssjs.
方案2: 做一个vue的plugin, 给Vue的原型链上添加一些方法以实现每个组件都可以emit自己的cssjs, 然后用统一一个组件去渲染这些cssjs.

具体的自由发挥吧.


添加新评论