用 Tinymce 打造智能写作

一、为什么要使用tinymce框架

AI 大模型正在把"富文本编辑器"从「打字板」变成「智能办公伙伴」。

前端工程师的交付物不再只是"能打字",而是"会思考、会润色、会排版、会翻译、会合规"的 AI 文书工作台,这是LLM在应用层的一个重要方面。对于前端工程师来说要实现这样的功能富文本编辑器是必不可少的。我们为什么要选择tinymce呢?它需要满足以下几个条件

(1)稳定可靠

对于前端工程师来说,可以用的富文本编辑器简直不要太多,但是我们要选择一个高度可靠的,当前正维护的富文本编辑器,并且开源可用的,tinymce分为商用和免费两个版本,并且是正在维护的项目,使用的人多。

(2)插件丰富可扩展

tinymce有丰富的插件,并且插件可扩展,但是插件由两部分,分为免费和付费的。一般情况下免费的就足够了,对于一些简单的并且没有免费的插件,我们可以自己扩展插件。

(3)高度可定制化

一般情况下,前端富文本编辑器是一般UI:

要做智能文书我们就需要富文本编辑器的UI高度可定制化,例如:妙笔平台的ai文书平台:

不但需要UI样式可定制化,而且需要toolbar高度可定制化,并且还可以支持侧边栏功能。

二、tinymce使用经验记录

tinymce的一个重要的问题是没有中文文档,并且分为收费和免费两个版本。我们应该如何使用呢?

(1)本地化部署

:tinymce官网,选择免费版本,当然你也可以使用收费版本,更加好用哦。

下载好后就可以在本地的vue3 项目中引入,放到public文件夹下,然后添加引用。

(2)toolbar配置

虽然文档都是英文的,不过结构清晰,其实是很好用的:

例如我们想实现,像妙笔那样的效果:就用以下代码:

php 复制代码
tinymce.init({
	selector: 'textarea#default',
	promotion: false,   //取消付费推广信息
	branding: false,    //取消付费推广信息
	language: 'zh_CN', 
	toolbar_mode: 'sliding',
	menubar: false,
	skin: 'tinymce-5',
	placeholder: '请输入内容...',
	license_key: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', //你自己申请的licenese
	height: 'calc(100vh - 66px)',    //自定义高度
	content_css: '/tinymce/tiny-scroll.css',   //一些自定义样式
	inline: false, // 设置为true时,编辑器会自动将内容包裹在<div>标签中,并添加一些默认样式。要模仿他们的,放到单独的iframe中。
	content_style: `
                body {
                    font-family: "宋体";
                    font-size: 16px;
                    padding:1in 0.8in 1in 1in;
                }
                `, //也可以放到自定义样式里面。
            plugins: 'table fullscreen wordcount',
	color_cols: 5,
	toolbar: 'undo redo removeformat | fontfamily fontsize | bold italic underline strikethrough forecolor backcolor| h1 h2 h3 h4 | sideName',
	setup: function (editor) {}, //做一些页面的设置
            init_instance_callback: (newEditor) => {}  //初始化文成后的回调。
});

这样我们就可以自定义UI的样式,实现例如a4纸的效果。

(3)toolbar私有化配置

如果我们想自定义toolbar,并且点击后要打开右边的侧边栏需要怎么做呢? 其实很简单,注册图标icon --> 注册sidebar,并且应该自定义图标 这个时候我们就可以看看api文档了。

虽然都是英文但是也很好理解。 下面直接看代码(注意下面的代码都要放到setup方法里面):

