Selectors
core:selectors 插件在渲染前解析選擇器別名。它支援靜態對應和基於 RegExp 的動態模式,並具備遞迴解析功能。
運作原理
- 選擇器定義在
rawConfigConfigured期間從config.selectors.selectors收集。 - 在
configureEngine期間,每個定義會被解析並註冊:- 靜態規則儲存供精確比對查找。
- 動態規則儲存供基於 RegExp 的比對。
- 為已知選擇器新增自動補齊條目。
- 在
transformSelectors期間,每個選擇器字串透過SelectorResolver遞迴解析。 - 若選擇器不符合任何規則,則原始字串保持不變並回傳。
- 動態解析結果會透過
onResolved自動回饋至自動補齊。
設定
ts
interface SelectorsConfig {
/** Array of selector definitions. */
selectors: Selector[]
}選擇器定義格式
有四種定義選擇器的方式。
字串形式
純字串僅作為自動補齊建議登錄——不會建立解析規則。
ts
import { defineSelector } from '@pikacss/core'
// String form — autocomplete suggestion only, no resolution rule
const selector = defineSelector('hover')元組形式——靜態
雙元素元組將選擇器名稱對應至一個或多個替換字串。使用 $ 作為元素預設選擇器的佔位符(見下方的 $ 佔位符)。
ts
type TupleFormStatic = [selector: string, value: string | string[]]ts
import { defineSelector } from '@pikacss/core'
// Static tuple: [name, replacement]
// Use $ as a placeholder for the element's default selector
const hover = defineSelector(['hover', '$:hover'])
const focus = defineSelector(['focus', '$:focus'])
const firstChild = defineSelector(['first-child', '$:first-child'])
// Ancestor / wrapper selectors
const dark = defineSelector(['dark', '[data-theme="dark"] $'])
// At-rules — do NOT include $ inside at-rules
const md = defineSelector(['md', '@media (min-width: 768px)'])
const lg = defineSelector(['lg', '@media (min-width: 1024px)'])
// Multiple values (array form)
const hoverOrFocus = defineSelector(['hover-or-focus', ['$:hover', '$:focus']])元組形式——動態
具有 RegExp 模式和解析函式的元組。函式接收 RegExpMatchArray 並回傳一個或多個替換字串。可選的第三個元素提供自動補齊提示。
ts
type TupleFormDynamic = [selector: RegExp, value: (matched: RegExpMatchArray) => string | string[], autocomplete?: string | string[]]ts
import { defineSelector } from '@pikacss/core'
// Dynamic tuple: [pattern, resolver, autocomplete?]
// The resolver function receives the RegExp match array
const screen = defineSelector([
/^screen-(\d+)$/,
m => `@media (min-width: ${m[1]}px)`,
['screen-640', 'screen-768', 'screen-1024'], // autocomplete hints
])物件形式
等同於元組形式,但使用具名屬性。支援靜態和動態兩種變體:
ts
import { defineSelector } from '@pikacss/core'
// Object form — static
const hover = defineSelector({
selector: 'hover',
value: '$:hover',
})
// Object form — dynamic (with autocomplete)
const breakpoint = defineSelector({
selector: /^bp-(\d+)$/,
value: (m: RegExpMatchArray) => `@media (min-width: ${m[1]}px)`,
autocomplete: ['bp-640', 'bp-768', 'bp-1024'],
})完整範例
ts
// pika.config.ts
import { defineEngineConfig } from '@pikacss/core'
export default defineEngineConfig({
selectors: {
selectors: [
// String form — autocomplete only
'my-selector',
// Static selectors
['hover', '$:hover'],
['focus', '$:focus'],
['first-child', '$:first-child'],
['dark', '[data-theme="dark"] $'],
['md', '@media (min-width: 768px)'],
['lg', '@media (min-width: 1024px)'],
// Dynamic selectors
[
/^screen-(\d+)$/,
m => `@media (min-width: ${m[1]}px)`,
['screen-640', 'screen-768', 'screen-1024'],
],
// Object form
{
selector: 'active',
value: '$:active',
},
],
},
})與 pika() 搭配使用
在樣式定義中使用選擇器名稱作為鍵。任何不是 CSS 屬性的鍵都會被視為選擇器:
ts
// Use selector names as keys in style definitions
const className = pika({
color: 'black',
hover: {
color: 'blue',
},
dark: {
color: 'white',
},
md: {
fontSize: '1.25rem',
},
})產生的 CSS 輸出:
css
.a { color: black; }
.b:hover { color: blue; }
[data-theme="dark"] .c { color: white; }
@media (min-width: 768px) {
.d { font-size: 1.25rem; }
}$ 佔位符
在選擇器值中,$ 會被替換為元素的預設選擇器(預設為 .%,其中 % 是原子化樣式 ID 佔位符)。這使得偽類、祖先選擇器等得以實現。
ts
import { defineSelector } from '@pikacss/core'
// $ is replaced with the element's default selector (e.g., .%)
// Then % is replaced with the atomic style ID (e.g., a)
// Pseudo-class: append to the element selector
const hover = defineSelector(['hover', '$:hover'])
// $ → .% → .%:hover → .a:hover
// Pseudo-element: append to the element selector
const before = defineSelector(['before', '$::before'])
// $ → .% → .%::before → .a::before
// Ancestor selector: place $ after the parent
const dark = defineSelector(['dark', '[data-theme="dark"] $'])
// $ → .% → [data-theme="dark"] .% → [data-theme="dark"] .a
// At-rules: no $ needed — the engine auto-appends the element selector
const md = defineSelector(['md', '@media (min-width: 768px)'])
// no $, no % → defaultSelector (.%) is appended → two-level nesting:
// @media (min-width: 768px) { .a { ... } }佔位符行為摘要
| 定義 | $ → defaultSelector | 最終 CSS |
|---|---|---|
['hover', '$:hover'] | .%:hover | .a:hover { ... } |
['before', '$::before'] | .%::before | .a::before { ... } |
['dark', '[data-theme="dark"] $'] | [data-theme="dark"] .% | [data-theme="dark"] .a { ... } |
['md', '@media (min-width: 768px)'] | (無 $) | @media (min-width: 768px) { .a { ... } } |
At-Rules
對於 CSS at-rules,如 @media 或 @container,請勿在值中包含 $。當解析後的選擇器不包含 % 佔位符時,引擎會自動將預設選擇器(.%)作為巢狀層級附加,產生正確的兩層結構:
css
@media (min-width: 768px) {
.a { ... }
}WARNING
請勿將 $ 嵌入 at-rule 字串中(例如 @media (...) { $ })。這會產生 @media (...) { .a } 作為單一區塊選擇器,導致無效的 CSS。
遞迴解析
選擇器解析是遞迴的。選擇器值可以參照另一個選擇器名稱,並透過鏈式關係進行解析:
ts
import { defineEngineConfig } from '@pikacss/core'
export default defineEngineConfig({
selectors: {
selectors: [
// Base selector
['hover', '$:hover'],
// Alias that resolves to another selector
['alias-hover', 'hover'],
// Chained: group-hover resolves through its own rule
['group-hover', '.group:hover $'],
],
},
})
// Using 'alias-hover' in a style definition:
// → resolves 'alias-hover' to 'hover'
// → resolves 'hover' to '$:hover'
// → final output: .a:hover { ... }defineSelector 輔助函式
使用 defineSelector() 輔助函式,可獲得具備完整自動補齊的型別安全選擇器定義:
ts
import { defineSelector } from '@pikacss/core'
// defineSelector() provides type safety and autocomplete
// for all selector definition formats
const hover = defineSelector(['hover', '$:hover'])
const dark = defineSelector({
selector: 'dark',
value: '[data-theme="dark"] $',
})Engine API
插件可以用程式方式管理選擇器:
engine.selectors.resolver—SelectorResolver實例engine.selectors.add(...list)— 在執行階段新增選擇器定義
行為說明
- 無效的選擇器設定形式會被靜默略過。
- 動態解析結果在首次解析後會被快取。
- 靜態和動態規則都儲存在繼承自
AbstractResolver的SelectorResolver中。 $佔位符遵循引擎的defaultSelector選項(預設為.%)。
原始碼參考
packages/core/src/internal/plugins/selectors.ts
Next
- 繼續閱讀 Shortcuts