骨头
Skeletor是一个轻量级,TypeScript-first反应数据库.
它允许您定义打入的模型,并用事件或订阅来响应变化, 同时坚持索引数据库、本地Storage、会话Storage、SQLite(节点)或REST API.
骨骼器是一种现代化的重写 后骨模式和收藏, 没有jQuery, 没有突触, 也没有查看或运行。 如果你知道Backbone的一切的话 直接转让。 不取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取出.
骨骼力量 交锋.js,一个全功能的开源XMPP聊天客户端.
为什么是骨骼?
- 反应模型 ——设定属性,获得属性
change活动。 使用回调和未订阅功能订阅 。 在任何UI层工作. - 直接属性访问 —— 说
model.attrs.name = 'Bob'火灾改变事件,不需要锅炉板. - 计算属性 ——声明有明确依赖关系的衍生值;它们缓存、重新计算和起火
change自动事件. - 存储式订阅 —— 说
subscribe()返回未订阅的函数,与 React 兼容useSyncExternalStore和类似的API. - 内建的持久性 ——索引DB, localStorage, sessionStorage, SQLite (Node), 和 REST 退出框.
- 类型脚本第一 ——完整类型定义,通用模型属性,被打入计算属性.
- 没有 j 查询, 没有强调 ——本地浏览器 API 和 摇篮 单项进口用于震动树木.
- 到处都行 ——浏览器,Node.js(22+),Web Workers. 包括无害环境管理+CJS.
- 与后骨兼容 —— 说
get, (中文(简体) ),set,事件,收藏:都在那里. Backbone数据层的倒置替换.
安装
npm install @converse/skeletor
快速启动
型号
import { Model } from '@converse/skeletor';
interface UserAttrs {
firstName: string;
lastName: string;
active: boolean;
}
class User extends Model<UserAttrs> {
get defaults() {
return { firstName: '', lastName: '', active: false };
}
get computed() {
return {
fullName: {
deps: ['firstName', 'lastName'],
fn: (model: User) => `${model.get('firstName')} ${model.get('lastName')}`,
},
};
}
}
const user = new User({ firstName: 'Alice', lastName: 'Smith' });
// Read — three equivalent ways
user.get('firstName'); // → 'Alice'
user.attrs.firstName; // → 'Alice'
user.get('fullName'); // → 'Alice Smith' (computed — cached, never persisted)
// Write — fires change events
user.attrs.firstName = 'Bob'; // triggers 'change:firstName' and 'change:fullName'
user.set('active', true); // triggers 'change:active'
// React to changes
user.on('change:fullName', (model, value) => {
console.log('Name is now', value);
});
// Store-style subscription (returns unsubscribe function)
const unsub = user.subscribe((model, changed) => {
console.log('Changed attrs:', changed);
});
unsub(); // clean up
收藏
import { Model, Collection } from '@converse/skeletor';
class User extends Model {}
class Users extends Collection {
get model() {
return User;
}
get url() {
return '/api/users';
}
}
const users = new Users([
{ id: 1, name: 'Alice', active: true },
{ id: 2, name: 'Bob', active: false },
]);
users.add({ id: 3, name: 'Carol', active: true });
const active = users.filter((u) => u.get('active'));
const names = users.pluck('name'); // → ['Alice', 'Bob', 'Carol']
// Subscribe to structural changes (fires once per operation, not per model)
const unsub = users.subscribe((collection) => {
console.log('collection changed, length:', collection.length);
});
// Load from the server
await users.fetch();
地方持久性
Skeletor可以坚持模式和收藏到索引DB,localStorage,SessionStorage,或SQLite(Node.js),没有额外的软件包.
人工持久性
传统的 Backbone 风格 API: 设置存储一次, 调用 save()编号 :fetch() 当然.
import { Model, PersistentStorage } from '@converse/skeletor';
class Settings extends Model {
initialize() {
this.storage = new PersistentStorage('app-settings', 'local');
}
}
const settings = new Settings({ id: 'main' });
await settings.fetch(); // load from localStorage
settings.set('theme', 'dark');
await settings.save(); // write to localStorage
自动持久性( O)autoSync(中文(简体) )
选入一次, 然后每个字会自动持续—— 不 save() 需要打电话.
import { Model, PersistentStorage } from '@converse/skeletor';
class Settings extends Model {
get autoSync() {
return true;
}
initialize() {
this.storage = new PersistentStorage('app-settings', 'local');
}
}
const settings = new Settings({ id: 'main' });
await settings.hydrated; // resolves when prior data has been loaded
settings.attrs.theme = 'dark'; // persisted automatically (debounced)
settings.set('lang', 'en'); // also auto-saved
// Pass { noAutoSave: true } to suppress persistence for a specific set() call
settings.set('transient', true, { noAutoSave: true });
待决写作被解禁(参见 autoSyncDelay时冲出
页面被隐藏( e)visibilitychange)或已卸下(pagehide) (中文(简体) ).
何时 autoSync 关闭, hydrated 实值 undefined不过 await model.hydrated 还是安全的
(等待时间) undefined 代码可以统一等待.
在一个 Collection, (中文(简体) ), autoSync 实值 仅水合物: 收藏装入存储的
状态,但不能自动保存 add编号 :remove编号 :reset继续
内容,启用 autoSync 在包含的模型类上——每个模型然后
写自己的记录.
支持的后端 : 'local' (当地施放), 'session' (会议集), 'indexed' (数据库), 'memory', (中文(简体) ), 'node' (SQLite,节点22+).
[注] 卸货时的可涂性是最佳的,不能保证. 冲一冲
visibilitychange编号 :pagehide是同步的,但基础写可能不是:
- 与 同步 后端( e)
'local', (中文(简体) ),'session') 冲洗完成之前 所以最后的写作是安全的.- 与 一个同步 后端( e)
'indexed'只有冲浪 开始 书写 浏览器可以在索引DB交易发生前关闭页面,损失最多 最近取消的更改。 浏览器不会给出原始的等待写入 卸下,所以这是内在的而不是虫子.
visibilitychange → hidden火更早,更可靠 比pagehide(特别是在手机上,背景标签在无pagehide),所以这个 是真正的保存点。 将损失窗口进一步缩放, 降低后端autoSyncDelay如果写作永远不能丢失,请打电话await model.save()明确 而不是依赖卸货冲出.
活动
import { EventEmitter } from '@converse/skeletor';
class Store extends EventEmitter {}
const store = new Store();
store.on('update', (data) => console.log('Updated:', data));
store.trigger('update', { key: 'value' });
// Listen to another object's events (auto-cleaned up with stopListening)
const view = new EventEmitter();
view.listenTo(store, 'update', (data) => console.log('View saw:', data));
view.stopListening(); // removes all listeners set up via listenTo
// subscribe() returns an unsubscribe function
const unsub = store.subscribe('update', (data) => console.log(data));
unsub();
与反应合并
subscribe() 与 React 直接兼容 useSyncExternalStore数字 :
import { useSyncExternalStore } from 'react';
function UserName({ user }) {
const attrs = useSyncExternalStore(
(cb) => user.subscribe(cb), // subscribe — returns unsub
() => user.toJSON() // getSnapshot
);
return <span>{attrs.firstName}</span>;
}
图片的特征
| 导出 | 它提供的东西 |
|---|---|
Model | get编号 :set, (中文(简体) ), attrs 代理, computed 属性、 更改跟踪、 验证、 服务器同步 |
Collection | 完整阵列 API 外加 where, (中文(简体) ), findWhere, (中文(简体) ), pluck, (中文(简体) ), groupBy, (中文(简体) ), keyBy, (中文(简体) ), countBy, (中文(简体) ), sortBy |
EventEmitter | on编号 :off编号 :trigger编号 :once, (中文(简体) ), listenTo编号 :stopListening, (中文(简体) ), subscribe() 返回未订阅的函数 |
PersistentStorage | IndexedDB, localStorage, sessionStorage, SQLite (节点), 和内元后端. autoSync 用于透明自救和自水合物. |
sync | 基于 HTTP 的低级获取功能( 自定义传输的覆盖) |
设计哲学
骨骼师是一个 无头数据层,而不是应用程序状态框架。 是属于你的 域模型 (型号)
以及收藏、它们之间的关系、持久性和服务器同步),并远离您的视图层.
把它绑在什么 让你的UI: 升反应(通过) useSyncExternalStore),或平地DOM.
这一范围是深思熟虑的。 Skeletor没有试图与信号库,Zustand,或Redux竞争一般UI状态. 它的特长是给一个真实的,长寿的应用程序 类型、持久性、可承诺性 数据层 可采用 递增 (以上所有现有的Backbone代码库,无法负担重写).
由此产生的原则:
- 渐入大爆炸. 每个特性都是选择入和倒相兼容的.
通过
attrs, (中文(简体) ),computed, (中文(简体) ),subscribe,或autoSync一个模型或一个呼叫站点一次;没有什么迫使迁移. - 承诺能力,召回兼容. Async 操作返回承诺, 而 Backbone 风格
success编号 :error调用和事件继续工作. 新代码可以await旧代码不会破解. - 遗传,不要重复.
computed用缓存和自动变化事件表达一次衍生值. - 无头和框架不可知论. 没有视图,没有路由器,没有框架假设. 反应表面是
change活动及subscribe()。 。 。 . - 诚实的权衡. 无法作出保证的地方(例如,在页面卸载时保持同步) 书中说得很清楚 而不是暗示不存在的耐久性(见下面的注释) 地方持久性) (中文(简体) ).
什么时候用
- 你正在更新Backbone时代的应用程序 想要一个没有重写 的、可承诺的数据层.
- 您想要一个无头存储, 内置的持久性, 绑定在任何UI框架上 .
- 你的状态是真的 域数据 ——具有身份,关系和持续生命周期的实体.
什么时候才能找到别的东西
- 你想要反应,自动跟踪依赖性并更新单个绑定——这就是信号给你的.
骨架通知每个属性(
change:foo)),但你将每个反应自己电线接通,它会在组件颗粒分解时重新发回. - 您的"状态"大多是平面视图状态(形式输入,切换,徘徊)——保留在您的视图层中.
- 你需要时间旅行,结构共享,或者一个严格的不可改变的单层建筑——这就是Redux的地盘.
方向
骨骼器正在从内部而不是被取而代之地现代化。 轨迹是 承诺第一核心 事件和召回作为兼容性shim和反应模型 连接到信号. 目的是让消费者永远不会面临移民。 图书馆在它们下面进行现代化改造 而公众表面保持稳定, 而今天存在的 Backbone 兼容性 并没有牺牲到那里.
从后骨移走
如果您已有 Backbone 工程, 您可以递增迁移数据层 :
- 安装骨骼 :
npm install @converse/skeletor - 替换
import Backbone from 'backbone'带有名称的进口:import { Model, Collection } from '@converse/skeletor' - 替换
Backbone.Model.extend({...})与class MyModel extends Model { ... } - 修复下面列出的少数被移除或重新命名的方法
- 继续使用 Backbone 查看、路由器和历史——它们不受影响
你的观点和路由器根本不需要改变 骨骼模型和收藏会发出同样的事件 Backbone 做的.
从 Backbone 更改
现代化
- 在 TypeScript 有完整类型定义的重写
- 取消了对 j 查询的依赖
- 已替换 下划线 与 摇篮,用于刮树的单项进口
- 尽可能使用本地浏览器 API 而不是 lodash
- 放弃对旧浏览器(包括 IE )的支持; 需要 ES6+
- 各类
Model, (中文(简体) ),Collection)是ES6类——使用class extends改为.extend() - 添加数
EventEmitter混合类(取代旧的)Events构造函数) - Async 操作返回承诺
- CJS同时提供无害环境管理
attrs直接反应属性访问的代理computed带有缓存和自动更改事件的属性subscribe()返回所有被动对象上的未订阅函数
被移除的东西
View财务报告和审定财务报表ElementView——单独管理您的用户界面Router财务报告和审定财务报表History——使用浏览器的历史 API 或专用路由器库.extend()静态方法——使用class MyModel extends Model换成clone()模型——使用new MyModel(model.toJSON())换成chain()财务报告和审定财务报表escape()模型inject, (中文(简体) ),foldl, (中文(简体) ),foldr关于收藏-使用reduce换成sample, (中文(简体) ),take, (中文(简体) ),tail, (中文(简体) ),initial收藏时without, (中文(简体) ),reject, (中文(简体) ),select关于收藏-使用filter换成partition财务报告和审定财务报表invokeMap收藏时
方法重命名( 分数 ~ Lodash)
| 旧( 低于) | 新建( 洛达什) |
|---|---|
rest | drop |
indexBy | keyBy |
invoke | invokeMap (当时已去除-使用) map(中文(简体) ) |
contains | includes |
其他行为变化
Collection.prototype.forEach不再返回过时的项目。 使用map换句话说.Model.prototype.set返回时null(无)false当验证失败时.Collection.prototype.create返回时null(无)boolean关于失败.
