Vue3: 二次封装富文本编辑器-hook

初衷

基于WangEditor进行了一次特殊处理,使其更加易于使用和灵活。这个编辑器可以让你像写文字一样轻松地编辑富文本内容。不论你是要写一篇精彩的博客文章,还是设计一个华丽的网页,这个编辑器都能满足我们的需求。我使用了"Hook"的机制,可以自由地定制和控制编辑器的各种功能。

其实,主要是方便易用,在不同页面中,如果需要到富文本编辑器,如果这个时候我们把它封装成hook,那么我们就很轻易的复用某些功能点,可以省去很多重新编写逻辑的代码。

接下来我们先从WangEditor的使用文档做一下初步的了解

介绍

简洁易用,功能强大快速接入,配置简单,集成了几乎所有常见功能。在 Vue React 也可以快速接入,只需再做个hook就能更加灵活

如下几步以Vue3使用为例:

第一步:安装

bash 复制代码
yarn add @wangeditor/editor
# 或者 npm install @wangeditor/editor --save

yarn add @wangeditor/editor-for-vue@next
# 或者 npm install @wangeditor/editor-for-vue@next --save

第二步:使用模版

html 复制代码
<template>
    <div style="border: 1px solid #ccc">
      <Toolbar
        style="border-bottom: 1px solid #ccc"
        :editor="editorRef"
        :defaultConfig="toolbarConfig"
        :mode="mode"
      />
      <Editor
        style="height: 500px; overflow-y: hidden;"
        v-model="valueHtml"
        :defaultConfig="editorConfig"
        :mode="mode"
        @onCreated="handleCreated"
      />
    </div>
</template>

第三步:Script

js 复制代码
<script>
import '@wangeditor/editor/dist/css/style.css' // 引入 css

import { onBeforeUnmount, ref, shallowRef, onMounted } from 'vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'

export default {
  components: { Editor, Toolbar },
  setup() {
    // 编辑器实例,必须用 shallowRef
    const editorRef = shallowRef()

    // 内容 HTML
    const valueHtml = ref('<p>hello</p>')

    // 模拟 ajax 异步获取内容
    onMounted(() => {
        setTimeout(() => {
            valueHtml.value = '<p>模拟 Ajax 异步设置内容</p>'
        }, 1500)
    })

    const toolbarConfig = {}
    const editorConfig = { placeholder: '请输入内容...' }

    // 组件销毁时,也及时销毁编辑器
    onBeforeUnmount(() => {
        const editor = editorRef.value
        if (editor == null) return
        editor.destroy()
    })

    const handleCreated = (editor) => {
      editorRef.value = editor // 记录 editor 实例,重要!
    }

    return {
      editorRef,
      valueHtml,
      mode: 'default', // 或 'simple'
      toolbarConfig,
      editorConfig,
      handleCreated
    };
  }
}
</script>

配置

可通过 toolbarConfig 和 editorConfig 来修改菜单栏和编辑器的配置,详细文档参考

封装

依据介绍中的内容,进行二次封装成hook

步骤

封装wangEditor成hook,我是按照以下步骤进行:

1. 创建一个新的Hook组件

创建一个新的组件来封装wangEditor成为一个可复用的hook。你可以使用React的useState和useEffect等hook来管理编辑器的状态和生命周期。

2. 初始化编辑器:

在组件的useEffect钩子中,使用wangEditor的初始化方法来创建编辑器实例,并将其存储在状态中。

3. 添加事件监听:

使用wangEditor提供的方法,为编辑器添加事件监听器。这样可以捕获用户的输入、选择和其他操作。

4. 定义公共方法

在hook组件中定义一些公共方法,例如获取编辑器内容、插入内容等,以便在其他组件中使用。

5. 销毁编辑器:

使用wangEditor提供的销毁方法,在组件的清理函数中销毁编辑器实例,避免内存泄漏。

以上步骤只是一个大致的方案,具体实现可能会根据项目的需求和编辑器的配置有所差异。所以在封装过程中要注意参考wangEditor的官方文档和示例,以确保正确使用和配置编辑器。封装wangEditor成为一个hook后,你可以在其他组件中方便地使用它,简化并提高你的开发效率。

实践

那么我们就开始进行封装了

首先,创建一个editor.ts hook文件

暴露出这几个方法如下:

1.1. 编辑器容器

用于包裹编辑器工具栏和编辑器的容器

1.2. 编辑器实例

ts 复制代码
// 编辑器实例,必须用 shallowRef
  const editorRef = shallowRef();

当编辑器渲染完成之后,通过 editorRef.value 获取 editor 实例,即可调用它的 API

1.3. 工具栏配置

这个配置必不可少

可通过 toolbarConfig 和 editorConfig 来修改菜单栏和编辑器的配置,详细文档参考

那么,我们可以将其作为参数传入hook,便于灵活定制化,如下代码的编写:

创建一个函数,提供额外的参数配置

