天天看點

【原子樣式實踐】第6篇 一行指令的微信小程式原子樣式工具

本系列之前文章(第1-5篇),已經較為清楚的介紹了原子樣式的特點、構成和實作原理。本文說明怎樣開發一個快捷工具用于生成微信小程式原子樣式。

1 開發成果

1.1 配置環境

windows 環境 Terminal 中運作

iwr https://deno.land/install.ps1 -useb | iex      

安裝完成後,通過 ​

​deno --version​

​​ 檢視版本,也可以運作 ​

​deno run https://deno.land/std/examples/welcome.ts​

​ 執行第一個腳本。

1.2 運作工具

安裝完畢後,進入小程式源碼目錄執行

deno run --allow-read --allow-write https://deno.land/x/wxmp_atomic_css/worker.ts      

miniprogram 目錄下有四個樣式檔案:

(1)reset.wxss 樣式重置檔案,使用 tagName 定義。

(2)font.wxss 是字型資源,定義字型和字型名稱。

(3)mini.wxss 是原子樣式檔案。程式将會根據目錄下的 wxml 檔案自動生成 mini.wxss,忽略 font.wxss 和  app.wxss 中已經生成的樣式。

(4)app.wxss 是全局樣式檔案,導入 reset.wxss、font.wxss 和 mini.wxss。 

@import "reset.wxss";
@import "font.wxss";
@import "mini.wxss";      

 1.3 運作結果

運作過程中,對于不支援的樣式會以警告資訊列出來。

Download https://deno.land/x/wxmp_atomic_css/worker.ts
Compile https://deno.land/x/wxmp_atomic_css/worker.ts
2022-9-19 9:20:56.384  [prepare] prase ./miniprogram/app.json, get 34 wxmp pages
...
2022-9-19 9:20:56.731  [generate] find 27 units -  0,1,10,120,144,150,160,2,20,200,24,256,28,3,300,32,36,4,48,64,72,8,80,90,96,d5,full
2022-9-19 9:20:56.731  [warning] total found 6 warnings
2022-9-19 9:20:56.731  [warning] expression [bg-blue] has no matched rules
2022-9-19 9:20:56.731  [warning] expression [op55555] has no matched rules
2022-9-19 9:20:56.731  [warning] expression [round-round-10] has no matched rules
2022-9-19 9:20:56.731  [warning] expression [userinfo] has no matched rules
2022-9-19 9:20:56.731  [warning] expression [userinfo-avatar] has no matched rules
2022-9-19 9:20:56.731  [warning] expression [userinfo-nickname] has no matched rules
2022-9-19 9:20:56.735  [save] save 23027 chars to ./miniprogram/mini.wxss
2022-9-19 9:20:56.735  css service started      

2 主要函數

2.1 源碼

最新版本釋出在 github 源碼

參見 ​​wxmp-atomic-css/worker.ts at main · foxgst/wxmp-atomic-css (github.com)​​

2.2 從wxml檔案提取class

解決思路

使用html解析工具(選型 htmlok),提取class屬性值,然後進行正規表達式比對,提取樣式名稱。

難點分析

微信小程式 class 中允許使用三目運算符和對象,可以動态判定樣式。

樣例1:

px-20 h-96 flex-row ai-center gap-20

樣例2:

c1 flex-cc ml-32 mr-32 h-96 {{ name && shortName && contactPhone ? 'bg-primary text-white' : 'bg-gray-7 text-black' }}

樣例3:

c1 flex-cc flex-col {{  courseMap[weekDayName][hour[2]].length == 0 ? 'jc-center' : 'jc-center' }}  py-10 gap-20

樣例4:

wh-64 {{ day.absent === 1 ? 'bg-red-7 text-white' : (day.signAt ? 'bg-green-7 text-white' : (day.classId ? 'bg-primary text-white': 'bg-gray-5 text-black')) }} {{ day.t ? ' ff-n text-28' : '' }} {{ day.d == 1 ? 'round' : 'round-8' }} flex-cc border border-2 {{ dayIndex == di ? 'border-black' : 'border-transparent' }}

實作方案

關鍵符号是​

