Monaco Editor教程(五): 实现同时多文件编辑,tab切换

news/2024/5/4 10:13:59/文章来源:https://blog.csdn.net/github_35631540/article/details/126977288

背景

上一篇我们讲解了如何设置编辑器的值,获取编辑器的值,以及监听编辑器的内容修改。这些功能对于基础的单文件修改,一次只修改一个文件的业务场景比较友好。但如果是复杂的场景,比如WEB IDE,同时打开一个项目的多个文件,并切换文件进行编辑,修改。这种应该怎么做那?
如下图
在这里插入图片描述
今天这篇我就给大家介绍一下如何使用monaco editor实现多文件编辑。

实现效果如下:
在这里插入图片描述

另外再说一下,上一篇,我看到有监听mode修改语言的事件,但没有找到在哪里修改,
这次我找到了
http://localhost:8080/monaco-editor-website/api/modules/monaco.editor.html#setModelLanguage

使用editor.setModelLanguage() 方法 修改model的语言。随着不断的阅读文档,你会被这个项目所折服。

文件

首先我们定义三个文件, file1,file2 file3,使用map来存储他们的内容。

 const fileMap = new Map()fileMap.set('file1', { content: 'const blog = "https://fizzz.blog.csdn.net/"', language: 'javascript', model: null, state: null })fileMap.set('file2', { content: 'x = 1 \nprint(x)', language: 'python', model: null, state: null })fileMap.set('file3', { content: 'System.out.println("Hello World");', language: 'java', model: null, state: null })

以文件名为key,以文件的其他内容为value,存放到一个map中。方便存取。
其中 content是文件的内容,
language 为文件的语言,
model是语言模型,
state是编辑器的状态 这个属性等下详细讲解

核心代码及解释

在页面上添加三个按钮

<button onclick="showFile('file1')">文件1</button>
<button onclick="showFile('file2')">文件2</button>
<button onclick="showFile('file3')">文件3</button>

点击按钮触发showFile函数,以下是showFile函数内容

function showFile(fileName) {const fileItem = fileMap.get(fileName)var currentState = editor.saveViewState();var currentModel = editor.getModel();fileMap.forEach((item, key) => {if (currentModel === item.model) {item.state = currentState}})if (fileItem.model) {editor.setModel(fileItem.model);editor.restoreViewState(fileItem.state);} else {const newModel = monaco.editor.createModel(fileItem.content, fileItem.language);editor.setModel(newModel);fileItem.model = newModel}editor.focus();
}

首先要说明的是,monaco editor 不提供文件导航的功能,如果你要实现一个web ide,那么编辑器上的 文件切换tab需要自己实现。就是这一部分
在这里插入图片描述

另外,我们需要为每一个打开的文件创建一个model,使用monaco.editor.createModel方法。
然后将创建的model保存到对应的文件内容中 fileItem.model = newModel 这行就是做一步的。

在创建model前,需要先判断文件是否已经有了model,如果已经有了,那么用已经创建的,如果没有,那么新建一个model,然后使用editor.setModel()方法,将语言模型显示到编辑器上。

关于model这一块,这里就不讲解太多,上一篇已经讲解的很详细了。
在来讲解一下这几行代码

// 保存当前编辑器的状态,赋值给currentState 
var currentState = editor.saveViewState();
...
// 恢复编辑器的状态
editor.restoreViewState(fileItem.state);
...
// 使编辑器获取焦点
editor.focus();

要引入编辑器状态就要首先搞清楚一点,这个编辑器状态,到底包含哪些状态。之前我也不知道,但我查到了这个
http://localhost:8080/monaco-editor-website/api/interfaces/monaco.editor.ICodeEditorViewState.html

并经过试验得知,
这里的状态包括光标,选中,滚动条。 是的你没看错,monaco editor会记录你在编辑器的所有操作,这些状态用户可以保存起来,并在合适的时机进行恢复。达到一种非常无缝衔接的丝滑交互体验。 真的 Amazing 。

在编辑器中 使用 editor.saveViewState() 方法获取当前编辑器的状态,
使用 editor.restoreViewState()方法恢复编辑器的状态。

恢复编辑器状态后,还需要使用editor.focus(); 让编辑器获取焦点。这样编辑器中选中的内容 就会高亮。

效果图

在这里插入图片描述

完整代码

