Visual LabINTERACTIVE LEARNING
界面与布局精校教程

UnoCSS 自定义规则与预设

拆解一个工程化预设:从正则匹配、单位转换到边框、间距和颜色规则。

UnoCSS正则Preset
专题预计 26 分钟查看源文 ↗
/* eslint-disable no-useless-escape */
// my-preset.ts
import { Preset } from 'unocss'
// 匹配3位,6位 8位的十六进制颜色*****************-
const singleHex = '[0-9a-fA-F]'
// 匹配0-255
// const singleRgb = '(25[0-5]|2[0-4][0-9]|1?[1-9]?[0-9])'
// 颜色字符串
const hex = (prefix: string) => new RegExp(`${prefix}-(${singleHex}{3}|${singleHex}{6}|${singleHex}{8})

  
    
    
    
    
    
    
    
  
    UnoCSS 自定义规则与预设 · 知识教程 · Visual Lab
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
  
  
    
    )
// const rgb = (prefix: string) => new RegExp(`${prefix}-rgb\\(${singleRgb},${singleRgb},${singleRgb}\\)

  
    
    
    
    
    
    
    
  
    UnoCSS 自定义规则与预设 · 知识教程 · Visual Lab
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
  
  
    
    )
// const rgba = (prefix: string) => new RegExp(`${prefix}-rgba\\(${singleRgb},${singleRgb},${singleRgb},(1|0?\\.\\d+)\\)

  
    
    
    
    
    
    
    
  
    UnoCSS 自定义规则与预设 · 知识教程 · Visual Lab
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
  
  
    
    )

// border样式
const bStyle = 'none|hidden|dotted|dashed|solid|double|groove|ridge|inset|outset'
// border
const borderHex = () => new RegExp(`b(l|r|t|b)?-(\\d+)-(${bStyle})-(${singleHex}{3}|${singleHex}{6}|${singleHex}{8})

  
    
    
    
    
    
    
    
  
    UnoCSS 自定义规则与预设 · 知识教程 · Visual Lab
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
  
  
    
    )
// const borderRgba = () => new RegExp(`b(l|r|t|b)-(\\d+)-(${bStyle})-rgba\\(${singleRgb},${singleRgb},${singleRgb},(1|0?\\.\\d+)\\)

  
    
    
    
    
    
    
    
  
    UnoCSS 自定义规则与预设 · 知识教程 · Visual Lab
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
  
  
    
    )

//返回单位
const getUnit = (a: string, u: string) => {
  switch (u) {
    case 'f':
      return `${a}%`
    case 'h':
      return `${a}vh`
    case 'w':
      return `${a}vw`
    case 'r':
      return `${a}rem`
    case 'e':
      return `${a}em`
    default:
      return `${a}px`
  }
}

// 返回方位
const getDiretion = (p: string) => {
  switch (p) {
    case 'l':
    case 'left':
      return 'left'
    case 'r':
    case 'right':
      return 'right'
    case 'b':
    case 'bottom':
      return 'bottom'
    case 't':
    case 'top':
      return 'top'
    case 'h':
    case 'height':
      return 'height'
    case 'width':
    case 'w':
      return 'width'
    case 'mh':
      return 'min-height'
    case 'mw':
      return 'min-width'
    case 'lh':
      return 'line-height'
    default:
      return ''
  }
}

// 返回4个方向的margin和padding
const getmp = (prefix: string, a?: string, b?: string, c?: string, d?: string) => {
  if (d) return `${prefix}t-${a} ${prefix}r${b} ${prefix}b${c} ${prefix}l${d}`
  if (c) return `${prefix}t-${a} ${prefix}r${b} ${prefix}b${c}`
  if (b) return `${prefix}t-${a} ${prefix}r${b}`
  return `${prefix}t-${a}`
}

const getFloat = (num: string, float: string) => (float ? `${num}.${float.slice(1, float.length)}` : num)

