如何开发一个基本的PostCSS插件

PostCSS简介

  • 介绍

PostCSS 是一个翻译样式的js插件。它能帮你对css做静态分析。支持变量和混入.编译尚未被浏览器支持的css预发,内联图片等。业界被广泛地应用,其中不乏很多有名的行业领导者,如:维基百科,Twitter,阿里巴巴, JetBrains。PostCSS 的 Autoprefixer 插件是最流行的 CSS 处理工具之一。

  • 发展

PostCSS 是 Autoprefixer 的开发者 Andrey Sitnik 开发的,最初是一个通过 JavaScript 来处理 CSS 的方法。PostCSS 本身只是一个 API,不过加上庞大的插件生态体系,作用就非常强大了。为了提供有用的调试功能,PostCSS 还生成了源码的 map,而且还提供了抽象语法树(AST)来帮助我们理解代码是如何被转换的。

  • 作用

JavaScript 能做到比其他处理方式更快的转换我们的样式。通过Gulp或Webpack这样的task工具,我们可以在 build 过程中对样式进行转换,这与 Sass 和 LESS 的编译过程非常类似。React 和 AngularJS 这样的库和框架还允许我们在 JavaScript 中直接编写 CSS 代码,这为使用 JavaScript 来转换样式打开了一扇大门。

PostCSS介绍

PostCSS API

Autoprefixer

插件介绍

到目前为止是PostCSS欣欣向荣的插件生态系统使得PostCSS如此惊艳。主要的原因是PostCSS开发插件对于有一些JavaScript开发经验的人来说非常容易。

开发PostCSS插件,不需要特别的许可;下面开发一个基本的PostCSS插件为例。

它可以做什么?

我们将要创建插件,这个插件能插入一些默认样式。编译函数,添加前缀,转换进制等功能。

  • 输入
a {
	font-family: "Open Sans", family("helloworld");
	font-size: 1rem;
	flex: 1;
}
  • 输出
html, body, ul{
	margin: 0;
	padding: 0;
	/* 用户自定义样式 */
}
a {
	color: black;
	background-color: white;
	font-family: "Open Sans", Arial, Helvetica, sans-serif;
	font-size: 12px;
	-webkit-flex: 1;
	-ms-flex: 1;
	/* 用户自定义样式 */
}

工程搭建

虽然我们是在创建自己的插件,但是仍然需要先创建一个空的Gulp或Webpack项目。

PostCSS介绍中有完整的项目搭建说明。如果你不想自己搭建环境,你也可以使用PostCSS样例,这里有完整的gulp与webpack已搭建好的环境以及运行文档。

编写PostCSS插件

node_modules中创建一个文件夹命名为 postcss-plugin-demo。常见的命名方式是使用postcss-前缀,明确插件是PostCSS插件。由于某些编辑器node_modules是隐藏文件夹,不易编写代码,我们也可以把postcss-plugin-demo移动到与node_modules并列文件夹。

postcss-plugin-demo目录下中创建名为index.js的文件,并且加载postcss的主模块。

const postcss = require('postcss')

接下来是基本的包装器,用来包装我们的插件处理代码:

const postcss = require('postcss');

module.exports = postcss.plugin('myplugin', function myplugin(options) {

    return function (css) {

        options = options || {};

        // Processing code will be added here

    }

});

读取插件

现在你可以加载你刚刚创建的插件了。但是插件里面没有任何代码,我们仅仅想得到必要的设置。

通过Gulp加载
什么是gulp

gulp是可以自动化执行任务的工具 在平时开发的流程里面,一定有一些任务需要手工重复得执行,比如:

  • 把文件从开发目录拷贝到生产目录
  • 把多个 JS 或者 CSS 文件合并成一个文件
  • 对JS文件和CSS进行压缩
  • 把sass或者less文件编译成CSS
  • 压缩图像文件
  • 创建一个可以实时刷新页面内容的本地服务器

只要你觉得有些动作是要重复去做的,就可以把这些动作创建成一个gulp任务 然后在指定的条件下自动执行

gulp中的流
  • gulp正是通过代码优于配置的策略来尽量简化任务编写的工作。
  • 类似jquery里的链式操作,把各个方法串连起来构建完整的任务。
  • 用gulp编写任务也可看作是用Node.js代码编写任务。
  • 当使用流时,gulp不需要生成大量的中间文件,只将最后的输出写入磁盘,整个过程因此变得非常快。