<!DOCTYPE html>
<html><head><title>Hello World Monaco Editor</title><meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
</head><body><h2>Hello World Monaco Editor</h2><button onclick="setValue()">设置值</button><button onclick="getValue()">获取值</button><button onclick="showFile('file1')">文件1</button><button onclick="showFile('file2')">文件2</button><button onclick="showFile('file3')">文件3</button><div id="container" style="width: 800px; height: 600px; border: 1px solid grey"></div><script src="./monaco-editor/package/min/vs/loader.js"></script><!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.5/require.min.js"></script> --><script>require.config({ paths: { vs: './monaco-editor/package/min/vs' } });let editorrequire(['vs/editor/editor.main'], function () {editor = monaco.editor.create(document.getElementById('container'), {value: ['function x() {', '\tconsole.log("Hello world!");', '}'].join('\n'),language: 'javascript'});});function setValue() {// 第一种重新设置值// var currentModel = editor.getModel();// currentModel.setValue(`// 重新设置值// const blog = 'https://fizzz.blog.csdn.net/'// `)// 第二种重新设置值var currentModel = editor.getModel();const model = monaco.editor.createModel(`
// 重新设置值
x = y = z = 1
print(x) #1
`, 'python');editor.setModel(model);model.onDidChangeContent(e => {console.log(e)});if (currentModel) {currentModel.dispose();}}function getValue() {var currentModel = editor.getModel();console.log(currentModel.getValue())}const fileMap = new Map()fileMap.set('file1', { content: 'const blog = "https://fizzz.blog.csdn.net/"', language: 'javascript', model: null, state: null })fileMap.set('file2', { content: 'x = 1 \nprint(x)', language: 'python', model: null, state: null })fileMap.set('file3', { content: 'System.out.println("Hello World");', language: 'java', model: null, state: null })function showFile(fileName) {const fileItem = fileMap.get(fileName)var currentState = editor.saveViewState();var currentModel = editor.getModel();fileMap.forEach((item, key) => {if (currentModel === item.model) {item.state = currentState}})if (fileItem.model) {editor.setModel(fileItem.model);editor.restoreViewState(fileItem.state);} else {const newModel = monaco.editor.createModel(fileItem.content, fileItem.language);editor.setModel(newModel);fileItem.model = newModel}editor.focus();}</script>
</body></html>

总结

多文件切换是一个常用的业务场景,也是编辑器的必备的功能,如果做好该场景的交互优化,用户体验是非常关键的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_16555.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

聊聊SQL注入

明天是国庆1001,祝大家国庆节快乐!!!这个月还有属于程序员的节日:1024SQL注入问题概述:首先SQL注入是一个非常危险的操作,很可能被一些不怀好意的人钻空导致我们系统出现异常等状况,比如数据库遭到破坏或被入侵。原因:使用JDBC的Statement语句添加SQL语句由于我们的JD…

直播电商开发,源码无加密

随着直播电商的流行&#xff0c;很多企业开始使用商场电商直播系统&#xff0c;该企业使用电商直播系统的优势具体体现在哪里&#xff1f;下面由零七科技小编为您总结企业电商直播系统的优点。 使用电商直播系统的优点&#xff1a; 1、全面展示商品风格和效果。 与在线平台的…

【Django-rest-framework框架】第04回 视图集

目录1. 两个视图基类1.1 GenericAPIview属性和方法1.2 基于APIView写5个接口1.3 基于GenericAPIview写5个接口2. 5个视图扩展类3. 9个视图子类4. 视图集5. 源码分析ViewSetMixin6. 总结7 继承关系画出来,有哪些常用属性或方法写出来 1. 两个视图基类 1.1 GenericAPIview属性和…

【redis】7.1 分布式架构概述(章节介绍)

分布式架构概述 请求业务比较长&#xff08;耗时业务&#xff09;&#xff0c;需要分布式系统。 1. 本章节内容 分布式缓存中间件Redis分布式会话与单点登录分布式搜索引擎Elasticsearch分布式文件系统分布式消息队列分布式锁数据库读写分离与分库分表数据库表全局唯一主键i…

迭代器并不全是指针,list的迭代器与vector和string的有什么不一样,让博主告诉你其底层原理!

链表的模拟实现 文章目录链表的模拟实现一、list的基本架构&#x1f916;_list_node基本构架--双向带头循环链表二、list的迭代器--重点&#x1f431;‍&#x1f464;list迭代器的基本架构构造函数--node*封装operator*()--得到值operator!()--跟另一个迭代器进行比较operator(…

xLua热更新(一)xLua基本使用

一、什么是xLua xLua为Unity、 .Net、 Mono等C#环境增加Lua脚本编程的能力&#xff0c;借助xLua&#xff0c;这些Lua代码可以方便的和C#相互调用。 xLua是用来实现Lua代码与C#代码相互调用的插件。我们可以借助这个插件来实现热更新方案。 那么为什么要选择Lua实现热更新呢&am…

报告分享|数字化转型,从战略到执行报告

报告链接:http://tecdat.cn/?p=28672 如何加速国家、城市、行业、企业数字化进程,激发数字经济新动能。这份报告通过洞察数字化的6大改变、4大载体、4个阶段、20+场景、100+国家/项目案例/数据,全面系统性地阐述了多层次多场景数字化如何落地实施,最终带来经济、社会价值的…

报告分享|2022年企业数字化人才发展白皮书

报告链接:http://tecdat.cn/?p=28670 数字经济时代,企业对数字化人才的需求急剧增长。此报告对数字化人才培养和企业数字化人才发展现状进行梳理和研究,聚焦于金融、零售、能源和制造四个行业,采用定量与定性相结合的研究方法,对数字化人才的发展态势、岗位能力需求、培养…

第八章 常用用类

文章目录8.4 StringBuffer类8.4.1 StringBuffer对象8.4.2 StringBuffer类的常用方法1.append方法2.charAt(int n)和setCharAt(int n, char ch)8.5 Date类与Calendar类8.5.1 Date类8.5.2 Calendar类8.6 日期的格式变化8.6.1 format方法8.6.2 不同区域的星期格式8.7 Math类、BigI…

【算法】【二叉树模块】求一个二叉树“子树“是否包含另一个二叉树的全部拓扑结构

目录前言问题介绍解决方案代码编写java语言版本c语言版本c语言版本思考感悟写在最后前言 当前所有算法都使用测试用例运行过&#xff0c;但是不保证100%的测试用例&#xff0c;如果存在问题务必联系批评指正~ 在此感谢左大神让我对算法有了新的感悟认识&#xff01; 问题介绍 …

三个线程顺序打印ABC?我有十二种做法,彻底掌握多线程同步通信机制

大家好&#xff0c;我是老三&#xff0c;这篇文章分享一道非常不错的题目&#xff1a;三个线程按序打印ABC。 很多读者朋友应该都觉得这道题目不难&#xff0c;这次给大家带来十二种做法&#xff0c;一定有你没有见过的新姿势。 1. synchronizedwaitnotify 说到同步&#xf…

Swift中的内存访问冲突、指针、局部作用域

内存访问冲突&#xff08;Conflicting Access to Memory&#xff09; 1、内存访问冲突会在两个访问满足以下条件时发生&#xff1a; 至少一个是写入操作它们访问的是同一块内存它们的访问时间重叠&#xff08;比如在同一个函数内&#xff09; //无内存访问冲突 func plus(_ n…

PIE-engine 教程 ——利用NDWI加载青海湖三年水域影像和面积计算

这里我们首先画一个自己选择的研究区&#xff0c;用于方便计算NDWI&#xff0c;这里我们将青海湖区域作为我们的研究区&#xff0c;第二步我们就是要设定一个函数&#xff0c;用于在函数中执行循环遍历&#xff0c;这里包括去云和影像筛选过程&#xff0c;最后按照最大值合成&a…

Windows 10 docker 容器添加新端口映射的方法与步骤

在Docker容器已经创建后&#xff0c;需要添加新的端口映射&#xff0c;即对已经存在的Docker容器添加新的端口映射&#xff0c;可以通过以下步骤来添加&#xff0c;即通过修改配置文件的方法。 1、Windows 10 下 Dockers容器的配置文件存在的路径为&#xff1a; 笔者本文是20…

CLIP扩展

Audio CLIP:Extend CLIP to Image,Text and Audio&#xff08;语音&#xff09; 在已有的image、text 的基础上又加上了audio语音模态。 找了一些视频&#xff0c;有视频帧&#xff08;图像&#xff09;、文本、语音三种模态的信息&#xff0c;仿照CLIP的模型结构。三种模态两…

SpringSecurity + JWT(前后端分离)

文章目录一、先来聊聊 SpringSecurity JWT二、简单聊聊SpringSecurity 完整流程1、认证2、授权三、撸代码1、入门案例2、认证-前端端分离 Demo2.1 环境准备2.2 密码加密存储2.3 数据库校验存储2.4 编写自定义登陆接口2.5 JWT 认证过滤器2.6 退出登陆3、授权-前后端分离 Demo3.…

Spring In Action 5 学习笔记 chapter8 RabbitMQ(AMQP)要点

本文记录Sping In Action5 第8章 发送异步消息 RabbitMQ(AMQP)中的踩坑情况。 网搜的Spring In Action5的书籍在线翻译 https://potoyang.gitbook.io/spring-in-action-v5/ 第8章的源码请自行github或gitee搜索&#xff0c;或参考一下。 GitHub - habuma/spring-in-action-5…

web学生网页设计作业源码 HTML+CSS+JS 网上鲜花商城购物网站

&#x1f329;️ 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f482; 作者主页: 【进入主页—&#x1f680;获取更多源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;HTML5网页期末作业 (1000套…

MySQL Workbench 创建用户

创建本机用户 选择权限(增删改查)6个 创建新用户编辑窗口

【Web基础】Web应用体系结构 — 容器 + MVC设计模式

前言&#xff1a;提前祝大家国庆快乐了~~~~ 文章目录1 容器1.1 容器定义1.2 容器功能1.3 容器如何处理请求1.4 URL 映射 servlet2. MVC设计模式2.1 MVC 设计模式定义2.2 为什么要采用 MVC 设计模式&#xff1f;1 容器 1.1 容器定义 Servlet 没有 main() 方法&#xff0c;它们…