Appearance
富文本编辑器
qxs-blocksuite-editor 是基于 BlockSuite PageEditor 封装的 Web Component 富文本编辑器,支持常显顶部工具栏、Slash 命令、图片上传、Markdown 输入输出和结构化内容事件。
富文本编辑器接入
这页先解决“编辑器怎么接起来”,再去区分工具栏模式、内容格式、图片上传和预览态。
先跑通一个完整 demo,会比先看字段更容易理解 content、content-format、content-update 和 preview 的关系。
loading
基础用法
ts
import '@qxs-bns/components/editor'使用说明
什么时候选 header,什么时候选 slash
toolbar-mode="header" 更适合后台表单、题目描述等固定编辑区域;toolbar-mode="slash" 更接近 Notion 式输入体验,适合正文创作。
Vue 宿主里的对象、数组、函数和布尔值
像 toolbar、header-toolbar-labels、upload-image、readonly、preview、use-model、deserialize-content 这类字段,Vue 里建议使用 .prop 透传。
例如 :toolbar.prop="toolbar"、:header-toolbar-labels.prop="headerToolbarLabels"、:preview.prop="true"、:upload-image.prop="uploadFn"。
content 和 model-value 的关系
默认使用 content 作为内容输入。
如果你希望走 v-model 风格的 model-value,需要同时开启 use-model。
常见场景
最小接入
html
<script type="module">
import '@qxs-bns/components/editor'
</script>
<qxs-blocksuite-editor content="<p>初始内容</p>"></qxs-blocksuite-editor>显式切换到 Slash 模式
html
<qxs-blocksuite-editor
toolbar-mode="slash"
content="<p>输入 / 唤出快捷命令</p>"
></qxs-blocksuite-editor>直接以 Markdown 作为宿主内容格式
html
<qxs-blocksuite-editor
toolbar-mode="slash"
toolbar-preset="simple"
content-format="markdown"
content="## 标题\n\n- 第一项\n- 第二项"
></qxs-blocksuite-editor>Header 工具栏默认常显,并可按需覆盖按钮文案
vue
<script setup lang="ts">
const toolbar = ['table', 'list', 'link', 'format', 'image']
const headerToolbarLabels = {
image: '插入图片',
link: '插入链接',
}
</script>
<template>
<qxs-blocksuite-editor
:toolbar.prop="toolbar"
:header-toolbar-labels.prop="headerToolbarLabels"
/>
</template>toolbar 现在不仅控制显示哪些工具项,也会直接决定这些工具项在 header / slash 工具栏中的渲染顺序。
例如上面的配置会把 表格 -> 列表 -> 链接 -> 格式组 -> 图片 排到前面,并把图片按钮固定到最后。
如果你希望回退成“聚焦后再展示 header”,可以显式传入 :header-always-visible.prop="false"。
自定义图片上传
vue
<script setup lang="ts">
const uploadImage = async (file: File) => {
const formData = new FormData()
formData.append('file', file)
const res = await fetch('/api/upload', {
method: 'POST',
body: formData,
})
const data = await res.json()
return data.url
}
</script>
<template>
<qxs-blocksuite-editor :upload-image.prop="uploadImage" />
</template>API
属性
| Name | Description | Type | Default |
|---|---|---|---|
content | 编辑器 HTML 内容 | string | '' |
model-value | 搭配 use-model 使用的内容值 | string | '' |
placeholder | 占位文案 | string | '输入内容' |
toolbar-mode | 工具栏模式 | 'header' | 'slash' | 'header' |
toolbar-preset | 内置工具栏预设;未传 toolbar 时生效 | 'full' | 'simple' | 'none' | 'full' |
header-toolbar-labels | 仅在 header 模式下生效的按钮文案映射;支持对象或 JSON 字符串 | Partial<Record<'bold' | 'italic' | 'underline' | 'strike' | 'code' | 'link' | 'image' | 'bulletList' | 'orderedList' | 'taskList' | 'blockquote' | 'table', string>> | string | { image: '插入图片', link: '插入链接' } |
header-always-visible | 是否始终显示顶部工具栏 | boolean | true |
use-model | 是否改用 model-value 作为内容输入源 | boolean | false |
readonly | 只读模式 | boolean | false |
preview | 预览模式,隐藏边框和编辑工具栏 | boolean | false |
editable | 显式控制是否可编辑,优先级高于 readonly | boolean | null |
min-height | 编辑区最小高度 | string | '80px' |
max-height | 编辑区最大高度;传入后内容区自动滚动 | string | '' |
show-character-count | 是否展示字符统计 | boolean | false |
toolbar-position | 顶部工具栏显示在上方还是下方 | 'top' | 'bottom' | 'top' |
custom-styles | 注入到 Shadow DOM 的额外样式文本 | string | '' |
content-format | 宿主内容格式;未传转换函数时决定内置序列化行为 | 'html' | 'markdown' | 'custom' | 'html' |
deserialize-content | 自定义输入转换函数,优先级高于 content-format | (value: string) => string | - |
serialize-content | 自定义输出转换函数,优先级高于 content-format | (value: string) => string | - |
upload-image | 自定义图片上传函数,返回最终图片 URL | (file: File) => Promise<string> | base64 |
事件
| Name | Description | Type |
|---|---|---|
content-update | 推荐使用的结构化内容事件,返回 { value, html, text, format } | (snapshot: ContentSnapshot) => void |
content-change | 兼容事件,仅返回宿主格式下的 value 字符串 | (value: string) => void |
image-upload-error | 图片上传失败时触发,返回 { file, error } | (detail: { file: File; error: Error }) => void |
方法
| Name | Description | Type |
|---|---|---|
getContent() | 获取当前宿主格式下的内容字符串 | () => string |
getContentSnapshot() | 获取结构化内容快照 { value, html, text, format } | () => ContentSnapshot |
常见问题
preview 和 readonly 有什么区别?
readonly仍保留编辑器外观,但不可编辑。preview会进一步关闭编辑器边框和工具栏,更适合最终展示。
我应该监听 content-change 还是 content-update?
新接入建议优先监听 content-update。
它会同时给出:
value: 当前宿主格式的值html: 编辑器内部 HTMLtext: 纯文本format: 当前内容格式
content-change 仍然保留,用来兼容旧代码。