gulp的使用流程一般是
  • 首先通过gulp.src()方法获取到想要处理的文件流
  • 然后把文件流通过pipe方法导入到gulp的插件中
  • 最后把经过插件处理后的流再通过pipe方法导入到gulp.dest()中
  • gulp.dest()方法则把流中的内容写入到文件中

如果你使用Gulp,gulp的任务要放到一个叫gulpfile.js的文件里面 先在项目的根目录下面创建一个这样的文件,导入刚才的插件:

const myplugin = require('../postcss-plugin-demo');
const processors = [ myplugin() ]

可以使用gulp的task方法 我们去创建一个叫 css 的任务,它要做的事就是取到想要处理的文件流,进行我们自定义的插件转换后,输出到目的地

  • 第一个参数是任务的名称
  • 第二个参数是任务的定义,是一个匿名函数
gulp.task('css', function () {
	return gulp.src('./src/*.css') // 获取文件的流的api
		.pipe(postcss(processors))
		.pipe(gulp.dest('./dest')); // 写文件的api
});

然后运行

$ gulp css

即可在dest目录下生成新的编译后文件style.css

gulp后面跟着的是任务的名称 不输入任务名称的话会默认找default任务,找不到会报错

通过Webpack加载

webpack不能直接编译css文件,必须通过js引入css才能编译。webpack.config.js导入刚才的插件:

const myplugin = require('../postcss-plugin-demo');
const processors = [ myplugin() ]

并且把css封装成rules规则:

{
  ...
  module: {
    rules: [
      {
        test: /\.css$/, 
				use: ExtractTextPlugin.extract({
        fallback: "style-loader",
        use: [{
          loader: 'css-loader'
        }, {
          loader: 'postcss-loader',
          options: {
            plugins() {
              return processors
            }
          }
        }]
      })
      },
    ]
  },
  ...
}

然后运行:

$ webpack

即可在dest目录下生成新的编译后文件style.css

编写插件功能

添加css

开始编写插件之前,我们先创建一段插件编译的样式测试代码。

在你的src/style.css下添加:

a {
	font-family: "Open Sans", family("helloworld");
	font-size: 1rem;
	flex: 1;
}

现在,因为你的插件并没有做任何事情,如果你编译你的css文件你会在dest文件夹下面看到完全一样的复制代码dest/style.css

开始编写插件

在你的插件postcss-plugin-demo/index.jsoptions = options || {}下添加:

/* 插入初始化html, body属性 */
const base = postcss.parse(`html, body, ul{
	margin: 0;
	padding: 0;
}`)
css.prepend(base)

返回到gulp(或webpack)运行编译命令:

$ gulp css

查看你的编译后文件,插入了一段语句:

html, body, ul{
	margin: 0;
	padding: 0;
	/* 用户自定义样式 */
}

你已经成功的编写了一段插件代码。
更多API请查看:PostCSS API

遍历你的css样式表

在css中,每个选择器以及后面的样式叫做rule规则,每行样式叫做decl声明,例如:

a {
    color: red;
}

那么这个css就一条规则a{ color: red; },这个规则有一个声明color: red;

如果我们想遍历查询我们的样式文件,我们可以在options = options || {}下面添加以下代码:

css.walkRules(function (rule) {

    rule.walkDecls(function (decl, i) {

    });

});

使用walkRules来遍历css文件每一条规则,接着,在每条规则里面,使用walkDecls遍历你的每一条声明。

给某些选择器增加样式

walkRules的回调函数里有两个参数,第一个参数就是规则,第二个参数是规则的索引。如果感兴趣,可以手动把规则全部打印出来看一下。

rule.selector用来获取规则的选择器名称。我们把所有的文字选择器增加两条css声明,黑色文字,白色背景。在walkRules回调函数下面添加这段代码:

const texts = ['label', 'a', 'span']
if(texts.includes(rule.selector)) {
	// 插入样式属性: color, background-color
	const color = postcss.decl({ prop: 'color', value: 'black' })
	const bgColor = postcss.decl({ prop: 'background-color', value: 'white' })
	rule.prepend(color, bgColor)
}
console.log(`${rowIndex + 1 }.处理选择器:`, rule.selector)

返回到gulp(或webpack)运行编译命令:

$ gulp css

查看你的编译后文件:

html, body, ul{
	margin: 0;
	padding: 0;
	/* 用户自定义样式 */
}
a {
	color: black;
	background-color: white;
	font-family: "Open Sans", family("helloworld");
	font-size: 1rem;
	flex: 1;
}

a选择器的规则里添加了color,background-color两个样式。

同时,控制台打印出来:

$ 1.处理选择器: html, body, ul
$ 2.处理选择器: a

