ace-builds&vue3-ace-editor代码编辑器+弹窗放大功能

下载:npm install --save-dev vue3-ace-editor
封装:
  • components文件夹下新建aceBuilds文件夹
  • 新建ace.config.js文件配置插件所需要的功能
  • 新建aceEditor.vue文件初始化并封装插件
  • 新建aceEditorFullScrenn.vue文件基于aceEditor.vue文件再次封装,实现弹框编辑
ace.config.js配置项
import ace from 'ace-builds';

import modeJsonUrl from 'ace-builds/src-noconflict/mode-json?url';
ace.config.setModuleUrl('ace/mode/json', modeJsonUrl);

import modeJavascriptUrl from 'ace-builds/src-noconflict/mode-javascript?url';
ace.config.setModuleUrl('ace/mode/javascript', modeJavascriptUrl);

import modeHtmlUrl from 'ace-builds/src-noconflict/mode-html?url';
ace.config.setModuleUrl('ace/mode/html', modeHtmlUrl);

import modeYamlUrl from 'ace-builds/src-noconflict/mode-yaml?url';
ace.config.setModuleUrl('ace/mode/yaml', modeYamlUrl);

import themeGithubUrl from 'ace-builds/src-noconflict/theme-github?url';
ace.config.setModuleUrl('ace/theme/github', themeGithubUrl);

import themeChromeUrl from 'ace-builds/src-noconflict/theme-chrome?url';
ace.config.setModuleUrl('ace/theme/chrome', themeChromeUrl);

import themeMonokaiUrl from 'ace-builds/src-noconflict/theme-monokai?url';
ace.config.setModuleUrl('ace/theme/monokai', themeMonokaiUrl);

import workerBaseUrl from 'ace-builds/src-noconflict/worker-base?url';
ace.config.setModuleUrl('ace/mode/base', workerBaseUrl);

import workerJsonUrl from 'ace-builds/src-noconflict/worker-json?url';
ace.config.setModuleUrl('ace/mode/json_worker', workerJsonUrl);

import workerJavascriptUrl from 'ace-builds/src-noconflict/worker-javascript?url';
ace.config.setModuleUrl('ace/mode/javascript_worker', workerJavascriptUrl);

import workerHtmlUrl from 'ace-builds/src-noconflict/worker-html?url';
ace.config.setModuleUrl('ace/mode/html_worker', workerHtmlUrl);

import workerYamlUrl from 'ace-builds/src-noconflict/worker-yaml?url';
ace.config.setModuleUrl('ace/mode/yaml_worker', workerYamlUrl);

import snippetsHtmlUrl from 'ace-builds/src-noconflict/snippets/html?url';
ace.config.setModuleUrl('ace/snippets/html', snippetsHtmlUrl);

import snippetsJsUrl from 'ace-builds/src-noconflict/snippets/javascript?url';
ace.config.setModuleUrl('ace/snippets/javascript', snippetsJsUrl);

import snippetsYamlUrl from 'ace-builds/src-noconflict/snippets/yaml?url';
ace.config.setModuleUrl('ace/snippets/javascript', snippetsYamlUrl);

import snippetsJsonUrl from 'ace-builds/src-noconflict/snippets/json?url';
ace.config.setModuleUrl('ace/snippets/json', snippetsJsonUrl);

import 'ace-builds/src-noconflict/ext-language_tools';
ace.require("ace/ext/language_tools");
aceEditor.vue封装代码编辑器
<template>
  <div class="editor-container" :style="{ width: cW, height: cH }">
    <slot></slot>
    <div
      ref="editorEle"
      class="editAceWrap"
      :class="className"
      :style="{ width: cW, height: cH }"
    ></div>
  </div>
</template>
<script setup name="VueAceEditor">
import ace from 'ace-builds';
import { computed, onBeforeUnmount, watch } from "vue";
const { proxy } = getCurrentInstance();
let props = defineProps({
  lang: {
    type: String,
    default: "",
  },
  theme: {
    type: String,
    default: "monokai",
  },
  fontSize: {
    type: Number,
    default: 14,
  },
  content: {
    type: String,
    default: "",
  },
  width: {
    type: [String, Number],
    default: "100%",
  },
  height: {
    type: [String, Number],
    default: "100%",
  },
  className: {
    type: String,
    default: "vue-ace-editor",
  },
  options: {
    type: Object,
    default: () => ({
    enableBasicAutocompletion: true,
    enableLiveAutocompletion: true,
    enableSnippets: true,
    enableEmmet: true,
    useElasticTabstops: true,
    enableChromevoxEnhancements: true,
    enableLinking: true,
    spellcheck: true,
    tabSize: 2
  }),
  },
  wrap: {
    type: String,
    default: "free",
  },
  readonly: {
    type: Boolean,
    default: false,
  },
  showPrintMargin: {
    type: Boolean,
    default: false,
  },
});
let editor = ref(null);
let session = ref(null);

const cH = computed(() => {
  if (typeof props.height === "number") return props.height + "px";
  if (typeof props.height === "string") return props.height;
  return "";
});
let cW = computed(() => {
  if (typeof props.width === "number") return props.width + "px";
  if (typeof props.width === "string") return props.width;
  return "";
});
let emits = defineEmits([
  "init",
  "onFocus",
  "update:content",
  "onBlur",
  "onChange",
  "onInput",
  "onCopy",
  "onPaste",
]);
watch(()=>props.fontSize,()=>{
  setFontSize();
})
watch(()=>props.theme,()=>{
  setTheme();
})
watch(()=>props.lang,()=>{
  setMode();
})
watch(()=>props.height,()=>{
  nextTick(() => {
    resize();
  });
})
watch(()=>props.width,()=>{
  nextTick(() => {
    resize();
  });
})
watch(()=>props.content,()=>{
  nextTick(() => {
    setValue();
  });
})

// watch: {
//   fontSize() {
//     this.setFontSize();
//   },
//   theme() {
//     this.setTheme();
//   },
//   lang() {
//     this.setMode();
//   },
//   height() {
//     this.$nextTick(() => {
//       this.resize();
//     });
//   },
//   width() {
//     this.$nextTick(() => {
//       this.resize();
//     });
//   },
//   content(val) {
//     this.setValue();
//   }
// },
onBeforeUnmount(() => {
  editor.destroy();
  editor.container.remove();
});
onMounted(() => {
  init();
});

function init() {
  editor = ace.edit(proxy.$refs.editorEle);
  editor.$blockScrolling = Infinity;
  session.value = editor.getSession();
  emits("init", editor);
  setMode();
  setTheme();
  setFontSize();
  setOptions();
  setOption();
  setValue();
  setReadonly();
  setShowPrintMargin();
  editor.on("focus", onFocus);
  editor.on("blur", onBlur);
  editor.on("copy", onCopy);
  editor.on("paste", onPaste);
  editor.on("change", onChange);
  editor.on("input", onInput);
}
function setMode() {
  session.value.setMode(`ace/mode/${props.lang}`);
  session.value.setUseWrapMode(true);
  return editor;
}
function setTheme() {
  editor.setTheme(`ace/theme/${props.theme}`);
  return editor;
}
function setFontSize() {
  editor.setFontSize(props.fontSize);
  return editor;
}
function setValue() {
  session.value.setValue(props.content);
  return editor;
}
function getValue() {
  return editor.getValue();
}
function setOptions() {
  editor.setOptions(props.options);
  return editor;
}
function setOption() {
  editor.setOption("wrap", props.wrap);
  return editor;
}
function setReadonly() {
  editor.setReadOnly(props.readonly);
  return editor;
}
function setShowPrintMargin() {
  editor.setShowPrintMargin(props.showPrintMargin);
  return editor;
}
function setCompleteData(data) {
  ace.acequire("ace/ext/language_tools").addCompleter({
    getCompletions(editor, session, pos, prefix, callback) {
      return callback(null, data);
    },
  });
}
function setAutocomplete() {
  editor.execCommand("startAutocomplete");
  return editor;
}
function getRowCol() {
  return editor.selection.getCursor();
}
function onFocus() {
  emits("onFocus", editor);
}
function onBlur() {
  emits("update:content", getValue());
  emits("onBlur", editor);
}
function onChange() {
  emits("onChange", editor);
}
function onInput() {
  emits("onInput", editor);
}
function onCopy() {
  emits("onCopy", editor);
}
function onPaste() {
  emits("onPaste", editor);
}