javascript 复制代码
export default function useEditor(
  options: EditorOptions = {
    config: {},
    toolbarConfig: {},
  },
) 

编写toolbarConfig 和 editorConfig 合并传进参数的方法

ini 复制代码
const editorToolbarConfig = merge(
		{
			excludeKeys: ['codeBlock', '|'],
		},
		options.toolbarConfig || {},
	);

将传入的toolbarConfig,与hook编写的公共默认参数部分合并。

1.4. 编辑器配置

editorConfig的配置

js 复制代码
const editorConfig = merge(
    {
        placeholder: '请输入正文,可插入图片、附件',
        MENU_CONF: {
            uploadImage: {
                // 自定义上传
                async customUpload(file: File, insertFn) {
                    // 限制大小
                    const maxFileSize = 10 * 1024 * 1024; // 10M
                    if (file.size > maxFileSize) {
                        await MessagePlugin.warning({ content: '请选择小于10M的图片' });
                        return;
                    }

                    const loading = LoadingPlugin({
                        attach: () => editorContainerRef.value,
                        showOverlay: true,
                        size: '20px',
                    });

                    try {
                        const result = (await upload(file)) as PutObjectResult;
                        insertFn(result.url, result.name, result.url);
                        loading.hide();
                    } catch (e) {
                        console.log(e);
                        loading.hide();
                    }
                },
            },
    },
    EXTEND_CONF: {
            mentionConfig: {
                // eslint-disable-next-line @typescript-eslint/no-empty-function
                showModal: () => {},
                // eslint-disable-next-line @typescript-eslint/no-empty-function
                hideModal: () => {},
            },
        },
    },
    options.config || {},
);

通过合并多个配置对象生成的editorConfig,代码中的图片上传方法,也是在此处进行配置好,

uploadImage 自定义上传的配置。在这个自定义上传配置中,首先对文件大小进行了限制,限制为10M以下的图片。如果超过了限制大小,会显示一个警告提示给用户。然后,它创建了一个loading对象,并在上传文件时显示loading动画。接着,通过upload函数上传文件,并将返回的结果(包括URL、名称等)传递给insertFn函数,这样就能将图片插入到编辑器中。最后,无论上传成功或失败,都会隐藏loading动画。

当然这里只是对图片上传做了配置,还可以根据wangEditor的相关文档,做深入的配置方法覆盖,以适配我们自己的后端服务接口以及业务逻辑。

当然官方文档也给有一个例子:

还有其他的自定义功能,这里就不作多的叙述

1.5. 销毁编辑器

在hook文件editor.ts的useEditor方法体里面写该销毁方法了

ini 复制代码
	// 组件销毁时,也及时销毁编辑器
	onBeforeUnmount(() => {
		const editor = editorRef.value;
		if (editor == null) return;
		editor.destroy();
	});

其次,使用useEditor

如图:

调用useEditor hook,并将配置参数传递给它。其中,toolbarConfig用于配置编辑器工具栏的显示和顺序,insertKeys指定了fontFamily工具的位置,excludeKeys指定了需要排除的工具项。config用于设置编辑器的占位符文本。

最后,将useEditor hook返回的结果解构赋值给之前定义的变量,以获取相关引用和配置信息, 代码:

js 复制代码
// 富文本
const { editorContainerRef, editorRef, editorToolbarConfig, editorConfig, editorCreated } = useEditor({
	toolbarConfig: {
		insertKeys: {
			index: 4,
			keys: ['fontFamily'],
		},
		excludeKeys: ['insertVideo', 'insertTable', 'fullScreen', 'blockquote', 'codeBlock', 'todo', '|'],
	},
	config: {
		placeholder: '请输入内容',
	},
});

最后,看效果:需要完整代码请在评论区留言,仅做参考

相关推荐
m0_748256148 分钟前
前端 MYTED单篇TED词汇学习功能优化
前端·学习
小马哥编程1 小时前
Function.prototype和Object.prototype 的区别
javascript
小白学前端6661 小时前
React Router 深入指南:从入门到进阶
前端·react.js·react
苹果醋31 小时前
React系列(八)——React进阶知识点拓展
运维·vue.js·spring boot·nginx·课程设计
web130933203982 小时前
前端下载后端文件流,文件可以下载,但是打不开,显示“文件已损坏”的问题分析与解决方案
前端
王小王和他的小伙伴2 小时前
解决 vue3 中 echarts图表在el-dialog中显示问题
javascript·vue.js·echarts
学前端的小朱2 小时前
处理字体图标、js、html及其他资源
开发语言·javascript·webpack·html·打包工具
outstanding木槿2 小时前
react+antd的Table组件编辑单元格
前端·javascript·react.js·前端框架
好名字08212 小时前
前端取Content-Disposition中的filename字段与解码(vue)
前端·javascript·vue.js·前端框架
摇光932 小时前
js高阶-async与事件循环
开发语言·javascript·事件循环·宏任务·微任务