处理具体样式声明

walkDecls的回调函数里同样有两个参数。

  • 第一个参数是样式声明,例如font-family: "Open Sans", family("helloworld");
  • 第二个参数是声明的索引。
  • 声明里有两个重要的属性prop, value
    • prop: 样式名称,例如font-family
    • value: 样式值,例如"Open Sans", family("helloworld")

利用这两个值,我们就可以随意处理样式声明。
walkDecls回调函数之内添加以下代码:

// 转换rem为px
if(value.includes('rem')) {
	decl.value = value.replace(/(.)rem/, (matched, catched) => {
		return Number(catched) * 12 + 'px'
	})
}

// 增加前缀
if(prefixs.includes(prop)) {
	decl.prop = decl.clone({ prop: '-webkit-' + prop }).prop
	rule.append(decl.clone({ prop: '-ms-' + prop }))
}

// 转换关键字
if (value.includes('family')) {
  decl.value = replaceValues(value);
}
function replaceValues(str) {
  const mapper = {
    helloworld: 'Arial, Helvetica, sans-serif'
  }

  return str.replace(/(.*)family\(\"(.*)\"\)/, (all, prefix, matched, index, input) => {
    const mapped = mapper[matched]
    return mapped ? `${prefix}${mapped}` : input
  })
}

返回到gulp(或webpack)运行编译命令:

$ gulp css

查看你的编译后文件:

html, body, ul{
	margin: 0;
	padding: 0;
}
a {
	color: black;
	background-color: white;
	font-family: "Open Sans", Arial, Helvetica, sans-serif;
	font-size: 12px;
	-webkit-flex: 1;
	-ms-flex: 1;
}

可以看到,flex属性增加了前缀,1rem编译成了12pxfamily("helloworld")编译成Arial, Helvetica, sans-serif

同时控制台准确的打印出每条规则与每个声明:

1.处理选择器: html, body, ul
1.1.处理选择器属性: margin
1.2.处理选择器属性: padding
2.处理选择器: a
2.1.处理选择器属性: color
2.2.处理选择器属性: background-color
2.3.处理选择器属性: font-family
2.4.处理选择器属性: font-size
2.5.处理选择器属性: flex
2.6.处理选择器属性: -ms-flex
3.处理选择器: label
3.1.处理选择器属性: color
3.2.处理选择器属性: background-color
3.3.处理选择器属性: font-family
根据外界参数处理样式

有时候,我们需要根据参数来做判断或者编译。比如刚才family("helloworld")是定死在插件内的。如果用户需要编译其他样式,肯定不能去修改插件。

这种情况我们可以让用户传入要编译的内容。然后在插件内与helloworld合并。

修改gulp/package.json,添加用户自定义编译内容到最外层json:

"myConfig": {
  "myHelloworld": "Arial, Helvetica Neue, Helvetica, sans-serif"
}

把用户定义的编译内容传入插件内:

const gulp = require('gulp')
const postcss = require('gulp-postcss')
const config = require('./package.json')
const myplugin = require('../postcss-plugin-demo')

const processors = [ myplugin(config.myConfig) ]

gulp.task('css', function () {
	return gulp.src('./src/*.css')
		.pipe(postcss(processors))
		.pipe(gulp.dest('./dest'));
});

插件的包装器回调传入的options就是刚才我们传入的myConfig