xml 复制代码
editor.ui.registry.addIcon(
        'youicon',
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ></svg>');  

这里有一点需要注意,如果你的图标有文字,那么把文字和图片都放到svg里面就行了。 然后注册sidebar:

javascript 复制代码
    editor.ui.registry.addSidebar('sideName', {
            icon: 'youicon', //你注册的图标
            onSetup: (api) => {},
            onShow: (api) => {},
            onHide: (api) => {}
     })

这样就注册了一个空的sidebar,名称为:sideName,将这个sidebar添加到toolbar上就行了。这样就实现了自定义toolbar,并且绑定到sidebar上。

(4)深入融合vue3组件

如果我们想在sidebar上添加自定义vue3组件怎么办呢?其实答案就藏在问题里面:在sidebar的onshow方法里面,我们再手动挂载个vue3 组件就行了。然后传递给他一些属性和方法,方法可以用于回调。其实就是两个vue实例都和tinymce交互,这样就是实现了组件之间的交互,下面是一个简单的例子,注意再onshow方法里面:

javascript 复制代码
        import youComponents from 'xxxxxxxxxxxxxxxxxxxx';
        ......
        const callbarFunction = () => {
        } //交互回调。
        ......
        onShow: (api) => {
            const mountPoint = document.createElement('div');
            api.element().appendChild(mountPoint);
            const vueApp = createApp(youComponents, {
                    editor, // 将编辑器实例传递给组件
                    callbarFunction: callbarFunction,
            });
            vueApp.mount(mountPoint);
        },

这样就把你的vue对象挂载到对应的sidebar上面,并且将editor实例传递过去,还有回调函数。能完成数据交互。

(5)tinymce事件系统

所有的事件都要放到setup函数里面进行定义。

5.1鼠标键盘事件

如果想在tinymce监听鼠标键盘事件。直接看代码:

javascript 复制代码
setup: function (editor) {
    editor.on('keyup', function (e) {
            //键盘事件
    });
    editor.on('mousedown', function (e) {
            //鼠标事件
});
    editor.on('init', function (e) {
            //初始化事件
});
    editor.on('change', function (e) {
            //文档改变事件
    });
}

tinymce支持那些事件呢?看文档:www.tiny.cloud/docs/tinymc... 。 这里有你所需要的大部分事件。

5.2自定义命令

如果我们想自定义一些命令,然后手动触发它怎么做呢?

javascript 复制代码
editor.on('ExecCommand', (e) => {
    console.log(e.value)  //自定义指令的名称
})

这个是用来监听自定义指令的。如果我们想自动打开sidebar,然后传递个参数进去:

arduino 复制代码
 tinymce.activeEditor.execCommand('ToggleSidebar', false, 'params');

你也可以查看参考文档:www.tiny.cloud/docs/tinymc...

(6)tinymce的前端安全

这是一个老生常谈的问题了。凡是富文本就离不开前端安全问题。当然我们的老熟人DOMPurify要用起来。

6.1使用v-safe-html代替v-html

javascript 复制代码
app.directive('safe-html', {
  beforeMount(el, binding) {
    el.innerHTML = DOMPurify.sanitize(binding.value)
  },
  updated(el, binding) {
    el.innerHTML = DOMPurify.sanitize(binding.value)
  }
})

6.2保存到服务端的数据要进行转义

arduino 复制代码
const clean = DOMPurify.sanitize(content)//将clean保存到服务端。

将转义后的内容保存到服务端。

项目心得

(1)前端保存docx需要注意事项

以前的项目都是服务端生成docx然后下载就行了,如果前端自己将页面生成docx然后下载需要注意什么呢? docx支持p,table,ul,li等少数几个标签,并且样式要写到style里面。并且并不支持所有的css样式,例如常用的display:flex。如果你是个老前端,知道为什么有flex布局,不是用flex如何布局。

(2)踩过的坑。

这个项目全部都采用tinymce结构,不能有的地方用,有的地方不用。这样容易出错,可以参考别人做过的,大体结构要按照别人的写。

相关推荐
angelQ6 小时前
Vue 3 中 ref 获取 scrollHeight 属性为 undefined 问题定位
前端·javascript
Dontla6 小时前
(临时解决)Chrome调试避免跳入第三方源码(设置Blackbox Scripts、将目录添加到忽略列表、向忽略列表添加脚本)
前端·chrome
我的div丢了肿么办6 小时前
js函数声明和函数表达式的理解
前端·javascript·vue.js
云中雾丽6 小时前
React.forwardRef 实战代码示例
前端
朝歌青年说6 小时前
一个在多年的技术债项目中写出来的miniHMR热更新工具
前端
Moonbit6 小时前
倒计时 2 天|Meetup 议题已公开,Copilot 月卡等你来拿!
前端·后端
Glink6 小时前
现在开始将Github作为数据库
前端·算法·github
小仙女喂得猪6 小时前
2025 跨平台方案KMP,Flutter,RN之间的一些对比
android·前端·kotlin
举个栗子dhy6 小时前
第二章、全局配置项目主题色(主题切换+跟随系统)
前端·javascript·react.js