本文适合对 Cycle.js 刚兴趣和入门, 主打轻量级。
什么是 Cycle.js?
Cycle.js 与其他的前端框架有明显的不同。是一个函数式具有响应编程能力的主打人机交互的前端框架。
Cycle.js 特点
- 函数式编程,函数为一等公民。
- 主函数,处理响应式数据程序。
- 启动器,处理副作用,属于主函数之外,专职与外部世界进行副作用交互(例如:定时器,http 请求等等...)
- RxJs 底层支持
- ...
数据流与核心概念
- main 函数
- Sources 资源(main 函数参数)
- main 函数中的纯函数操作
- Sinks 输出
- 外部副作用
示例
- 基于 vite 创建一个原生 JS 项目并给基本逻辑改造
sh
cd your_target_dir
pnpx create-vite cyclejs
# 安装依赖
pnpm add @cycle/dom @cycle/run
- 主 html
html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Cycle.js with Vite App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
- js 逻辑
ts
import {run} from '@cycle/run'
import {div, label, input, hr, h1, makeDOMDriver} from '@cycle/dom'
function main(sources) {
const input$ = sources.DOM.select('.field').events('input')
const name$ = input$.map(ev => ev.target.value).startWith('') // 从输入流中获取 name
// 在 map 操作符中返回虚拟可观察 dom
const vdom$ = name$.map(name =>
div([
label('Name:'),
input('.field', {attrs: {type: 'text'}}),
hr(),
h1('Hello ' + name),
])
)
return { DOM: vdom$ } // 返回一个可观察的 dom
}
run(main, { DOM: makeDOMDriver('#app') }); // 运行主函数
- 效果
RxJS 支持
Cycle.js 的核心概念是将整个应用程序视为数据流的集合,而RxJS提供了处理这些数据流的强大工具和操作符。Cycle.js的数据流管理部分是建立在RxJS之上的,使得开发者可以方便地处理数据的变化和响应式事件。
底层虚拟 dom: snabbdom
ts
"dependencies": {
"snabbdom": "^3.4.0",
"snabbdom-selector": "^5.0.0",
},
- 虚拟 DOM 树构建与比较: 使用 Snabbdom,可以轻松地创建虚拟 DOM 树,表示应用程序的状态和视图结构。这些虚拟 DOM 树是 Snabbdom 的核心数据结构。 Snabbdom 会在两个虚拟 DOM 树之间执行比较操作,找出它们之间的差异。可用于更新实际的浏览器 DOM。
- 选择器库支持: Snabbdom-selector 是一个用于处理选择器的库,使用选择器来查找和操作虚拟 DOM 树中的元素。处理复杂的视图结构。
资源
小结
Cycle.js 主逻辑非常简单,一个 run 函数,一个 main 函数和驱动对象。本文基于 vite + cycle.js 实现一个小的小的示例。Cycle.js 难点在于,要从原生 JS 和主流框架的思想中进入响应式编程和纯函数式编程。实践中编写函数代码逻辑和外部 effect 逻辑,与现有逻辑不同,响应式编程有自己的世界,功能特别的强大,需要根据自己的情况进行使用。