Nuxt3接入Monaco Editor编辑器,实现翻译网站比对功能
一、需求背景
最近在负责公司翻译网站的开发,需要实现原文和译文之间的对比功能,这个对比功能主要有三点:
- 行保持:原文和译文同一段高度需要保持一致,以最高的为准,假设同一段(行)文本,原文是 2 行的高度,译文是 3 行,那么原文此段下方需要填充空行,保持左右两边高度一致;
- 差异高亮显示:译文相对于原文,不同的字词需要高亮显示;
- 同步滚动:类似于 MD 编辑器的同步滚动。
刚开始是想自己去实现这几个功能,在 MD 编辑器的基础上实现,同步滚动倒是没什么问题,关键是另外两点很难实现,初始的想法是:行保持采用手动操作 DOM 实现,差异高亮显示使用 jsdiff 实现,但是效果以及性能特别差,也许是自己的能力不行,无奈之下只能放弃,另寻出路。
后面同事给我推荐了一款编辑器 Monaco Editor,这款编辑器功能十分强大,自带差异编辑模式。
二、Monaco Editor
Monaco Editor 由微软开发,它和 VSCode 在编辑代码,交互以及 UI 上几乎是一模一样,Monaco Editor (基于浏览器)可以看作是一个编辑器控件,只提供了基础的编辑器与语言相关的接口,可以被用于任何基于 Web 技术构建的项目中(不支持移动浏览器)。
普通的编辑器模式:
差异编辑器模式:
Monaco Editor 的应用是十分广泛的,很多平台都用到它作为编辑器,举几个常见的例子:
Gitlab:
Github在线编辑器:
在线WebIDE CodeSandBox:
通过官网的 DEMO,我简单测试了下,发现该编辑器已经提供了上面所说的 3 个对比功能点,因此采用这款编辑器进行开发,但是需要去掉默认的许多配置,以及修改样式,将其进行彻底的改造!
Monaco Editor 提供了很多的配置以及 API,大家可以根据需要自行查阅:
microsoft.github.io/monaco-edit…
三、最终效果展示
四、在 Nuxt3 项目中接入
在 Nuxt3 项目中接入 Monaco Editor 编辑器的过程中踩了很多的坑,网站很多文章都是关于 webpack 项目接入的,而 Nuxt3 内部的构建打包工具用的是 Vite,在这里和大家分享接入的过程!
首先项目的 Nuxt 版本:"^3.7.0",安装 monaco-editor 的版本为:0.50.0
首先封装个组件,这里不能直接使用 import 语句导入 monaco-editor,服务端渲染会报错,因此在客户端的时候,动态引入使用:
使用组件,传入左右编辑器对应的 value 即可:
五、编辑器的使用及改造
5.1、常用的配置项
下面这些是我在项目里用到的编辑器配置,因为用不到编辑器里的很多默认功能,所以我把它们都去掉了,大家可以根据项目的需要进行设置:
这里比较坑的一点是:默认情况下编辑器最后会有一段大留白,极大影响了页面的样式效果,需要设置 scrollBeyondLastLine: false 将其去掉。
更加完整的配置可以参考这篇博客:blog.csdn.net/qq252320847… 或者直接去官方文档中查找。
5.2、对比色、背景色修改
编辑器默认的对比背景色,大多时候都不符合我们项目的要求,因此需要进行修改,但是修改对比背景色并不容易,尝试了几种方法,才顺利解决。
第一种方法:使用 CSS 修改对应盒子的样式,颜色倒是可以生效
但是会影响其他的颜色,比如鼠标选中文本的颜色,对比色均无法正常显示,没法解决这个问题,只能尝试其他的方式。
第二种方法:自定义主题,查阅了许多文档才知道可以通过定义主题的方式去修改颜色
但是需要找到对应的属性名称才行,正好在浏览器元素面板中可以看到 Vscode 定义的许多主题属性:
对上面的代码进行修改:
遗憾的是,还是有问题,跟第一种情况是一样的,会影响其他的颜色正常显示
第三种方法:受第二种方法的启发,决定尝试修改 css 变量的值,新建 monaco-editor.less 文件,在里面覆盖默认的 CSS 变量的值
这种方法终于完美的修改了对比色、背景色,同时不会影响到别的东西。
5.3、鼠标光标定位的最后
在项目里翻译功能有个需求,由于翻译后的内容是流式输出的,因此在输出的时候需要滚动到编辑器的最底部。
这个听起来是很简单的,只要找到滚动的元素,然后一行代码便可以搞定:
但是效果不佳,存在许多问题,比如在对比编辑器中,如果左侧的内容非常多,右侧目前是空的,此时两侧的滚动条其实是同步的:
如果这个时候执行滚动到底部的操作,那么上面输出的内容就无法看到了,虽然说可以解决这个问题,但是尝试了下,会造成其他的问题,所以便放弃了这种方式。
最终采用控制鼠标光标的位置来实现平滑滚动到内容的最后:
5.4、预加载编辑器
由于这个编辑器的体积比较大,加载耗时,会影响用户的体验,所以我在项目中做了优化:预加载编辑器
其实就是在用户见到编辑器之前,先加载渲染一遍编辑器相关的东西,我是在 loading 页面中预加载的,进入主页面之后编辑器几乎是秒出。
首先封装个简单的组件 PrefetchMonaco.vue,与上面的 Nuxt3项目接入 中的封装是类似的,只不过将多余的代码全都去掉,给组件设置定位移出屏幕可视区域:
PrefetchMonaco.vue
在 loading 页面中引入使用,需要根据实际情况处理,要记得销毁编辑器实例!
原文链接:
https://juejin.cn/post/7406253583317073972