6

使用monaco-editor,registerCompletionItemProvider多次注册,最终导致展示的提示内...

 2 years ago
source link: https://segmentfault.com/a/1190000040712964
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

最近项目实现一个提示功能,输入某个符号,展示匹配的内容,和代码提示功能类似。最终选择了monaco-editor,微软开发的js库,vscode也是基于这个库开发的。

在开发过程中,遇到些问题,由于文档不是很友好,花了半天才解决问题。下面主要记录一下问题以及解决办法,希望以后遇到这些问题的童鞋能快速避坑。

遇到的问题以及解决办法

在Antd Modal中使用monaco-editor,显示Modal后关闭Modal,再次打开Modal,monaco-editor的提示内容就会重复,显示几次Modal,对应的内容就会重复几次,如下图:

demo

思路1:
经过调试发现,registerCompletionItemProvider方法多次执行,首先猜到的可能是插件多次创建,没有销毁造成的,查阅对应的文档后,发现有插件提供了一个销毁的方法:

monaco.editor.dispose()

于是,尝试在组件销毁之前调用上面的方法,但是运行后发现并不生效,上述问题依旧存在,此法不通~

思路2:
既然registerCompletionItemProvider多次执行,那么给组件中添加一个全局的计数器count,组件注册一次后执行一次count+1,只有当count===0时,才走对应的插件注册逻辑,否则直接取缓存的数据。部分代码片段如下:

 let count = 0;
      monaco.languages.registerCompletionItemProvider(languageName, {
        triggerCharacters: ['['],
        provideCompletionItems: function (model, position, context) {
          count=count+1;
          if(count===1){
            let suggestions = [];
            if (context.triggerCharacter === '[') {
              [...dimensions, ...modules].forEach((item, index) => {
                suggestions.push({
                  label: item.customName,
                  insertText: `${item.customName}]`,
                  kind: 12,
                });
              });
            }
            return { suggestions };
          }
        },
      });

这种方式简单粗暴,如果需要插件提示的内容是固定的,直接用缓存的数据是可以解决这个问题。但是!!!我遇到的需求是,提示的内容是根据接口动态取的。所以,此法依旧不通~

思路3:
由于谷歌和百度都没用找到满意的答案,于是去monaco-editorGitHubissues中查找答案,刚开始根据registerCompletionItemProvider关键字搜索,但是并没有类似的问题,然后又尝试搜索provideCompletionItems关键词,最终在issues中找到了2个类似的问题,链接如下:

https://github.com/microsoft/monaco-editor/issues/2217

https://github.com/microsoft/monaco-editor/issues/2084

最终解决办法:
registerCompletionItemProvider注册创建时,将创建的对象存储起来,如下:

 monacoProviderRef.current = monaco.languages.registerCompletionItemProvider(languageName, {

在组件销毁时,将editorregisterCompletionItemProvider生成的对象一同销毁。代码如下:

useEffect(() => {
      // todo
      // xxxxxx
      return () => {
        // 销毁
        monacoProviderRef.current?.dispose();
        monacoRef.current?.dispose();
        
      };
    }, []);

最后测试,bug完美解决!

设置editor的默认主题,但是Modal第一次展示时,默认主题没有生效,第一次之后主题才会生效,如下图:

设置默认主题代码如下:

monaco.editor.defineTheme('myCoolTheme', {
        base: 'vs',
        inherit: false,
        colors: { token: 'value', foreground: '#00c1de' },
        rules: [{ token: 'value', foreground: '#00c1de' }],
      });

去官方文档中找设置主题的api,发现以上代码是对主题的定义操作,如果要首次运行生效,还需要手动设置一次上面对应定义的主题

monaco.editor.setTheme('myCoolTheme');

最终,问题解决,效果如下:

愿天下没有难解的bug!祝大家中秋节快乐!!!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK