npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@bireturn/word-editor

v1.0.14

Published

类 Word 的 Web 富文本编辑器,基于canvas-editor的数据结构渲染

Downloads

2,158

Readme

@bireturn/word-editor

类 Word 的 Web 富文本编辑器,目前只实现了只读渲染功能,基于 Vue 3 + Vite + TypeScript。参考 canvas-editor 的数据结构与命令系统设计,但使用 DOM 渲染代替 Canvas,并通过虚拟滚动支撑大文档。

安装

npm install @bireturn/word-editor

需宿主项目提供 vue ^3.4(已声明为 peerDependency,避免重复打包与多实例)。

使用

数据由使用方通过 props 传入,组件本身不发请求:

<script setup>
import { EditorContainer } from '@bireturn/word-editor'
import '@bireturn/word-editor/style.css'   // 必须引入样式
import { ref, onMounted } from 'vue'

const docData = ref([])   // IElement[],来源由使用方决定
const loading = ref(false)

onMounted(async () => {
  loading.value = true
  docData.value = await fetchDoc()   // 使用方自己的数据源
  loading.value = false
})
</script>

<template>
  <EditorContainer :data="docData" :loading="loading" />
</template>

也可通过 app.use() 全局注册:

import WordEditor from '@bireturn/word-editor'
import '@bireturn/word-editor/style.css'

app.use(WordEditor)   // 注册全局组件 <EditorContainer />

Props

| 名称 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | data | IElement[] | [] | 文档结构数据,渲染所需的行内元素列表 | | loading | boolean | false | 外部数据加载态,为 true 时显示加载占位 |

特性

  • 数据驱动渲染:文档数据模型是唯一数据源,DOM 仅作视图
  • 命令系统(Command Pattern):所有写操作经 editor.exec() 分发,统一支持撤销/重做
  • 虚拟滚动:以段落为最小单元,配合自研 VirtualTable 支撑大文档
  • A4 分页排版:按页面内容高度自动分页,支持页眉/页脚、连续图片与表格跨页拆分
  • 富内容:文本、图片、超链接、表格、控件(文本/输入/单选)、上下标、复选框等
  • 插件机制:通过 editor.use() 注入自定义命令与能力

技术栈

| 类别 | 选型 | | --- | --- | | 框架 | Vue 3(Composition API) | | 构建 | Vite 5 + TypeScript 5 | | 状态 | Pinia | | 图标 | lucide-vue-next | | 工具 | @vueuse/core、lodash-es | | 虚拟滚动 | vue-virtual-scroller + 自研 VirtualTable | | Mock | vite-plugin-mock-dev-server |

快速开始

npm install          # 安装依赖
npm run dev          # 启动开发服务器(默认 http://localhost:5173)

开发态接口由 mock/ 提供,可完全离线运行,无需后端。

常用命令

npm run dev          # 启动开发服务器
npm run build        # 构建可部署的应用产物
npm run build:lib    # 构建组件库产物(lib/,含 ESM/UMD + 类型声明)
npm run preview      # 本地预览构建产物
npm run lint         # ESLint 检查并自动修复
npm run type-check   # 仅做 TypeScript 类型检查

构建与本地联调

本项目可同时作为独立应用组件库使用。vite.config.tsmode 区分两种产物:默认模式构建应用,--mode lib(即 npm run build:lib)构建组件库。

构建产物

npm run build:lib

产物输出到 lib/

| 文件 | 说明 | | --- | --- | | word-editor.es.js | ESM 格式,供打包工具按需引入 | | word-editor.umd.js | UMD 格式,供浏览器/旧环境直接引用 | | word-editor.css | 组件样式,需由使用方手动引入 | | index.d.ts | TypeScript 类型声明 |

vue 被声明为 peerDependencies 并在构建时外置,由使用方提供,避免重复打包与多实例问题。

本地联调(不发布到 npm)

构建后,在消费方项目通过本地路径安装,推荐 file: 方式:

// 消费方 package.json
{
  "dependencies": {
    "@bireturn/word-editor": "file:../word-editor"   // 改成实际路径
  }
}
npm install

改动本库后,重跑 npm run build:lib 并重启消费方 dev server 即可生效。也可用 npm pack 生成 .tgz 后安装(更贴近真实发布),或 npm link(改库实时联动)。

⚠️ 若用 file: / npm link 出现 Vue 响应式失效或 inject 报错,通常是加载了两份 Vue。在消费方 vite.config.tsresolve.dedupe: ['vue']optimizeDeps.include: ['@bireturn/word-editor'] 去重即可。

发布到 npm

npm run build:lib        # 先构建产物到 lib/
npm publish --access public   # scoped 包首次发布需加 --access public

lib/ 会随包发布(由 package.jsonfiles 字段约定)。

Mock 数据

开发态接口基于 vite-plugin-mock-dev-server 实现,配置见 mock/api.mock.ts,数据文件存放于 mock/json/,可完全离线运行、无需后端。

接口约定

前端通过 src/api/file.tsgetStructInfo() 请求 /api/info,期望返回文档结构数组 IElement[](即 DocumentModel 渲染所需的行内元素列表)。