module.exports = postcss.plugin('myplugin', function (options) {
	return function (css) {
		options = options || {}

我们把这个属性传入replaceValues函数中,与helloworld合并:

function replaceValues(str, options) {
  const mapper = Object.assign({
		helloworld: 'Arial, Helvetica, sans-serif',
  }, options)

  return str.replace(/(.*)family\(\"(.*)\"\)/, (all, prefix, matched, index, input) => {
    const mapped = mapper[matched]
    return mapped ? `${prefix}${mapped}` : input
  })
}

然后我们修改src/style.css,添加一个新规则label,引用刚才定义的myHelloworld

a {
	font-family: "Open Sans", family("helloworld");
	font-size: 1rem;
	flex: 1;
}

label {
	font-family: "Open Sans", family("myHelloworld");
}

返回到gulp(或webpack)运行编译命令:

$ gulp css

查看你的编译后文件,这就是我们最终的代码了:

html, body, ul{
	margin: 0;
	padding: 0;
}

a {
	color: black;
	background-color: white;
	font-family: "Open Sans", Arial, Helvetica, sans-serif;
	font-size: 12px;
	-webkit-flex: 1;
	-ms-flex: 1;
}

label {
	color: black;
	background-color: white;
	font-family: "Open Sans", Arial, Helvetica Neue, Helvetica, sans-serif;
}

family('myHelloworld')被编译成了Arial, Helvetica Neue, Helvetica, sans-serif

最后

基于上面的PostCSS插件相关学习,希望大家迸发出一些其他插件的想法,或者项目中写css时候遇到困扰我们的小问题的时候,以尝试用自己的解决方案去解决它。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 很高兴为您提供帮助。要创建一个自定义插件来实现登录页面,您可以按照以下步骤操作: 1. 首先,您需要在WordPress中创建一个新的插件。您可以在wp-content/plugins目录下创建一个新的文件夹,并在其中创建一个新的PHP文件。 2. 在新的PHP文件中,您可以使用WordPress提供的函数来创建一个新的页面模板。例如,您可以使用add_menu_page函数来创建一个新的菜单页面,并使用add_submenu_page函数来创建一个子菜单页面。 3. 在页面模板中,您可以使用HTML和CSS来设计您的登录页面。您可以添加表单元素,例如用户名和密码字段,并使用JavaScript来验证用户输入。 4. 当用户提交表单时,您可以使用PHP代码来验证用户输入,并将用户重定向到他们的个人资料页面或其他页面。 5. 最后,您可以将您的插件上传到WordPress插件目录,并在WordPress后台激活它。 希望这些步骤能够帮助您创建一个自定义插件来实现登录页面。如果您需要更多的帮助,请随时联系我。 ### 回答2: 首先,我们需要了解WordPress插件的结构和钩子机制。一个WordPress插件通常由两个文件组成:一个插件的主文件(通常是以插件名命名),一个插件的配置文件(通常是以插件名加上“-info”后缀命名)。配置文件中包含了插件基本信息和启用、禁用插件的设置。 为了实现一个登录页面功能的自定义插件,我们需要: 1. 创建主文件和配置文件。在主文件中,我们需要使用WordPress的钩子机制,将登录页面输出到WordPress网站中。配置文件中定义插件基本信息和启用、禁用插件的设置。 2. 在主文件中使用WordPress的钩子机制(即add_action()函数)来实现登录页面的输出。我们可以将登录页面输出到WordPress站点的特定页面或使用短代码添加页面中。 3. 在登录页面中添加表单和提交按钮。当用户填写表单后,我们需要使用POST方法将用户提交的数据发送给服务器。 4. 在后端代码中对用户数据进行验证。我们需要检查用户输入的用户名和密码是否正确。如果验证不通过,需要重定向到登录页面,并显示错误信息。如果验证通过,可以将用户信息存储到WordPress中,以便用户登录时进行验证。 5. 添加样式和脚本。我们需要为登录页面添加样式和JavaScript代码,以使其更加美观、易于使用和交互。 最后,我们需要将创建的插件上传到WordPress插件库或手动将其安装到WordPress站点中。用户可以在WordPress站点的后台管理界面中启用或禁用该插件。用户访问站点时,即可看到我们创建的登录页面并进行登录。 ### 回答3: 随着互联网的发展,各种网站应用也越来越普及。而登录页是每个网站应用都必须要有的一个页面,也是用户访问网站时必须首先进行的页面,因此,创建一个自定义插件来实现一个登录页面就显得非常重要。 首先,我们需要考虑插件的目的和功能。那么,这个插件需要实现哪些功能呢?一般来说,登录页面应该至少包含两个输入框和一个提交按钮。我们可以在插件中添加这些基本元素,以便用户能够输入用户名和密码,然后通过点击提交按钮登录。 为了增强插件的使用性和美观性,我们还可以添加一些额外的功能和特性,例如自定义主题颜色、显示验证码、添加第三方登录(如微信、QQ、微博等)、记住密码、找回密码等等。这些功能和特性都有助于提高用户体验和安全性。 当然,要实现这些功能,我们还需要掌握一些相关的技术和知识。例如使用HTML和CSS设计页面布局样式,使用JavaScript实现页面交互效果和表单验证等,使用AJAX技术实现异步提交表单数据,使用数据库存储用户信息等等。 最后,我们需要将插件打包成一个可安装的文件或者发布到插件市场中。这样,其他开发人员就可以方便地使用我们的插件来实现登录页面了。 总之,创建一个自定义插件实现一个登录页面可以提高网站应用的安全性、用户体验和美观度,具有非常重要的意义。关键是要掌握相关技术和知识,并不断改进和完善插件功能和特性,以适应不同的应用场景和用户需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值