插件系统是 Tailwind CSS 的核心特性之一,它允许我们扩展和定制框架的功能。通过开发插件,我们可以添加新的工具类、组件和功能,使 Tailwind CSS 更好地满足项目需求。

插件开发基础

插件结构

  1. const plugin = require('tailwindcss/plugin')
  2. module.exports = plugin(function({ addUtilities, addComponents, theme, config }) {
  3. // 插件逻辑
  4. }, {
  5. // 配置项
  6. theme: {
  7. extend: {
  8. // 扩展主题配置
  9. }
  10. }
  11. })

核心 API

  1. plugin(function({
  2. addUtilities, // 添加工具类
  3. addComponents, // 添加组件
  4. addBase, // 添加基础样式
  5. addVariant, // 添加变体
  6. e, // 转义类名
  7. prefix, // 添加前缀
  8. theme, // 访问主题配置
  9. variants, // 访问变体配置
  10. config, // 访问完整配置
  11. postcss // PostCSS API
  12. }) {
  13. // 插件实现
  14. })

工具类开发

创建基础工具类

  1. // plugins/aspect-ratio.js
  2. const plugin = require('tailwindcss/plugin')
  3. module.exports = plugin(function({ addUtilities, theme }) {
  4. const ratios = {
  5. '1': '1',
  6. '4/3': '4/3',
  7. '16/9': '16/9',
  8. '21/9': '21/9'
  9. }
  10. const utilities = Object.entries(ratios).map(([key, value]) => ({
  11. [`.aspect-${key}`]: {
  12. aspectRatio: value
  13. }
  14. }))
  15. addUtilities(utilities)
  16. })

响应式工具类

  1. // plugins/grid-auto-fit.js
  2. const plugin = require('tailwindcss/plugin')
  3. module.exports = plugin(function({ addUtilities, theme, e }) {
  4. const minWidths = theme('gridAutoFit.minWidth', {
  5. 'xs': '12rem',
  6. 'sm': '14rem',
  7. 'md': '16rem',
  8. 'lg': '18rem'
  9. })
  10. const utilities = Object.entries(minWidths).map(([key, value]) => ({
  11. [`.grid-auto-fit-${e(key)}`]: {
  12. 'grid-template-columns': `repeat(auto-fit, minmax(${value}, 1fr))`
  13. }
  14. }))
  15. addUtilities(utilities, ['responsive'])
  16. })

组件开发

基础组件

  1. // plugins/buttons.js
  2. const plugin = require('tailwindcss/plugin')
  3. module.exports = plugin(function({ addComponents, theme }) {
  4. const buttons = {
  5. '.btn': {
  6. display: 'inline-flex',
  7. alignItems: 'center',
  8. justifyContent: 'center',
  9. padding: `${theme('spacing.2')} ${theme('spacing.4')}`,
  10. borderRadius: theme('borderRadius.lg'),
  11. fontWeight: theme('fontWeight.medium'),
  12. fontSize: theme('fontSize.sm')[0],
  13. lineHeight: theme('fontSize.sm')[1].lineHeight,
  14. transition: 'all 150ms ease',
  15. '&:focus': {
  16. outline: 'none',
  17. boxShadow: theme('boxShadow.outline')
  18. }
  19. },
  20. '.btn-primary': {
  21. backgroundColor: theme('colors.blue.600'),
  22. color: theme('colors.white'),
  23. '&:hover': {
  24. backgroundColor: theme('colors.blue.700')
  25. }
  26. }
  27. }
  28. addComponents(buttons)
  29. })

复杂组件

  1. // plugins/card.js
  2. const plugin = require('tailwindcss/plugin')
  3. module.exports = plugin(function({ addComponents, theme }) {
  4. const cards = {
  5. '.card': {
  6. backgroundColor: theme('colors.white'),
  7. borderRadius: theme('borderRadius.lg'),
  8. boxShadow: theme('boxShadow.md'),
  9. overflow: 'hidden'
  10. },
  11. '.card-header': {
  12. padding: theme('spacing.4'),
  13. borderBottom: `1px solid ${theme('colors.gray.200')}`
  14. },
  15. '.card-body': {
  16. padding: theme('spacing.4')
  17. },
  18. '.card-footer': {
  19. padding: theme('spacing.4'),
  20. borderTop: `1px solid ${theme('colors.gray.200')}`
  21. },
  22. // 变体
  23. '.card-hover': {
  24. transition: 'transform 150ms ease, box-shadow 150ms ease',
  25. '&:hover': {
  26. transform: 'translateY(-2px)',
  27. boxShadow: theme('boxShadow.lg')
  28. }
  29. }
  30. }
  31. addComponents(cards)
  32. })