function resize() {
  editor.resize();
  return editor;
}
function setRange(startRow, startCol, endRow, endCol) {
  const Range = ace.acequire("ace/range").Range;
  return new Range(startRow, startCol, endRow, endCol);
}
/**
 * @param(r) type:new Range()
 */
function getTextRange(r) {
  return session.value.getTextRange(r);
}
function save(storageName) {
  localStorage[storageName] = getValue();
  session.value.getUndoManager().markClean();
  return editor;
}
function undo() {
  editor.undo();
  return editor;
}
function redo() {
  editor.redo();
  return editor;
}
defineExpose({
  session,
  setValue,
  getValue
})
</script>
<style scoped>
.editor-container {
  position: relative;
}
.editAceWrap{
  /* touch-action: none; */
}
:deep(.ace_scrollbar-inner){
  background-color: #272822;
}
:deep(.ace_scrollbar-v){
  background-color: #fff;
}
</style>
aceEditorFullScrenn.vue文件基于aceEditor.vue文件再次封装,实现弹框编辑
<template>
  <el-row style="width: 100%">
    <el-dialog
      ref="dialog"
      append-to-body
      :close-on-click-modal="false"
      draggable
      width="900px"
      :title="title"
      v-model="isFullscreen"
      top="8vh"
    >
      <vue-ace-editor
        ref="aceEditor1"
        v-bind="$attrs"
        :content="innerValue"
        :height="dialogBodyHeight"
        :readonly="disabled"
        @onBlur="aceEditorInput"
      />
      <template #footer>
        <span class="dialog-footer">
          <el-button type="primary" @click="isFullscreen = false"
            >关 闭</el-button
          >
        </span>
      </template>
    </el-dialog>
    <el-col class="flex-sub">
      <vue-ace-editor
        ref="aceEditor2"
        v-bind="$attrs"
        :content="innerValue"
        :readonly="disabled"
        @onBlur="aceEditorInput"
      />
    </el-col>
    <el-col v-if="!noFullScreen" class="text-right full-screen-btn">
      <el-button
        icon="FullScreen"
        type="text"
        class="padding-0 large"
        title="在新窗口显示"
        @click="isFullscreen = true"
      />
    </el-col>
  </el-row>
</template>

<script setup name="FullScreenAceEditor">
import "./ace.config.js";
const { proxy } = getCurrentInstance();
let props = defineProps({
  title: {
    type: String,
    default: "",
  },
  content: {
    type: String,
    default: "",
  },
  noFullScreen: {
    type: Boolean,
    default: false,
  },
  disabled: {
    type: Boolean,
    default: false,
  },
});
let isFullscreen = ref(false);
let innerValue = ref("");
let dialogBodyHeight = ref(0);
let emits = defineEmits(["update:content"]);
let inputValue = ref("");
watch(
  () => props.content,
  (newValue) => {
    nextTick(() => {
      inputValue.value = newValue;
      proxy.$refs.aceEditor2.session.setValue(newValue);
    });
  },
  { immediate: true }
);
watch(inputValue, (val) => {
  emits("update:content", val);
});
watch(isFullscreen, (val) => {
  if (val) {
    nextTick(() => {
      // const { height } = proxy.$refs.dialog.$el.getBoundingClientRect();
      // if (height) {
      //   dialogBodyHeight.value = height - 80;
      // }
      dialogBodyHeight.value = 600;
      proxy.$refs.aceEditor1.session.setValue(inputValue.value);
    });
  }
});

function aceEditorInput(editor) {
  emits("update:content", editor.getValue());
}
function resize() {
  proxy.$refs?.aceEditor1?.resize?.();
  proxy.$refs?.aceEditor2?.resize?.();
}
</script>

<style lang="scss" scoped>
.full-screen-btn {
  width: 30px;
  position: absolute;
  right: 10px;
  top: -2px;
  z-index: 2000;
}
</style>
使用:
import FullScreenAceEditor from "@/components/vue-ace/full-screen-ace-editor";

            <full-screen-ace-editor
                lang="json"
                v-model:content="绑定值"
                height="300px"
                title="弹框标题"
              />

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值