- 前端
- UI组件
【免费下载链接】jss
JSS is an authoring tool for CSS which uses JavaScript as a host language.
JSS(CSS-in-JS 的 JavaScript 样式创作工具)通过jss-plugin-rule-value-observable插件原生支持 TC39 Observables 提案(proposal-observable 为骨架,结合仓库中的插件源码与测试用例,系统讲解 Observable 值的接入、Observable 规则的声明、process: false的性能开关,以及完整的安装与集成方式。
一、插件定位与核心机制
jss-plugin-rule-value-observable是 JSS 官方的 Observables 支持插件,其本质是一个值/规则转换器:它拦截样式对象中所有"可观察"的值,一旦检测到值是符合 TC39 Observable 约定的对象,就订阅该流,并把流中每次发射的新值实时写入对应的 CSS 规则;当整个样式对象本身就是 Observable 时,插件会先创建一条空规则,再随流中发射的样式对象逐属性填充。项目仓库中该插件的完整源码位于 packages/jss-plugin-rule-value-observable/src/index.js,其包描述在 packages/jss-plugin-rule-value-observable/package.json 中明确标注为 "JSS plugin for TC39 Observables support",版本与 JSS 核心保持同步(当前仓库为 10.10.0)。
1.1 如何判定一个值是 Observable
插件的入口是一个关键的isObservable判断函数:
const isObservable = (value) => value && value[$$observable] && value === value[$$observable]()其中$$observable来自symbol-observable包(见 packages/jss-plugin-rule-value-observable/package.json 的 dependencies)。TC39 Observable 提案约定:一个对象只要实现了Symbol.observable方法,并且调用该方法返回其自身,就被认定为 Observable。因此,任何遵循这一约定的库(如 RxJS、Zen Observable 等)都可以无缝接入,插件并不绑定某个特定流库。
1.2 两条处理通道:onCreateRule 与 onProcessRule
从 packages/jss-plugin-rule-value-observable/src/index.js 的实现可以看到,插件通过 JSS 的两个生命周期钩子分两条通道工作:
- onCreateRule(Observable 规则通道):当声明整条规则的
decl本身是 Observable 时,先用createRule(name, {}, options)创建一条空规则,然后style$.subscribe(...)订阅流;流每次发射一个样式对象时,遍历其属性并逐个调用rule.prop(prop, style[prop], updateOptions)写入规则。 - onProcessRule(Observable 值通道):当规则本身是普通样式对象、但其中某个属性值是 Observable 时,先
delete style[prop]把流从静态样式中移除,再订阅该值流,每次发射新值时调用styleRule.prop(prop, nextValue, updateOptions)更新该属性。
两条通道共同保证了"值级"与"规则级"两种响应式写法都能工作,且与普通静态样式规则可以共存于同一张样式表中。
1.3 前置条件:link: true
无论使用哪种写法,插件正常工作都依赖样式表选项link: true。这是因为流更新的落点依赖于 packages/jss/src/plugins/styleRule.js 中prop()方法的行为:当link: true时规则与 DOM 中的真实渲染节点(renderable)建立关联,prop()才能把新值直接写入 CSSOM(见 packages/jss/src/plugins/styleRule.js 中this.renderable && this.renderer分支)。若缺少该选项,JSS 会抛出警告[JSS] Rule is not linked. Missing sheet option "link: true".(见 packages/jss/src/plugins/styleRule.js),流式更新将无法实时反映到渲染结果中。
二、安装与基本接入
2.1 安装插件
使用 npm 或 yarn 安装(见 packages/jss-plugin-rule-value-observable/readme.md):
npm install jss-plugin-rule-value-observable # 或 yarn add jss-plugin-rule-value-observable2.2 注册插件
在创建样式表之前,通过jss.use()注册插件即可:
import jss from 'jss' import jssPluginRuleValueObservable from 'jss-plugin-rule-value-observable' jss.use(jssPluginRuleValueObservable()) const styles = { button: { color: new Observable(observer => { observer.next('red') }) } } const {classes} = jss.createStyleSheet(styles, {link: true}).attach()仓库中提供了可直接运行的完整演示示例:examples/plugins/jss-plugin-rule-value-observable/app.js,其中包含jss.use()注册、createStyleSheet(styles, {link: true})创建以及渲染<button>元素的完整链路,与上方代码保持一致。
三、Observable 值(Observable Values)
当样式对象中的单个属性值是一个 Observable 时,该属性就会随流的每次发射而更新。文档中的经典示例:
import {Observable} from 'rxjs' const styles = { button: { color: new Observable((observer) => { observer.next('red') }) } }创建样式表并 attach 后,生成的 CSS 为:
.button-0 { color: red; }3.1 运行时实时更新
值流的威力在于"实时":当 observer 后续再发射新值(例如把颜色从red变为blue),styleRule.prop()会立即被调用,CSSOM 与样式字符串同步更新,无需重建样式表。这一点在 packages/jss-plugin-rule-value-observable/src/observable-values.test.js 中有非常直观的验证:
- 初始订阅:创建样式表后,observer 被订阅(测试
should subscribe the observer); - 发射
'10px'后,输出.a-id { height: 10px; }; - 再次发射
'20px'后,输出更新为.a-id { height: 20px; }(见测试should update the value 2)。
这证明一个 Observable 值可以驱动属性在多个状态间持续切换,非常适合动画帧、拖拽、实时数据等场景。
3.2 与 default-unit 插件的配合
值流中发射的值同样会经过 JSS 的 value 处理管线。测试用例(packages/jss-plugin-rule-value-observable/src/observable-values.test.js)中注册了pluginObservable()与pluginDefaultUnit():当流发射数字20时,输出为height: 20px;(default-unit 自动补上px单位);而禁用处理时则原样输出height: 20;。这说明 Observable 值更新默认会继续经过后续插件(如默认单位、驼峰转 kebab、厂商前缀等)的加工。
四、Observable 规则(Observable Rules)
与"值级"响应式相对,"规则级"响应式允许整条规则本身是一个 Observable,流中发射的内容是一整个样式对象。文档示例:
import {Observable} from 'rxjs' const styles = { button: new Observable((observer) => { observer.next({ color: 'red', opacity: 1 }) }) }初始生成的 CSS:
.button-0 { color: red; opacity: 1; }4.1 多属性与多规则的流式更新
packages/jss-plugin-rule-value-observable/src/observable-rules.test.js 验证了规则流的多种行为:
- 连续发射:先发射
{opacity: '0', height: '5px'},再发射{opacity: '1', height: '10px'},规则随之从.div-id { opacity: 0; height: 5px; }更新为.div-id { opacity: 1; height: 10px; }; - 多条规则独立订阅:
div与button各自绑定独立 Observable,互不干扰,可分别驱动; - 与静态规则混合:同一张表中既有 Observable 规则(div、button),又有普通静态规则(a),三者可以同时存在并各自输出;
- 同步发射:在 Observable 构造器内部立即
observer.next(...)的值也能被正确捕获,且之后仍可继续接受新的发射(测试should update synchronous values when it receives a new emission)。
4.2 规则流的属性处理管线
规则流发射的样式对象同样默认走完整处理管线。测试should process props and values证明:发射{marginLeft: 20}时,在同时注册 camelCase 与 default-unit 插件的情况下,输出为margin-left: 20px;——属性名被转换为 kebab-case,数字被补上px单位。这意味你在流中可以用更自然的 camelCase 写法。
五、关闭处理开销:process: false
默认情况下,插件会对 Observable 发射出的值或规则做完整加工。若你的流中已经预先输出最终 CSS 形态(例如服务端或上游已经完成了属性名转换与单位处理),出于性能考虑可以传入process: false关闭这一层处理。
5.1 单独注册时的用法
import jss from 'jss' import pluginObservable from 'jss-plugin-rule-value-observable' import pluginCamelCase from 'jss-plugin-camel-case' import pluginDefaultUnit from 'jss-plugin-default-unit' jss.use(pluginObservable({process: false}), pluginCamelCase(), pluginDefaultUnit())5.2 通过 jss-preset-default 的用法
官方默认预设 packages/jss-preset-default/src/index.js 已内置本插件(顺序位于 function 插件之后),并支持把配置透传给插件:observable(options.observable)。因此可通过setup统一配置:
import jss from 'jss' import preset from 'jss-preset-default' jss.setup( preset({ observable: {process: false} }) )5.3 process: false 的实际影响
从源码(packages/jss-plugin-rule-value-observable/src/index.js)看,updateOptions正是创建插件时传入的选项对象,它会被透传给每次rule.prop()/styleRule.prop()调用。对照 packages/jss/src/plugins/styleRule.js 中prop()的实现:
if (!options || options.process !== false) { newValue = this.options.jss.plugins.onChangeValue(value, name, this) }可见process: false会跳过onChangeValue这一整条值处理链。测试用例也验证了这一行为(见 packages/jss-plugin-rule-value-observable/src/observable-rules.test.js 的should not process props or values):发射{marginLeft: 20}时,即便同时注册了 camelCase 与 default-unit 插件,输出仍是未加工的marginLeft: 20;。因此该选项适合对流内容已完全确定、且希望省去每帧处理开销的高频动画场景。
六、类型定义与生态集成
该插件提供了完整的 TypeScript 类型声明 packages/jss-plugin-rule-value-observable/src/index.d.ts,其中Options类型直接复用 JSS 核心的UpdateOptions(即{process?: boolean}形态的配置对象),并返回标准Plugin类型,便于在 TS 项目中以类型安全的方式配置:
import jssPluginSyntaxRuleValueObservable from 'jss-plugin-rule-value-observable' jss.use(jssPluginSyntaxRuleValueObservable({process: false}))该插件的 keywords(见 packages/jss-plugin-rule-value-observable/package.json)覆盖observable、reactive、rxjs等,表明其定位于响应式/流式样式生态。与 packages/jss-plugin-rule-value-function(函数值插件)可以互补使用:函数值适合"每次渲染基于 props 计算",而 Observable 适合"随时间连续推送、由外部流驱动"的场景。
七、运行示例与验证路径
仓库中提供了开箱即用的演示项目:
- 示例源码:examples/plugins/jss-plugin-rule-value-observable/app.js(基于 RxJS 的
Observable演示按钮颜色随流更新); - 值级测试:packages/jss-plugin-rule-value-observable/src/observable-values.test.js(含
process开关对比用例); - 规则级测试:packages/jss-plugin-rule-value-observable/src/observable-rules.test.js(含多规则、混合规则、同步发射、处理管线等完整覆盖);
- 入口测试聚合:packages/jss-plugin-rule-value-observable/src/index.test.js;
- 插件实现:packages/jss-plugin-rule-value-observable/src/index.js。
遵循 TC39 Observable 提案的任何流库(RxJS、Zen Observable 等)均可配合使用。需要留意的是,源码中保留了一处 TODO 注释(packages/jss-plugin-rule-value-observable/src/index.js):当前实现订阅后尚未显式管理退订(subscription),在样式表生命周期管理要求严格的长期运行应用中,应结合自身场景评估是否需要在移除样式表时手动断开流。
八、快速上手清单
- 安装:
npm install jss-plugin-rule-value-observable; - 注册:
jss.use(jssPluginRuleValueObservable()),或通过jss-preset-default的preset({observable: {...}})透传配置; - 建表:
jss.createStyleSheet(styles, {link: true})——务必带link: true; - 值级写法:属性值为
new Observable(...),发射单个样式值; - 规则级写法:规则本身为
new Observable(...),发射整个样式对象; - 性能优化:若流内容已为最终 CSS 形态,注册时传
{process: false}跳过加工管线。
- 前端
- UI组件
【免费下载链接】jss
JSS is an authoring tool for CSS which uses JavaScript as a host language.
相关推荐
CamillaDSP多平台部署教程:Linux、Windows与macOS安装配置全攻略
CamillaDSP多平台部署教程:Linux、Windows与macOS安装配置全攻略 CamillaDSP是一款灵活的跨平台IIR和FIR引擎,适用于分频器
在 Gatsby 中集成 JSS:基于 using-jss 示例与 gatsby-plugin-jss 的样式方案实战
在 Gatsby 中集成 JSS:基于 using jss 示例与 gatsby plugin jss 的样式方案实战 本指南以仓库中的 examples/us
前端静态站点Web框架Imba Observable 响应式编程:用 @observable、@autorun 与 @computed 构建声明式状态逻辑
Imba Observable 响应式编程:用 @observable、@autorun 与 @computed 构建声明式状态逻辑 Imba 在语言层面内置了
编程语言编译器语言运行时
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考