mock/api.mock.ts 中有两类挂载方式:

  • 约定式apiList):/api/xxx 自动读取 mock/json/xxx.json,默认延迟 300ms
  • 自定义式customApis):显式指定 url 与数据文件,可单独设置延迟。当前 /api/info 即在此挂载

切换测试数据

修改 customApis/api/info 读取的 json 文件即可切换渲染数据,例如:

const customApis = [
  {
    url: '/api/info',
    delay: 1000,
    body: () =>
      JSON.parse(
        fs.readFileSync(path.resolve(root, `./mock/json/info.json`), 'utf8')
      )
  }
]

数据文件清单

所有文件均为顶层 IElement[] 数组,元素以 type 区分(text / table / image / hyperlink / control / list 等)。

| 文件 | 体积 | 元素数 | 主要内容 | 用途 | | --- | --- | --- | --- | --- | | info.json | ~1.6 MB | 81 | 文本、9 个表格、控件、超链接 | 常规文档,功能演示基线 | | pagetable.json | ~388 KB | 1 | 单个跨页大表格(77 行) | 表格分页与行渲染调试 | | page1000.json | ~32 MB | 84 | 84 个表格 | 大量表格的分页/性能压测 | | page69.json | ~85 MB | 2323 | 文本、198 表格、列表、控件 | 超大文档虚拟滚动压测 | | page69i.json | ~85 MB | 2344 | 在 page69 基础上增加 18 张图片 | 含图片的超大文档压测 |

说明:page69* / page1000 体积较大,仅用于性能与边界场景验证,日常开发建议使用 info.jsonpagetable.json

元素数据结构

type 的字段含义见 docs/0.JSON数据类型说明.mddocs/1.页面样式属性说明.md

核心设计原则

  1. 数据模型是唯一数据源,DOM 只是视图,不存储状态
  2. contenteditable 仅用于输入捕获,不用于渲染(透明 overlay 模式)
  3. 所有写操作必须通过 editor.exec(),不能直接修改 docModel
  4. 大文档通过虚拟滚动实现,段落是虚拟列表的最小单元

目录结构

src/
├── core/                       # 纯 TypeScript,与 Vue 无关
│   ├── editor/Editor.ts        # 编辑器主类,所有子系统的聚合入口
│   ├── model/DocumentModel.ts  # 文档数据模型,所有原子修改方法在此
│   ├── command/                # 命令系统
│   │   ├── CommandManager.ts   # exec() 分发,注册/执行命令
│   │   └── commands/           # InsertText / Delete / Format / InsertParagraph 等
│   ├── selection/SelectionManager.ts  # 模型坐标系的光标/选区
│   ├── history/HistoryManager.ts      # undo/redo 栈
│   └── input/InputHandler.ts   # DOM 事件 → exec() 转换层
├── composables/
│   ├── useEditor.ts            # provide/inject Editor 实例
│   └── useDocumentData.ts      # 从 docModel 提取响应式数据
├── components/
│   ├── Editor/                 # 编辑器根组件(含分页、表格、页眉页脚渲染)
│   └── VirtualTable/           # 自研虚拟表格组件
├── api/                        # 接口请求封装
└── types/                      # 全局类型(document/selection/command/plugin)

mock/                           # vite mock,离线可用的接口数据
docs/                           # 功能说明与问题分析文档

架构

数据流

用户输入(键盘/鼠标)
  → InputHandler(DOM 事件拦截)
  → editor.exec(commandName, payload)
  → CommandManager(查找命令工厂)
  → ICommand.execute()(修改 DocumentModel)
  → Vue 响应式自动触发重渲染
  → 组件根据最新 docModel 渲染 DOM

数据模型

DocumentModel
  └── sections[]          # 节(分页/分栏单位)
        └── paragraphs[]  # 段落(块级,虚拟滚动的最小单元)
              └── children: IElement[]  # 行内元素(文本/图片/超链接/表格等)

坐标系

所有位置用 ModelPoint 表示:

{ sectionIndex, paragraphIndex, elementIndex, offset }

DOM 元素通过 data-si / data-pi / data-ei 属性反向映射回模型坐标(见 SelectionManager.domToModelPoint)。

扩展

注册命令

CommandManager._registerBuiltinCommands() 中注册,或通过插件注入:

editor.commands.register('myCommand', (payload) => new MyCommand(...))

命令须实现 ICommandexecute + undo),可选实现 canMergeWith / merge 以支持连续输入合并。

插件

editor.use({
  name: 'my-plugin',
  install(editor) {
    editor.commands.register('customCommand', ...)
  }
})

新增元素类型

需同时更新:

  • src/types/document.ts(类型定义)
  • src/components/Editor/index.vue(渲染逻辑)

关键约束

  • 禁止在渲染组件中直接修改 docModel
  • 禁止在 InputHandler 中直接修改 docModel(必须通过 exec
  • DocumentModel 的原子方法(insertText / deleteAt 等)只能由 Command 调用

文档

更多功能说明与问题分析见 docs/ 目录。