​?​

​​,可以據此進行清理,剩下的部分使用​

​\w+​

​即可提取

const extraClassItem = (className: string): string[] => {
    if (className == "" || className.length < 2) {
      return []
    }
    className = className.replace(/[a-zA-Z\d\.\s=&\[\]<>!]+\?/g, "")
    if (className.match(/^[\s\da-z-\\.]+$/)) {
      return className.trim().split(/\s+/)
    }
    const result = className.trim().match(/[\w-]+/g)
    if (!result) {
      return []
    }
    return result.filter(m => m.length > 1 && !/[A-Z]/.test(m))
  }      

2.3 組合樣式使用

原子樣式在功能上完全分割時,使用較為繁瑣,需要對部分進行組合,友善使用。從應用出發,場景不可分割作為組合樣式的判定标準。

解決思路

每條樣式規則的樣式即可使用​

​expr​

​​直接表示,也可以使用​

​compose​

​進行組合,組合值為樣式規則名稱或者樣式值。

難點分析

(1)組合樣式規則可能嵌套。(2)規則組合時可能帶特定或者額外的數值機關或顔色。

實作方案

(1)通過棧處理嵌套規則,疊加樣式,對後面原子樣式覆寫帶來便利。

(2)通過正規表達式提取規則參數,可以有效識别規則外的樣式名稱。

樣例1

{
  package: "spacing.padding.ext",
  syntax: "p-[U]",
  compose: ['pl-[U]', 'pr-[U]', 'pt-[U]', 'pb-[U]']
},
{
  package: "spacing.padding.ext",
  desc: "padding-x-axis",
  syntax: "px-[U]",
  compose: ['pl-[U]', 'pr-[U]']
},
{
  package: "spacing.padding.ext",
  desc: "padding-y-axis",
  syntax: "py-[U]",
  compose: ['pt-[U]', 'pb-[U]']
},
{
  package: "spacing.padding.ext",
  syntax: "pt-[U]",
  expr: "padding-top: var(--unit-[U]);"
},
{
  package: "spacing.padding.ext",
  syntax: "pb-[U]",
  expr: "padding-bottom: var(--unit-[U]);"
},
{
  package: "spacing.padding.ext",
  syntax: "pl-[U]",
  expr: "padding-left: var(--unit-[U]);"
},
{
  package: "spacing.padding.ext",
  syntax: "pr-[U]",
  expr: "padding-right: var(--unit-[U]);"
},      

樣例2

{
  package: "sizing.size.ext",
  syntax: "wh-screen",
  compose: ['w-full', 'h-full', 'pos-abs', 'top-0', 'bottom-0', 'left-0', 'right-0']
},
{
  package: "sizing.width.ext",
  syntax: "w-[U]",
  expr: "width: var(--unit-[U]);"
},
{
  package: "sizing.height.ext",
  syntax: "h-[U]",
  expr: "height: var(--unit-[U]);"
},
{
  package: "layout.float.core",
  syntax: "pos-abs",
  expr: "position: absolute;"
},
{
  package: "layout.float.ext",
  syntax: "top-[U]",
  expr: "top: var(--unit-[U]);"
},
{
  package: "layout.float.ext",
  syntax: "bottom-[U]",
  expr: "bottom: var(--unit-[U]);"
},
{
  package: "layout.float.ext",
  syntax: "left-[U]",
  expr: "left: var(--unit-[U]);"
},
{
  package: "layout.float.ext",
  syntax: "right-[U]",
  expr: "right: var(--unit-[U]);"
},      

生成正規表達式規則

// 生成正規表達式
const regexExpr = style.syntax
.replace("[U]", "(?<U>[0-9a-z]+)")
.replace("[C]", "(?<C>[a-z]+)")
.replace("[N]", "(?<N>[0-9]+)")
.replace("[A]", "(?<A>[0-9]+)")
// 設定規則名稱
style.syntaxRegex = new RegExp("^" + regexExpr + "$")      

2.4 實時生成樣式

通過 watch 函數監測目錄變化,檢測到 wxml 變動時重新生成原子樣式。

3 小結

繼續閱讀