export const unoPreset: Preset = {
  name: 'my-preset',
  rules: [
    [
      /^line-(\d+)$/,
      ([, a]) => ({
        '-webkit-line-clamp': `${a}`,
        overflow: 'hidden',
        ' word-break': 'break-all',
        ' text-overflow': 'ellipsis',
        display: '-webkit-box',
        ' -webkit-box-orient': 'vertical',
      }),
    ],
    // 颜色3位,6位 8位
    [hex(`^color`), ([, a]) => ({ color: `#${a}` })],
    [hex(`^bg`), ([, a]) => ({ 'background-color': `#${a}` })],
    // [rgb('^color'), ([, a, b, c]) => ({ color: `rgb(${a},${b},${c})` })],
    // [rgb('^bg'), ([, a, b, c]) => ({ 'background-color': `rgb(${a},${b},${c})` })],
    // [rgba('^color'), ([, a, b, c, d]) => ({ color: `rgba(${a},${b},${c},${d})` })],
    // [rgba('^bg'), ([, a, b, c, d]) => ({ 'background-color': `rgb(${a},${b},${c},${d})` })],
    [/^fs-(\d+)$/, ([, a]) => ({ 'font-size': `${a}px` })],

    [
      /^(p|m)(l|r|b|t)-(-)?(\d+)(p\d+)?(f|h|w|r|e)?$/,
      ([, a, p, d, b, c, u]) => ({ [`${a === 'p' ? 'padding' : 'margin'}-${getDiretion(p)}`]: `${d ? '-' : ''}${getUnit(getFloat(b, c), u)}` }),
    ],

    [
      /^(width|w|mw|height|h|mh|top|bottom|right|left|lh)-(\d+)(p\d+)?(f|h|w|r|e)?$/,
      ([, a, b, c, u]) => ({ [`${getDiretion(a)}`]: getUnit(getFloat(b, c), u) }),
    ],
    [/^(top|bottom|right|left)--(\d+)(p\d+)?(f|h|w|r|e)?$/, ([, a, b, c, u]) => ({ [`${getDiretion(a)}`]: '-' + getUnit(getFloat(b, c), u) })],

    [/^br-(\d+)$/, ([, a]) => ({ 'border-radius': `${a}px` })],
    [
      /^br-(t|b)-(l|r)-(\d+)(p\d+)?(f|h|w|r|e)?$/,
      ([, a, d, b, c, u]) => ({ [`border-${getDiretion(a)}-${getDiretion(d)}-radius`]: getUnit(getFloat(b, c), u) }),
    ],
    [borderHex(), ([, a, b, c, d]) => ({ [`border${a ? '-' + getDiretion(a) : ''}`]: `${b}px ${c} #${d}` })],
    // [borderRgba(), ([, a, b, c, d, e, f, g]) => ({ [`border${a ? '-' + getDiretion(a) : ''}`]: `${b}px ${c} rgba(${d},${e},${f},${g})` })],
    [/^scale-(\d+)$/, ([, a]) => ({ transform: `scale(${Number(a) / 10})` })],
    [/^translateX-(-)?(\d+)(p\d+)?(f|h|w|r|e)?$/, ([, m, a, c, u]) => ({ transform: `translateX(${m ? '-' : ''}${getUnit(getFloat(a, c), u)})` })],
    [/^tran-(\d+)$/, ([, a]) => ({ transition: `all ${Number(a) / 10}s` })],
    ['poiter', { cursor: 'pointer' }],
    ['ew-arrow', { cursor: 'ew-resize' }],
    ['not-allowed', { cursor: 'not-allowed' }],
    ['grab', { cursor: 'grab' }],
    ['no-drop', { cursor: 'no-drop' }],
    ['not-allowed', { cursor: 'not-allowed' }],
    ['no-select', { 'user-select': 'none' }],
    ['box-s', { 'box-sizing': 'border-box' }],
    ['as-s', { 'align-self': 'flex-start' }],
    ['as-e', { 'align-self': 'flex-end' }],
    ['as-c', { 'align-self': 'center' }],
    ['as-b', { 'align-self': 'baseline' }],
    ['as-st', { 'align-self': 'stretch' }],
    ['line', { 'border-bottom': '2px solid #CDCDCD' }],
    ['fw-b', { 'font-weight': 'bold' }],
    ['f-ac', { 'align-items': ' center' }],
    ['f-as', { 'align-items': ' flex-start' }],
    ['f-ae', { 'align-items': ' flex-end' }],
    ['f-js', { 'justify-content': ' flex-start' }],
    ['f-jc', { 'justify-content': ' center' }],
    ['f-je', { 'justify-content': ' flex-end' }],
    ['f-jsb', { 'justify-content': 'space-between' }],
    ['f-jsa', { 'justify-content': 'space-around' }],
    ['fr', { display: 'flex', 'flex-direction': 'row' }],
    ['fc', { display: 'flex', 'flex-direction': 'column' }],
    ['fw', { 'flex-wrap': 'wrap' }],
    ['fb', { 'flex-basis': 'auto' }],
    ['fg', { 'flex-grow': '0' }],
    ['fs', { 'flex-shrink': '0' }],
    ['f-1', { flex: 1 }],
    ['b-1', { border: '1px solid #626161' }],
    ['tline', { 'text-decoration': 'line-through' }],
    ['uline', { 'text-decoration': 'underline' }],
    ['hidden', { overflow: 'hidden' }],
    ['f-0', { flex: '0 0 auto' }],
    ['frr', { display: 'flex', 'flex-direction': 'row-reverse' }],
    ['scroll-x', { 'overflow-x': 'scroll' }],
    ['scroll-y', { 'overflow-y': 'scroll' }],
    ['text-c', { 'text-align': 'center' }],
    ['text-l', { 'text-align': 'left' }],
    ['text-r', { 'text-align': 'right' }],
    ['pos-r', { position: 'relative' }],
    ['pos-a', { position: 'absolute' }],
    ['pos-f', { position: 'fixed' }],
    ['vertical-line', { height: '24px', opacity: 0.53, border: '1px solid rgba(203, 203, 203, 0.47)' }],
  ],

  variants: [
    // hover:
    matcher => {
      if (!matcher.startsWith('hover:')) return matcher
      return {
        // slice `hover:` prefix and passed to the next variants and rules
        matcher: matcher.slice(6),
        selector: s => `${s}:hover`,
      }
    },
  ],
  shortcuts: [
    {
      'f-ac-jc': 'f-ac f-jc',
      'f-ac-je': 'f-ac f-je',
      'f-ac-jsb': 'f-ac f-jsb',
      'f-ac-jsa': 'f-ac f-jsa',
      'btn-hover': 'hover:scale-11 tran-1 ',
    },
    [/^mtb-(\d+)$/, ([, c]) => `mt-${c} mb-${c}`],
    [/^mlr-(\d+)$/, ([, c]) => `ml-${c} mr-${c}`],
    [/^ptb-(\d+)$/, ([, c]) => `pt-${c} pb-${c}`],
    [/^plr-(\d+)$/, ([, c]) => `pl-${c} pr-${c}`],
    [/^br-t-(\d+)$/, ([, c]) => `br-t-l-${c} br-t-r-${c}`],
    [/^br-b-(\d+)$/, ([, c]) => `br-b-l-${c} br-b-r-${c}`],
    [/^p-(\d+[fhwre]?)(-\d+[fhwre]?)?(-\d+[fhwre]?)?(-\d+[fhwre]?)?$/, ([, a, b, c, d]) => getmp('p', a, b, c, d)],
    [/^m-(\d+[fhwre]?)(-\d+[fhwre]?)?(-\d+[fhwre]?)?(-\d+[fhwre]?)?$/, ([, a, b, c, d]) => getmp('m', a, b, c, d)],
  ],
}