变体开发

自定义状态变体

  1. // plugins/custom-variants.js
  2. const plugin = require('tailwindcss/plugin')
  3. module.exports = plugin(function({ addVariant, e }) {
  4. // 添加 first-child 变体
  5. addVariant('first', ({ modifySelectors, separator }) => {
  6. modifySelectors(({ className }) => {
  7. return `.${e(`first${separator}${className}`)}:first-child`
  8. })
  9. })
  10. // 添加 parent-hover 变体
  11. addVariant('parent-hover', ({ container, separator }) => {
  12. container.walkRules(rule => {
  13. rule.selector = `.parent:hover .${e(`parent-hover${separator}${rule.selector.slice(1)}`)}`
  14. })
  15. })
  16. })

响应式变体

  1. // plugins/screen-variant.js
  2. const plugin = require('tailwindcss/plugin')
  3. module.exports = plugin(function({ addVariant, e }) {
  4. addVariant('supports-grid', ({ container, separator }) => {
  5. const supportsRule = postcss.atRule({
  6. name: 'supports',
  7. params: '(display: grid)'
  8. })
  9. supportsRule.append(container.nodes)
  10. container.append(supportsRule)
  11. supportsRule.walkRules(rule => {
  12. rule.selector = `.${e(`supports-grid${separator}${rule.selector.slice(1)}`)}`
  13. })
  14. })
  15. })

主题扩展

扩展现有主题

  1. // plugins/extended-spacing.js
  2. const plugin = require('tailwindcss/plugin')
  3. module.exports = plugin(function({}) {}, {
  4. theme: {
  5. extend: {
  6. spacing: {
  7. '4.5': '1.125rem',
  8. '5.5': '1.375rem',
  9. '13': '3.25rem',
  10. '15': '3.75rem'
  11. }
  12. }
  13. }
  14. })

添加新主题特性

  1. // plugins/gradients.js
  2. const plugin = require('tailwindcss/plugin')
  3. module.exports = plugin(function({ addUtilities, theme, variants }) {
  4. const gradients = theme('gradients', {})
  5. const gradientUtilities = Object.entries(gradients).map(([name, value]) => ({
  6. [`.bg-gradient-${name}`]: {
  7. backgroundImage: `linear-gradient(${value})`
  8. }
  9. }))
  10. addUtilities(gradientUtilities, variants('gradients', []))
  11. }, {
  12. theme: {
  13. gradients: {
  14. 'blue-green': '45deg, #4F46E5 0%, #10B981 100%',
  15. 'purple-pink': '45deg, #7C3AED 0%, #EC4899 100%'
  16. }
  17. }
  18. })

工程化实践

插件测试

  1. // tests/button-plugin.test.js
  2. const postcss = require('postcss')
  3. const tailwindcss = require('tailwindcss')
  4. const buttonPlugin = require('../plugins/buttons')
  5. const generatePluginCss = (content) => {
  6. return postcss(
  7. tailwindcss({
  8. content: [{ raw: content }],
  9. plugins: [buttonPlugin]
  10. })
  11. )
  12. }
  13. test('generates button component styles', async () => {
  14. const css = await generatePluginCss(`
  15. <div class="btn btn-primary"></div>
  16. `)
  17. expect(css).toMatchSnapshot()
  18. })

插件发布

  1. {
  2. "name": "tailwindcss-plugin-name",
  3. "version": "1.0.0",
  4. "main": "index.js",
  5. "peerDependencies": {
  6. "tailwindcss": "^3.0.0"
  7. }
  8. }

插件文档

  1. # Tailwind CSS Plugin Name
  2. ## 安装
  3. npm install tailwindcss-plugin-name

配置

  1. // tailwind.config.js
  2. module.exports = {
  3. plugins: [
  4. require('tailwindcss-plugin-name')
  5. ]
  6. }

最佳实践

  1. 插件设计原则

    • 单一职责
    • 可配置性
    • 性能优化
    • 文档完善
  2. 开发建议

    • 遵循命名规范
    • 提供类型定义
    • 编写单元测试
    • 示例完整
  3. 发布注意事项

    • 版本控制
    • 依赖管理
    • 更新日志
    • 兼容性说明
  4. 维护策略

    • 及时响应问题
    • 定期更新
    • 社区互动
    • 版本迭代