Appearance
Vue 集成
@axewo/fin-editor 提供 Vue 3 组件和组合式函数,将编辑器核心绑定到 Vue 的响应式系统。
FinEditor
主编辑器组件,开箱即用。
基础用法
loading
loading
vue
<script setup lang="ts">
import { ref } from 'vue'
import { FinEditor } from '@axewo/fin-editor'
import '@axewo/fin-editor/index.scss'
const content = ref('<p>Hello World</p>')
</script>
<template>
<fin-editor v-model="content" />
</template>Props
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
modelValue | string | '' | 编辑器内容(v-model) |
config | EditorConfig | {} | 编辑器配置 |
mode | 'edit' | 'view' | 'edit' | 编辑模式 |
theme | 'light' | 'dark' | 'auto' | 'light' | 主题 |
locale | 'zh-CN' | 'en-US' | 'zh-CN' | 国际化语言 |
showToolbar | boolean | true | 显示工具栏 |
showLabels | boolean | false | 工具栏显示文字标签 |
showStatusBar | boolean | true | 显示状态栏 |
showWordCount | boolean | true | 状态栏显示字数 |
showFullscreenBtn | boolean | true | 显示全屏按钮 |
showBubble | boolean | true | 显示选中气泡菜单 |
bodyHeight | string | number | — | 编辑器主体高度 |
loading
Events
| 事件 | 参数 | 说明 |
|---|---|---|
update:modelValue | content: string | 内容变化(v-model 更新) |
save | content: string | 手动保存(Ctrl+S) |
ready | editor: EditorInstance | 编辑器初始化完成 |
mode-change | mode: EditorMode | 模式切换 |
loading
Expose API
通过 ref 可访问以下方法(defineExpose):
vue
<script setup lang="ts">
import { ref } from 'vue'
const editorRef = ref<InstanceType<typeof FinEditor>>()
function handleGetContent() {
const html = editorRef.value?.getContent()
console.log(html)
}
</script>
<template>
<fin-editor ref="editorRef" v-model="content" />
</template>暴露的方法:
| 方法 | 返回值 | 说明 |
|---|---|---|
getEditor() | EditorInstance | null | 获取编辑器核心实例 |
getHTML() | string | 获取 HTML 内容 |
getContent() | string | 获取 HTML 内容(getHTML 别名) |
getText() | string | 获取纯文本内容(不含 HTML 标签) |
getJSON() | Record<string, any> | 获取 JSON 格式内容 |
setContent(content) | void | 设置内容 |
executeCommand(name, ...args) | any | 执行命令 |
isCommandActive(name) | boolean | 检查命令状态 |
完整示例
vue
<script setup lang="ts">
import { ref } from 'vue'
import { FinEditor } from '@axewo/fin-editor'
import '@axewo/fin-editor/index.scss'
const content = ref('')
const editorRef = ref()
const isViewMode = ref(false)
const showLabels = ref(false)
function handleReady(editor) {
console.log('编辑器就绪', editor)
}
function handleSave(html) {
console.log('保存内容:', html)
}
function toggleMode() {
isViewMode.value = !isViewMode.value
}
function insertHello() {
editorRef.value?.executeCommand('toggleBold')
}
</script>
<template>
<div class="editor-container">
<!-- 工具栏外部控制 -->
<div class="custom-controls">
<button @click="toggleMode">
{{ isViewMode ? '编辑' : '只读' }}
</button>
<button @click="insertHello">加粗</button>
<label>
<input v-model="showLabels" type="checkbox" />
显示工具栏标签
</label>
</div>
<fin-editor
ref="editorRef"
v-model="content"
:mode="isViewMode ? 'view' : 'edit'"
:show-labels="showLabels"
body-height="400px"
@ready="handleReady"
@save="handleSave"
/>
</div>
</template>BubbleMenu
文本选中时的浮动工具栏,提供加粗/斜体/下划线/删除线等快捷操作。
Props
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
editor | EditorInstance | null | — | 编辑器核心实例 |
items | string[] | ['bold', 'italic', 'underline', 'strike', 'link'] | 要显示的工具栏项 ID |
showLabels | boolean | false | 是否显示标签文字 |
用法
vue
<script setup lang="ts">
import { BubbleMenu } from '@axewo/fin-editor'
</script>
<template>
<bubble-menu
:editor="editorInstance"
:items="['bold', 'italic', 'underline']"
:show-labels="false"
/>
</template>BubbleMenu 由 FinEditor 内部管理,一般不需要单独使用。通过 showBubble prop 控制即可。
loading
useEditor
无 UI 渲染的组合式函数,适合需要完全自定义 UI 的场景。
用法
vue
<script setup lang="ts">
import { ref, shallowRef } from 'vue'
import { useEditor } from '@axewo/fin-editor'
const elementRef = ref<HTMLElement>()
const modelValue = ref('<p>Custom UI</p>')
const { editor, isReady, content } = useEditor({
element: elementRef,
modelValue,
})
function doCommand(cmd: string) {
if (!editor.value) return
editor.value.executeCommand(cmd)
}
</script>
<template>
<div class="my-editor">
<!-- 自定义工具栏 -->
<div class="my-toolbar" v-if="isReady">
<button @click="doCommand('toggleBold')">B</button>
<button @click="doCommand('toggleItalic')">I</button>
<button @click="doCommand('toggleUnderline')">U</button>
</div>
<!-- 编辑器内容区域 -->
<div ref="elementRef" class="my-content" />
</div>
</template>Options
| 属性 | 类型 | 说明 |
|---|---|---|
element | Ref<HTMLElement | undefined> | 编辑器挂载的 DOM 元素(template ref) |
modelValue | Ref<string> | 双向绑定的内容 |
config | Partial<EditorConfig> | 编辑器配置 |
mode | Ref<EditorMode> | 编辑模式 |
theme | Ref<EditorTheme> | 主题 |
locale | Ref<EditorLocale> | 国际化语言 |
Return
| 属性 | 类型 | 说明 |
|---|---|---|
editor | ShallowRef<EditorInstance | null> | 编辑器核心实例(浅响应) |
isReady | Ref<boolean> | 编辑器是否就绪 |
content | Ref<string> | 当前内容(HTML) |
mode | Ref<EditorMode> | 当前编辑模式 |
theme | Ref<EditorTheme> | 当前主题 |
locale | Ref<EditorLocale> | 当前语言 |
国际化
编辑器内置 zh-CN(中文)和 en-US(英文)两种语言,默认中文。
vue
<template>
<fin-editor v-model="content" locale="en-US" />
</template>支持动态切换语言:
vue
<script setup lang="ts">
import { ref } from 'vue'
import type { EditorLocale } from '@axewo/fin-editor'
const locale = ref<EditorLocale>('zh-CN')
</script>
<template>
<el-select v-model="locale">
<el-option label="中文" value="zh-CN" />
<el-option label="English" value="en-US" />
</el-select>
<fin-editor v-model="content" :locale="locale" />
</template>国际化覆盖范围:工具栏按钮 tooltip、对话框标题与按钮、图片/链接编辑弹窗、状态栏文字。
撤销 / 重做
CoreExtension 内置 History 扩展,开箱即用:
| 快捷键 | 功能 |
|---|---|
Ctrl+Z | 撤销 |
Ctrl+Shift+Z | 重做 |
Ctrl+Y | 重做 |
工具栏也有撤销/重做按钮,当没有可撤销/重做的操作时自动禁用。
图片编辑
插入的图片支持:
- 拖拽调整大小:点击图片选中后,拖拽右下角/左下角圆点调整宽度
- 编辑属性:选中图片后点击编辑按钮,可修改 Alt 文本、宽度和高度
- 拖拽/粘贴上传:直接拖拽图片文件到编辑器或从剪贴板粘贴
vue
<script setup lang="ts">
import { ref } from 'vue'
const content = ref(`
<p>选中下方图片可调整大小和编辑属性:</p>
<img src="https://picsum.photos/600/300" alt="示例图片" width="100%" />
`)
</script>
<template>
<fin-editor v-model="content" />
</template>链接
选中文本后可添加超链接,链接文字自动变色为主题色并带下划线。
| 快捷键 | 功能 |
|---|---|
Ctrl+K | 插入/编辑链接 |
链接操作:
- 插入链接:选中文本 → 点击工具栏链接按钮或
Ctrl+K→ 输入 URL - 编辑链接:光标置于已有链接上 →
Ctrl+K→ 修改 URL - 取消链接:在链接编辑弹窗中点击"移除"按钮
BubbleMenu 中也集成了链接按钮,选中文本后可直接操作。
纯文本内容
除了 getContent()(返回 HTML),还提供 getText() 获取纯文本:
vue
<script setup lang="ts">
import { ref } from 'vue'
import { FinEditor } from '@axewo/fin-editor'
const editorRef = ref()
const plainText = ref('')
function showPlainText() {
plainText.value = editorRef.value?.getText() || ''
}
</script>
<template>
<fin-editor ref="editorRef" v-model="content" />
<button @click="showPlainText">获取纯文本</button>
<pre>{{ plainText }}</pre>
</template>主题定制
使用内置主题
vue
<fin-editor v-model="content" theme="dark" />
<!-- 可选值:'light' | 'dark' | 'auto' -->自定义 SCSS 变量
scss
// 覆盖 CSS 变量
.fin-editor {
--fin-editor-bg: #f5f5f5;
--fin-editor-border: #e0e0e0;
--fin-editor-toolbar-bg: #ffffff;
--fin-editor-content-min-height: 300px;
--fin-editor-radius: 8px;
--fin-editor-font-size: 15px;
--fin-editor-line-height: 1.8;
}暗色主题变量
暗色主题通过 .fin-editor--dark 类名下的 CSS 变量覆盖实现:
scss
.fin-editor--dark {
--fin-editor-bg: #1e1e1e;
--fin-editor-border: #333;
--fin-editor-toolbar-bg: #252525;
--fin-editor-text: #d4d4d4;
}注册默认扩展
@axewo/fin-editor 导出了一个 registerDefaults 便捷函数,等价于 FinEditor 内部注册的默认扩展集:
ts
import { registerDefaults } from '@axewo/fin-editor'
import { EditorInstance } from '@axewo/fin-editor'
const editor = new EditorInstance({ ... })
registerDefaults(editor)
// = editor.use(CoreExtension) // Document/Paragraph/Text + History (undo/redo)
// .use(TextStyleExtension) // Bold/Italic/Underline/Strike/Color/Highlight
// .use(ParagraphExtension) // Heading/Align/Lists/Blockquote/HR
// .use(LinkExtension) // Link mark with colored text
// .use(createImageExtension()) // Image node with resize + alt
// .use(CodeBlockExtension) // Code block with syntax highlighting依赖关系
@axewo/fin-editor
├── vue (peer)
├── element-plus (peer, 工具栏 UI)
├── @element-plus/icons-vue (peer)
├── @tiptap/vue-3 (peer)
├── @axewo/fin-editor (dep)
├── @axewo/fin-editor (dep)
└── @axewo/fin-editor (peer, 用户自行导入 SCSS)