# @converse/skeletor 中文文档

规范地址：https://npmcn.com/package/%40converse/skeletor/

版本：4\.0\.2
npm 元数据更新时间：2026-11-05T06:14:32.567Z
中文译文更新时间：2026-11-10T19:25:42.732Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40converse/skeletor
原文对照：https://npmcn.com/package/%40converse/skeletor/?lang=original
项目主页：https://github.com/conversejs/skeletor#readme
源码仓库：https://github.com/conversejs/skeletor

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：3.3 MB，29 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- Node.js 要求：\>=22\.0\.0
- 运行依赖：9 个
- 首次发布：2020-06-08T16:10:58.190Z
- 最新版本发布：2026-11-05T06:14:32.396Z
- 近 30 天下载量：3324（2026-10-11 至 2026-11-09，npm 官方下载统计）
- 已发布版本数：23（近 12 个月 14 个）

## 中文简介

现代网络应用的模型和收藏

## 安装

```sh
npm install @converse/skeletor
```

也可以使用：`pnpm add @converse/skeletor`、`yarn add @converse/skeletor`、`bun add @converse/skeletor`

## README

![Skeletor](https://npmcn.com/package/%40converse/skeletor/images/skeletor-logo.svg)

# 骨头

[![XMPP Chat](https://conference.conversejs.org/muc_badge/discuss@conference.conversejs.org)](https://chat.conversejs.org/#converse/room?jid=discuss@conference.conversejs.org) [![CI Tests](https://github.com/conversejs/skeletor/actions/workflows/karma-tests.yml/badge.svg)](https://github.com/conversejs/skeletor/actions/workflows/karma-tests.yml)

Skeletor是一个轻量级,TypeScript-first反应数据库.

它允许您定义打入的模型,并用事件或订阅来响应变化, 同时坚持索引数据库、本地Storage、会话Storage、SQLite(节点)或REST API.

骨骼器是一种现代化的重写 [后骨](http://backbonejs.org/)模式和收藏, 没有jQuery, 没有突触, 也没有查看或运行。 如果你知道Backbone的一切的话 直接转让。 不取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取出.

骨骼力量 [交锋.js](https://conversejs.org/),一个全功能的开源XMPP聊天客户端.

## 为什么是骨骼?

-   **反应模型** ——设定属性,获得属性 `change` 活动。 使用回调和未订阅功能订阅 。 在任何UI层工作.
-   **直接属性访问** —— 说 `model.attrs.name = 'Bob'` 火灾改变事件,不需要锅炉板.
-   **计算属性** ——声明有明确依赖关系的衍生值;它们缓存、重新计算和起火 `change` 自动事件.
-   **存储式订阅** —— 说 `subscribe()` 返回未订阅的函数,与 React 兼容 `useSyncExternalStore` 和类似的API.
-   **内建的持久性** ——索引DB, localStorage, sessionStorage, SQLite (Node), 和 REST 退出框.
-   **类型脚本第一** ——完整类型定义,通用模型属性,被打入计算属性.
-   **没有 j 查询, 没有强调** ——本地浏览器 API 和 [摇篮](https://lodash.com/) 单项进口用于震动树木.
-   **到处都行** ——浏览器,Node.js(22+),Web Workers. 包括无害环境管理+CJS.
-   **与后骨兼容** —— 说 `get`, (中文(简体) ), `set`,事件,收藏:都在那里. Backbone数据层的倒置替换.

## 安装

```
npm install @converse/skeletor
```

## 快速启动

### 型号

```ts
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
```

### 收藏

```ts
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()` 当然.

```ts
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()` 需要打电话.

```ts
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()` 明确 而不是依赖卸货冲出.

### 活动

```ts
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`数字 :

```ts
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: [升](https://lit.dev/)反应(通过) [`useSyncExternalStore`](https://npmcn.com/package/%40converse/skeletor/#readme-integration-with-react)),或平地DOM.

这一范围是深思熟虑的。 Skeletor没有试图与信号库,Zustand,或Redux竞争一般UI状态. 它的特长是给一个真实的,长寿的应用程序 _类型、持久性、可承诺性_ 数据层 可采用 **递增** (以上所有现有的Backbone代码库,无法负担重写).

由此产生的原则:

-   **渐入大爆炸.** 每个特性都是选择入和倒相兼容的. 通过 `attrs`, (中文(简体) ), `computed`, (中文(简体) ), `subscribe`,或 `autoSync` 一个模型或一个呼叫站点一次;没有什么迫使迁移.
-   **承诺能力,召回兼容.** Async 操作返回承诺, 而 Backbone 风格 `success`编号 :`error` 调用和事件继续工作. 新代码可以 `await`旧代码不会破解.
-   **遗传,不要重复.** `computed` 用缓存和自动变化事件表达一次衍生值.
-   **无头和框架不可知论.** 没有视图,没有路由器,没有框架假设. 反应表面是 `change` 活动及 `subscribe()`。 。 。 .
-   **诚实的权衡.** 无法作出保证的地方(例如,在页面卸载时保持同步) 书中说得很清楚 而不是暗示不存在的耐久性(见下面的注释) [地方持久性](https://npmcn.com/package/%40converse/skeletor/#readme-local-persistence)) (中文(简体) ).

### 什么时候用

-   你正在更新Backbone时代的应用程序 想要一个没有重写 的、可承诺的数据层.
-   您想要一个无头存储, 内置的持久性, 绑定在任何UI框架上 .
-   你的状态是真的 _域数据_ ——具有身份,关系和持续生命周期的实体.

### 什么时候才能找到别的东西

-   你想要反应,自动跟踪依赖性并更新单个绑定——这就是信号给你的. 骨架通知每个属性(`change:foo`)),但你将每个反应自己电线接通,它会在组件颗粒分解时重新发回.
-   您的"状态"大多是平面视图状态(形式输入,切换,徘徊)——保留在您的视图层中.
-   你需要时间旅行,结构共享,或者一个严格的不可改变的单层建筑——这就是Redux的地盘.

### 方向

骨骼器正在从内部而不是被取而代之地现代化。 轨迹是 **承诺第一核心 事件和召回作为兼容性shim**和反应模型 连接到信号. 目的是让消费者永远不会面临移民。 图书馆在它们下面进行现代化改造 而公众表面保持稳定, 而今天存在的 Backbone 兼容性 并没有牺牲到那里.

## 从后骨移走

如果您已有 Backbone 工程, 您可以递增迁移数据层 :

1.  安装骨骼 : `npm install @converse/skeletor`
2.  替换 `import Backbone from 'backbone'` 带有名称的进口: `import { Model, Collection } from '@converse/skeletor'`
3.  替换 `Backbone.Model.extend({...})` 与 `class MyModel extends Model { ... }`
4.  修复下面列出的少数被移除或重新命名的方法
5.  继续使用 Backbone 查看、路由器和历史——它们不受影响

你的观点和路由器根本不需要改变 骨骼模型和收藏会发出同样的事件 Backbone 做的.

## 从 Backbone 更改

### 现代化

-   在 TypeScript 有完整类型定义的重写
-   取消了对 j 查询的依赖
-   已替换 [下划线](http://underscorejs.org/) 与 [摇篮](https://lodash.com/),用于刮树的单项进口
-   尽可能使用本地浏览器 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`关于失败.

* * *

![](https://raw.githubusercontent.com/conversejs/skeletor/master/images/skeletor2.jpg)

## 常见问题

### @converse/skeletor 是什么？

现代网络应用的模型和收藏

### 如何安装 @converse/skeletor？

在项目目录运行 npm install @converse/skeletor，或使用 pnpm add / yarn add / bun add。

### @converse/skeletor 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @converse/skeletor 支持 ESM 还是 CommonJS？

同时提供 ES Module 与 CommonJS 入口，import 和 require\(\) 都可以使用，打包工具会自动选择合适的版本。

### @converse/skeletor 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=22\.0\.0。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @converse/skeletor 可以商用吗？

@converse/skeletor 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @converse/skeletor 的下载量有多少？

根据 npm 官方下载统计，@converse/skeletor 在 2026/10/11 – 2026/11/09 这 30 天内被下载 3,324 次，日均约 111 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @converse/skeletor 还在维护吗？

最新版本 4\.0\.2 发布于 2026/11/05（5 天前）；至今共发布 23 个版本，其中过去 12 个月发布了 14 个；首次发布于 2020/06/09。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

