【超详细】 对 AceEditor 二次封装 及 自定义扩展语言实现

这篇具有很好参考价值的文章主要介绍了【超详细】 对 AceEditor 二次封装 及 自定义扩展语言实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

📢 前言

最近调研前端代码编辑器,选中了 Ace editor,其本身功能丰富,扩展性也极强,插件目前更新稳定。ace 本身支持上百种语言的语法,然鹅日常项目中总有些奇葩的需求,以致我们需要去了解更多的技术研究。
技术支持: Vue3 + Vite ,基于 ace-builds 进行二次扩展封装。

📄 Ace 简介

1、什么是 Ace editor ?

Ace(Ajax.org Cloud9 Editor)是一个用 JavaScript 编写的可嵌入代码编辑器。它与 Sublime,Vim 和 TextMate 等本地编辑器的功能和性能相匹配。它可以轻松地嵌入任何网页和 JavaScript 应用程序中。

2、特征
  • 超过 110 种语言的语法高亮显示(可以导入 TextMate/Sublime Text.tmlanguage 文件)
  • 超过 20 个主题(可以导入 TextMate/Sublime Text .tmtheme 文件)
  • 自动缩进和缩进
  • 可选的命令行
  • 处理大型文档(四百万行似乎是极限!
  • 完全可定制的键绑定,包括 vim 和 Emacs 模式
  • 搜索并替换为正则表达式
  • 突出显示匹配的括号
  • 在软标签和真实标签之间切换
  • 显示隐藏字符
  • 使用鼠标拖放文本
  • 换行
  • 代码折叠
  • 多个光标和选择
  • 实时语法检查器(目前为 JavaScript/CoffeeScript/CSS/XQuery)
  • 剪切、复制和粘贴功能

✒️ Ace 使用及封装

1、安装

使用 pnpm 包管理器,引入 ace-builds 库

	pnpm i ace-builds -D
	pnpm i vue-loader-v16 -D // 引入 ace 报错时需安装
2、引入

引入基础模块,测试ace编辑器基础功能

	<template>
	  <div class="aceEditor" ref="aceEditor"></div>
	</template>
	
	<script lang="ts" setup>
	import { onBeforeUnmount, onMounted, ref, watch } from 'vue';
	import * as ace from 'ace-builds';
	
	import "ace-builds/src-noconflict/mode-javascript"; // 语言模式
	import "ace-builds/src-noconflict/theme-monokai" // 主题
	import "ace-builds/src-noconflict/ext-language_tools"; // 语法提示
	import "ace-builds/src-noconflict/snippets/javascript"; // 语法段提示模块
	</script>
3、配置
	const options = {
	  theme: 'ace/theme/monokai', // 设置语法高亮主题
	  mode: 'ace/mode/javascript', // 设置语法 mode
	  tabSize: 1,
	  maxLines: 25,
	  minLines: 25,
	  showPrintMargin: false,
	  fontSize: 14,
	  printMarginColumn: 20,
	  useWorker: false,
	  showLineNumbers: true, // 显示行号
	  showGutter: true, // 显示行号区域
	  highlightActiveLine: false,
	  highlightSelectedWord: false, // 高亮选中文本
	  readOnly: false, // 控制编辑器是否只读
	  enableSnippets: true, // 启用代码段提示
	  enableLiveAutocompletion: true, // 启用实时自动完成
	  enableBasicAutocompletion: true,  // 启用基本自动完成
	}
4、初始化
	const initEditor = () => {
	  if (editor) editor.destroy();
	
	  // 初始化
	  editor = ace.edit(aceEditor.value, options);
	
	  // 切换自动换行
	  editor.getSession().setUseWrapMode(true);
	}
	
	onMounted(() => {
	  initEditor()
	});

测试 aceEditor 基础封装是否功能正常,方便后续扩展开发。

🔧 Ace 自定义语言扩展

Ace 编辑器本身不支持直接自定义语言,但支持通过扩展语言模式的方式实现对自定义语言的支持。在 Ace 中,语言模式是指将文本分解为标记,定义了每个标记的样式和语法高亮规则,以此来实现语法高亮、代码折叠、自动完成等功能。
想要自定义新增语言模型,首先需要了解如何定义一个 mode (语言模式),可参考官方文档 Ace - The High Performance Code Editor for the Web (c9.io
1、在 node_modules\ace-builds\src-noconflict 下新增一个 mode-mylang.js 的文件,定义语言模式、语言高亮规则及代码提示。

	ace.define('ace/mode/mylang', ['require', 'exports', 'module', 'ace/lib/oop', 'ace/mode/text', 'ace/mode/custom_highlight_rules'], (require, exports, module) => {
	  const oop = require('ace/lib/oop');
	  const TextMode = require('ace/mode/text').Mode;
	  const { MyLangHighlightRules } = require('ace/mode/mylang_highlight_rules');
	  const { Tokenizer } = require('ace/tokenizer');
	
	  const Mode = function () {
	    this.HighlightRules = MyLangHighlightRules;
	    this.$tokenizer = new Tokenizer(new MyLangHighlightRules().getRules());
	  };
	
	  oop.inherits(Mode, TextMode);
	
	  (function () {
	    // 加载css 样式设置,以便控制自定义语言关键词高亮颜色
	    const dom = require('ace/lib/dom');
	    dom.importCssString(exports.cssText, exports.cssClass);
	  }).call(Mode.prototype);
	
	  (function () {
	    // 添加代码提示
	    this.completer = {
	      getCompletions(editor, session, pos, prefix, callback) {
	        const wordList = [
	          'hello',
	          'world',
	          'AceEditor',
	          'hello world this is AceEditor',
	        ];
	        callback(
	          null,
	          wordList.map((word) => ({
	            caption: word,
	            value: word,
	            meta: 'mylang', // 自定义语言标识
	          })),
	        );
	      },
	    };
	  }.call(Mode.prototype));
	
	  exports.Mode = Mode;
	});

2、接着定于语法高亮规则, 高亮规则里面定义一系列的规则(Rules), 每个规则描述了如何处理输入文本中的单个字符序列。Ace Editor 中的规则是由 Tokenizer 对象处理的。Tokenizer 是 Ace Editor 内置的一种基于正则表达式的解析器,用于将输入文本转换为标记(Token)流。标记是 Ace Editor 中的基本元素,它们由不同类型的 token 组成,例如:keyword、comment、string 等等。

	ace.define(
	  'ace/mode/mylang_highlight_rules',
	  ['require', 'exports', 'module', 'ace/lib/oop', 'ace/mode/text_highlight_rules'],
	  (require, exports, module) => {
	    const oop = require('ace/lib/oop');
	    const { TextHighlightRules } = require('ace/mode/text_highlight_rules');
	
	    const MyLangHighlightRules = function () {
	      // 定义高亮规则
	      const keywordList = 'let|const|function|world'; // 高亮关键词
	      this.$rules = {
	        start: [
	          {
	            token: 'keyword',
	            regex: `\\b(?:${keywordList})\\b`,
	          },
	          {
	            token: 'string',
	            regex: '".*?"',
	          },
	          {
	            token: 'constant',
	            regex: /\b(true|false|null)\b/,
	          },
	          {
	            token: 'comment',
	            regex: /\/\/.*$/,
	          },
	          {
	            token: 'comment',
	            start: '/\\*',
	            end: '\\*/',
	          },
	          {
	            token: 'mylang',
	            regex: '\\b(?:hello|world|AceEditor)\\b',
	          },
	        ],
	      };
	    };
	
	    oop.inherits(MyLangHighlightRules, TextHighlightRules);
	
	    exports.MyLangHighlightRules = MyLangHighlightRules;
	  },
	);

3、自定义特殊高亮颜色,比如我们想对 true | false | null 进行特殊颜色高亮,只需更具规则中 “token” 属性值,以 .ace_[属性值] 形式定义css。
例:

	/* 自定义语言,匹配不同类型关键词高亮颜色 */
	.ace_constant {
	  color: #FF00FF;
	  font-weight: bold;
	} 

4、最后引入我们自定义语言即可,可直接在option中配置即可

	mode: 'ace/mode/mylang',

🏁 源码

插件本身还有很多配置和 api , 感兴趣的可以继续探索,本文旨在对初阶自定义功能实现讲解,后续会慢慢更新更深层次自定义方案。

	<template>
	  <div class="aceEditor" ref="aceEditor"></div>
	</template>
	
	<script lang="ts" setup>
	import { onBeforeUnmount, onMounted, ref, watch } from 'vue';
	import * as ace from 'ace-builds';
	
	import "ace-builds/src-noconflict/mode-javascript"; // 语言模式
	import "ace-builds/src-noconflict/theme-monokai" // 主题
	import "ace-builds/src-noconflict/ext-language_tools"; // 语法提示
	import "ace-builds/src-noconflict/snippets/javascript"; // 语法段提示模块
	
	// 自定义语言
	import "ace-builds/src-noconflict/mode-mylang"; // 此模块需对应目录创建
	
	const props = withDefaults(defineProps<{
	  value: string,
	}>(), {
	})
	
	const emits = defineEmits(['update:value']);
	
	let editor: any = null;
	const aceEditor = ref<string | Element>('')
	
	// 编辑器默认配置项
	const options = {
	  theme: 'ace/theme/monokai',
	  //mode: 'ace/mode/javascript',
	  mode: 'ace/mode/mylang',
	  tabSize: 1,
	  maxLines: 25,
	  minLines: 25,
	  showPrintMargin: false,
	  fontSize: 14,
	  printMarginColumn: 20,
	  useWorker: false,
	  showLineNumbers: true, // 显示行号
	  showGutter: true, // 显示行号区域
	  highlightActiveLine: false,
	  highlightSelectedWord: false, // 高亮选中文本
	  readOnly: false, // 控制编辑器是否只读
	  enableSnippets: true, // 启用代码段
	  enableLiveAutocompletion: true, // 启用实时自动完成
	  enableBasicAutocompletion: true,  // 启用基本自动完成
	}
	
	// 初始化编辑器
	const initEditor = () => {
	  if (editor) editor.destroy();
	
	  // 初始化
	  editor = ace.edit(aceEditor.value, options);
	
	  // 切换自动换行
	  editor.getSession().setUseWrapMode(true);
	
	  // 支持双向绑定
	  editor.setValue(props.value ? props.value : "");
	  editor.on("change", () => {
	    emits("update:value", editor.getValue());
	  })
	}
	
	watch(
	  () => props.value,
	  (newProps) => {
	    //解决光标移动问题
	    const position = editor.getCursorPosition();
	    editor.getSession().setValue(newProps);
	    editor.clearSelection();
	    editor.moveCursorToPosition(position);
	  }
	);
	
	onMounted(() => {
	  initEditor()
	});
	
	onBeforeUnmount(() => {
	  editor.destroy();
	});
	
	</script>
	<style>
	.aceEditor {
	  width: 500px;
	  height: 500px;
	}
	
	/* 自定义语言,匹配不同类型关键词高亮颜色 */
	.ace_constant {
	  color: #FF00FF;
	  font-weight: bold;
	}
	</style>

📖 相关文档及网站

官网: https://ace.c9.io
GitHub: https://github.com/ajaxorg/ace
Vue3 ace组件: https://github.com/CarterLi/vue3-ace-editor
在线测试: https://ace.c9.io/build/kitchen-sink.html

创作不易,如果本篇文章你觉得还不错的话求个赞😜😜😜文章来源地址https://www.toymoban.com/news/detail-797321.html

到了这里,关于【超详细】 对 AceEditor 二次封装 及 自定义扩展语言实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • vue3 ts element plus form表单二次封装详细步骤 (附参数、类型详细介绍及简单使用示例)

    上篇table 表格封装 讲到项目中经常会用到 table 表格,所以做了封装。当然,form 表单使用的频率依然很高,所以和封装 table 表格的思路相似,对 form 表单也做了一个二次封装的组件。 查看国内预览站 查看国外预览站 1. EasyForm 表单组件封装 src/components/EasyForm/index.vue Form 表单

    2024年02月07日
    浏览(53)
  • NUXT3.0实现网络请求二次封装

    😊最近在开发基于nuxt3.0的项目,看了官网的网络请求,感觉不太适合,就自己基于官网的 useFetch() 方法封装了一个网络请求,下面开始实现封装。 我选择在 composables 目录中新建 http.ts 。 composables 是官方默认的插件目录, 官方描述:Nuxt 3使用 composables/ 目录使用auto-imports自

    2024年02月03日
    浏览(26)
  • 【vue2小知识】实现axios的二次封装

    🥳博       主: 初映CY的前说(前端领域) 🌞个人信条: 想要变成得到,中间还有做到! 🤘 本文核心 :在vue2中实现axios的二次封装 目录 一、平常axios的请求发送方式 二、axios的一次封装 三、axios的二次封装  四、总结 【前言】我们在使用axios发送请求的时候,如果是直

    2024年02月01日
    浏览(32)
  • VIVADO 自定义封装ip核(超详细)

    版本:vivado 2018.3 vivado 自定义封装ip核,可以将ip核封装成带AXI总线,也可将ip核封装成不带AXI总线。 本次设计介绍,如何将当前工程封装成ip核(不带AXI总线) 目录 一、工程文件介绍 二、封装IP核步骤 三、将IP核添加到ip核库  一、工程文件介绍 1. 创建如下的工程: 2. 工程

    2024年02月03日
    浏览(53)
  • C++数据封装以及定义结构的详细讲解鸭~

    名字:阿玥的小东东   博客主页:阿玥的小东东的博客_CSDN博客-pythonc++高级知识,过年必备,C/C++知识讲解领域博主 目录 定义结构 访问结构成员 结构作为函数参数

    2024年02月04日
    浏览(32)
  • vue2+ant-design-vue a-select组件二次封装(支持单选/多选添加全选/分页(多选跨页选中)/自定义label)

    参数 说明 类型 默认值 v-model 绑定值 boolean / string / number/Array - mode 设置’multiple’\\\'tags’多选 (显示全选) String - optionSource 下拉数据源 Array - width select宽度(可以设置百分比或px) String 100% customLabel 是否自定义设置下拉label String - valueKey 传入的 option 数组中,要作为最终选择

    2024年02月08日
    浏览(30)
  • 在.NetCore中 DDD中基于mediatr实现领域事件并结合EFCore进行二次封装

    [源代码地址https://github.com/junkai-li/NetCoreKevin] 基于NET6搭建跨平台WebApi架构支持单点登录、多缓存、自动任务、分布式、多租户、日志、授权和鉴权 、网关 注册与发现、CAP集成事件、领域事件、 docker部署 **首要要理解什么是领域事件?** 领域事件是指发生在特定领域中的事件

    2024年02月02日
    浏览(29)
  • LLM大语言模型(九):LangChain封装自定义的LLM

    想基于ChatGLM3-6B用LangChain做LLM应用,需要先了解下LangChain中对LLM的封装。本文以一个hello world的封装来示例。 继承关系:BaseLanguageModel——》BaseLLM——》LLM 简化和LLM的交互 _call抽象方法定义 BaseLLM类其实有两个abstract方法:_generate方法和_llm_type方法 注意:LLM类仅实现了_genera

    2024年04月10日
    浏览(34)
  • vue3+ts+elementui-plus二次封装树形表格实现不同层级展开收起的功能

    一、TableTreeLevel组件 

    2024年02月15日
    浏览(47)
  • 帝国CMS调用自定义列表名称的方法(简单二次开发实现)

    本文讲述了帝国CMS调用自定义列表名称的方法,yii666在这里提供了2种实现方法,涉及针对帝国CMS底层代码的修改。具体如下: 一、问题描述: 需要调出自定义列表名称,如下图所示: 而使用帝国CMS原有的标签只能调用网页标题,而无法调出列表名称 二、解决方法: 方法一

    2023年04月20日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包