实用示例。实时演示。
选择一个示例全屏打开,实时预览与源码并排显示。
组件
4带静态与动态参数、子节点、按标识匹配的列表和嵌套数据的普通函数。每个预览都统计自己的挂载次数。
API
13每个构建块一个小演示,与文档中嵌入的相同。
标签构建器
构建器接受属性、静态子节点和动态文本。重命名会改变状态,然后调用 update()。
组件
组件就是一个普通函数。每次 Counter() 调用都保有自己的计数。
属性
属性值可以是函数。第二个按钮翻转 busy 并调用 update();Save 的 disabled 和 aria-busy 随之变化。
事件
onInput 和 onKeyDown 是普通属性。输入文字,然后按 Escape 清空。
生命周期
onMount 启动一个定时器并返回其清理函数。卸载时运行清理,所以计数会暂停,直到计时器再次挂载。
显式更新
count++ 只改变变量。文本在下一次 update() 时才跟上,无论它来自按钮还是页面上的其他任何地方。
动态值
编辑名字。静态文本在元素构建时就固定了;动态文本在每次 update() 时重新运行。forceUpdate() 重建整棵树,所以静态文本也会跟上。
update()
每次 update() 都运行所有动态值,即使其数据没有变化。页面上的其他演示也会推高这个计数。
scope()
两个按钮都添加一项并重命名用户。update('cart') 只刷新带作用域的面板。
when()
第一个为真的条件胜出;否则渲染 .else()。新分支从头构建。
list()
行按标识匹配。勾选一行,然后点 Reverse:同一个 <li> 连同复选框一起移动。
region() 与 into()
一个布局,带有堆叠的主区域和侧边区域,从外部填充。在 Home 中输入,打开对话框再关闭:文本仍在。Article 用一次 into() 填充两个区域。
forceUpdate()
update() 只刷新动态的 lang 行。forceUpdate() 再次调用 App 并修补同一个 <h1>。显式形式只重建这棵树,而非整个页面。
样式
3创建一个类,组合一个类,并使用一个小主题。
SVG
27用 SVG 标签构建器做的图表、动画、工具和游戏,由普通数据、指针事件和 update() 驱动。
柱状图
由数组生成 rect。它们的 y 和 height 是数据的函数,所以 update() 会移动柱子。
折线图
一条 path,其 d 由各点构建,带渐变面积和每点一个圆。
环形图
每个扇区一个圆。stroke-dasharray 给出各自在环上的份额,stroke-dashoffset 给出起点。
SVG 动画
以构建器形式写 SMIL:animateSvg 让太阳脉动,animateTransformSvg 让行星绕行。一个动态的 dur 设定速度。
仪表
一段用 stroke-dashoffset 填充的弧,和一根用 CSS transform 旋转的指针。两者都是同一个数的函数。
雷达图
五个轴上的五个值。形状是一条 path,其 d 由数据算出,所以 update() 会让它变形。
热力图
一组 rect,其 fill-opacity 跟随一个等级。点击格子提升它;一个 titleSvg 子节点是它的提示。
悬停提示
SVG 元素上的指针事件。onPointerEnter 选出活动点,一个提示组滑到它那里。
曲线编辑器
拖动三次贝塞尔曲线的控制柄。onPointerDown 选中一个点,svg 上的 onPointerMove 移动它,path 随之变化。
时钟
表针是 line,其 transform 是时间的函数。onMount 启动走时并返回清理函数。
图标切换
一个用 CSS 过渡变形为叉号的菜单图标,和一个点击时以 SMIL 动画弹跳的心形。
实时流
两条序列随定时器向左滚动。一段与一拍等长的 CSS 过渡让滑动平滑,悬停可读取任意采样。
K 线图
四十个槽位各读取自己的蜡烛。切换时间周期,开关均线,悬停查看数值,或让实时蜡烛走动。
柱状竞赛图
十根柱子从不离开 DOM。排名设定 translateY,所以数值变化时一个过渡把每根柱子滑到它的行。
堆叠面积图
四条带在堆叠、流式和百分比布局之间变形。隐藏一条序列只是让它的带厚度为零,所以每条 path 保持形状。
矩形树图
可以逐级下钻的方化布局。切换指标时每个格子滑到新位置,点击分组则换入它的子项。
实时直方图
样本从四种分布中涌入。每次变化时重新计数分箱,一条拟合的钟形曲线跟随均值,滑块设定分箱数。
画板
指针事件绘制折线。list() 为每一笔渲染一条,正在画的那一笔在每次 update() 时延长。
旋钮
一个自定义滑块:指针的角度设定值,方向键步进,pathLength="100" 把值变成一段虚线。
色轮
按角度选色相,按距离选饱和度。九十个楔形、一个径向渐变和一个深色圆盘组成色轮。
万花尺
一个轮子在环内滚动,一支笔描绘轨迹。每帧延长一段虚线,只更新它自己的 scope()。
弹跳球
requestAnimationFrame 循环中的重力、墙壁和碰撞。拉回再放手,发射一个球。
粘稠团块
一个模糊和一个颜色矩阵滤镜把团块融在一起。一串圆跟随指针。
力导向图
节点互斥,连线牵引,布局逐渐冷却直至静止。拖动节点,或点击一个节点长出子节点。
刷选与缩放
在概览图上刷选一个范围,放大上方的图表。一个跟随刷选的 clipPath 为选区上色。
井字棋
和电脑对弈。when() 添加每个标记,其虚线上的 CSS 动画把它画出来。
环形文字
输入一个徽章。textPath 让文字沿圆弯曲,textLength 让它恰好绕满一圈。
路由
6路由表、匹配、当前路由、层和加载器。nuclo-router 是独立的包:npm install nuclo nuclo-router。
带路由的应用
一个在框架内运行、拥有自己路由器的真实应用:路由表、一个 outlet()、普通链接、等待状态和 404。随意点击,再用返回。
嵌套路由
Docs 是一个带子路由的布局。主题渲染在它的 outlet() 里,./topic 链接相对于布局的路由解析。在笔记中输入,再切换主题:布局永不重建。
路由加载器
文章页导出一个 load(),在页面构建前运行。等待时观察 router.pending,在损坏的文章上抛出时则看到带重试的错误状态。
层
订单表单把客户页作为一层推入并等待其结果。表单不会重新渲染,所以它的备注得以保留。保存会 resolve 这次推入,取消或返回则将其关闭。
多路由器与加载
两个路由器,两个加载指示。商店布局和它的分区都有 load():它们在同一个 router.pending 下并行运行。侧边栏有自己的路由器,已创建但从未启动,其加载标志由 onNavigate 刷新。
模式匹配
静态、:param 和 *rest 模式,以及挂在两个父级下的分区表。输入路径并观察 match(),它不加载任何东西即可解析。
应用
15更大的程序,全屏运行,真实源码放在标签页后面:带窗口的桌面、数据表格、聊天、游戏、编辑器,以及拥有自己状态的库。
页面构建器
直接在页面上书写,拖动把手重排块或把它们移入布局,按 / 插入,右键打开操作。设置网格和弹性布局样式,撤销编辑,以手机尺寸预览并导出 HTML。
算法步进器
引擎是普通 JavaScript:修改数组并在每一步后 yield 的生成器。播放器调用 next() 和 update();柱子是作用于同一批对象的 list(),所以一次交换只移动两个元素。
看板
一个团队看板:添加任务、分派给成员、在对话框中编辑、按人员或搜索过滤、在列间拖动,以及撤销删除。列和卡片是同一批对象的普通数组;每次移动都是一次 splice()。行按标识匹配,所以拖动、排序、分派或编辑卡片都会复用它的元素。屏幕上的挂载计数可以证明。
three.js 检视器
一个拥有自己状态的库。面板直接从 three.js 对象读取位置、颜色和标志,并把编辑写回去。渲染循环每帧调用一次 update();没有任何东西被镜像。
无限滚动
一个没有尽头的信息流:一个快速的假 fetch() 把每一页即时生成到同一个普通数组里。只有视口附近的行在 DOM 中:list() 在两个占位元素之间渲染 posts.slice(start, end),所以到十万条帖子时页面依然轻快。真正末尾处的哨兵在进入视野前就请求下一页。
桌面
一个可用的桌面,带文件、便笺、终端、计算器、计时器、看板、财务和日历。在一个保存于浏览器中的共享模拟磁盘上创建和整理文件夹、编辑便笺、使用 shell 命令。直接用键盘在计算器中输入,点击终端任意位置聚焦其输入行,在看板的列间拖动卡片,或在财务电子表格中记账并看图表随之变化——账本保存在 IndexedDB 中。移动、缩放和切换应用时窗口保持自己的状态;运行中的计时器用 into() 填充任务栏托盘。
节点图
把数字、文本和开关接入数学、比较和 If 节点,每个值随你的输入实时更新。函数也是图:它们的 Input 和 Output 节点就是每个 Call 的端口,而 Call 可以指向自己所在的函数,所以 factorial 和 sum 以 If 作为出口进行递归。引擎是普通 JavaScript:每个节点是一个生成器,通过 yield 请求输入,一个循环用自己的栈驱动它们,所以 sum(50000) 嵌套五万层调用约只需十分之一秒,且不触碰 JavaScript 调用栈。只有步数预算能阻止没有出口的递归。拖动写入 x 和 y 并只更新画布作用域;运行计数表明移动从不触发图的运行。
数据表格
一张作用于 10,000 个普通行对象的工作表。搜索、过滤、排序和分页都是作用于数组的普通函数,表体是作用于当前页的 list()。行按标识匹配,所以排序只移动留在本页的行,编辑过的行在任何地方都是同一个对象。已构建行数可以证明。
聊天
一个有三个频道的聊天,每个频道是一个普通对象:历史、游标、正在输入、草稿和滚动位置,所以切换时每个频道都保持原样,update("chat-sidebar") 只刷新未读角标。历史用 unshift() 无限向上加载,scrollTop 按新增高度增长。你的消息在服务器收到前就已显示,send() 修补同一个对象,重试、编辑、删除和表情回应从不重建它所在的行。消息支持渲染代码、粗体、链接和 @提及。
实时仪表盘
以不同频率刷新的卡片,从每秒 20 次到每秒 1 次。每张卡片是一个 scope(),它的定时器带着卡片 id 调用 update(),所以一拍只求值那张卡片。每个动态值都在屏幕上计数:换成普通的 update(),时钟每秒会被求值约一百次,却只变化一次。
像素编辑器
图片是一个含 1024 个颜色字符串的普通数组,每个格子从中读取颜色。一笔写入数组并调用 update();结束时编辑器用 slice() 保留一份副本。撤销、重做和历史 list() 中的每一步都把旧数组放回去:没有 store,没有不可变数据。
贪吃蛇
游戏循环是一个定时器,在普通对象上调用 step(),然后每拍调用一次 update()。蛇是其格子对象的 list(),每一拍尾部对象变成新的头部,所以只有一个元素移动,没有任何元素被构建:已构建段数只在蛇进食时增加。食物以 keyframes() 动画弹出。
步进音序器
一个拥有自己时钟的库。Web Audio 在自己的时间线上提前预订每个音符,节拍是一个普通的二维布尔数组,网格翻转它,调度器读取它,所以点击会在下一轮被听到。播放头只在可听步变化时更新自己的 scope()。音频在第一次播放时启动,并在挂载清理中关闭,所以离开示例就会停止声音。
语言切换
每个标签都是静态值,写法与单语言应用一样,所以 update() 从不再读它们:购物车点击只刷新数量和总计。切换语言在这棵树上调用 forceUpdate(),它再次运行组件并修补同样的元素,包括 lang 和 dir。货币、复数、日期和列表来自 Intl,购物车和已输入的优惠码在切换后仍然保留。
主题编辑器
一个小型组件库:createCss() 命名 token,variants() 用它们构建按钮、徽章、卡片、输入框、警告和开关。token 是 CSS 变量,所以每个类只编译一次。每个控件写入一个普通的主题对象并调用 update(),它重写一个 style 元素的文本。