Vuetify 对话框 - 在 ACE 编辑器中格式化 2.5MB 的 XML 非常慢
Vuetify dialog - extremely slow formatting 2.5MB of XML in ACE editor
我有一个 Vue/Vuefify 项目,我正在使用 vkbeutify 库格式化 XML,然后在 Ace 编辑器中显示它。编辑器在模态对话框(全屏模式)中打开,当 XML 的数量很少时,一切都运行良好。
我必须解析其中的大约 2.5MB+(在 Notepad++ 中格式化时大约 2,500,000 个字符),然后 Ace 变得无法使用(它最终显示 XML,但需要很长时间)。
我创建了一个带有文本区域和编辑器的简单测试页面,格式化和显示速度非常快。该页面与此完全相同:https://www.webtoolkitonline.com/xml-formatter.html(这使用 Ace 和 vkbeautify 来格式化 xml)
我尝试在将 XML 传递给子对话框之前在文本区域中对其进行预格式化,尝试颠覆 Vue 并通过获取 DOM 在 mounted() 函数中填充编辑器容器内容直接。
独立测试页:
<!DOCTYPE html>
<html lang="en">
<head>
<title>ACE in Action</title>
<style type="text/css" media="screen">#editor {position: absolute;top: 0;right: 0;bottom: 0;left: 0;}</style>
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<script src="https://pagecdn.io/lib/ace/1.4.5/ace.js" integrity="sha256-5Xkhn3k/1rbXB+Q/DX/2RuAtaB4dRRyQvMs83prFjpM=" crossorigin="anonymous"></script>
<script src="https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/vkbeautify/vkbeautify.0.99.00.beta.js"></script>
</head>
<body>
<div style="position: relative; width: 100%; height: 500px;">
<div id="editor">
<tag><inner_tag>sce to aux</inner_tag></tag>
</div>
</div>
<div>
<form>
<textarea id="xml"><?xml version="1.0" encoding="UTF-8"?><tag><inner_tag>hi</inner_tag></tag></textarea>
<fieldset><input type="button" id="format" value="Format"></fieldset>
</form>
</div>
<script>
var editor = ace.edit("editor");
editor.setTheme("ace/theme/cobalt");
editor.session.setMode("ace/mode/xml");
$( function() {
$( "#format").click(
async function() {
var content = document.getElementById("xml").value;
try {
editor.setValue( content );
editor.setValue( vkbeautify.xml( editor.getValue() ) );
} catch( err ) {
alert( "Your document is invalid" );
}
}
);
});
</script>
</body>
</html>
Vue 组件:
<template>
<div>
<b>Open In Editor </b>
<v-btn icon color="transparent" depressed small @click="openInEditor()"><v-icon color="#666666">mdi-pencil</v-icon>
</v-btn>
<v-dialog v-model="showAceEditorModal" fullscreen hide-overlay eager>
<v-card>
<v-toolbar dark color="primary">
<v-btn icon dark @click="closeAceEditor">
<v-icon>mdi-close</v-icon>
</v-btn>
<v-toolbar-title>{{title}}</v-toolbar-title>
<v-card-text v-if="editable===false"> Read Only Mode - you won't be able to edit or save changes</v-card-text>
<v-spacer></v-spacer>
<v-toolbar-items>
<v-btn dark text @click="sendEditsToParent">
{{ closeLabelTxt }}
</v-btn>
</v-toolbar-items>
</v-toolbar>
<div :id=editorIdX >
{{ v }}
</div>
<div id="test"></div>
</v-card>
</v-dialog>
</div>
</template>
<script>
import * as ace from '@/assets/js/ace/src-min-noconflict/ace.js';
import * as v from '@/assets/js/ace/vkbeautify.js';
export default {
name: "AceEditor",
props:['title', 'editable', 'value', 'originalItem', 'editorIdX'],
data(){
return {
v : "",
oldItem : this.originalItem,
showAceEditorModal: false
}
},
computed : {
closeLabelTxt : function (){
return this.editable?"Save":"Close Me";
}
},
mounted(){
this.v = document.getElementById("textArea_0").value
document.getElementById("test").innerText = document.getElementById("textArea_0").value
},
methods:{
openInEditor(){
this.editorId = this.editorIdX;
this.editor = ace.edit( this.editorIdX );
if( this.editable === false ){
this.editor.setReadOnly( true );
}
// deprecation fix
this.editor.$blockScrolling = Infinity;
// ignore doctype warnings
const session = this.editor.getSession();
session.on("changeAnnotation", () => {
const a = session.getAnnotations();
const b = a.slice(0).filter( (item) => item.text.indexOf('DOC') == -1 );
if(a.length > b.length) session.setAnnotations(b);
});
// editor options
this.options = this.options || {};
// opinionated option defaults
this.options.maxLines = this.options.maxLines || Infinity;
this.options.printMargin = this.options.printMargin || false;
this.options.highlightActiveLine = this.options.highlightActiveLine || false;
// hide cursor
if(this.options.cursor === 'none' || this.options.cursor === false){
this.editor.renderer.$cursorLayer.element.style.display = 'none';
delete this.options.cursor;
}
// add missing mode and theme paths
if(this.options.mode && this.options.mode.indexOf('ace/mode/')===-1) {
this.options.mode = `ace/mode/${this.options.mode}`;
}
if(this.options.theme && this.options.theme.indexOf('ace/theme/')===-1) {
this.options.theme = 'ace/theme/${this.options.theme}';
}
this.editor.setOptions(this.options);
this.showAceEditorModal = true;
},
closeAceEditor(){
this.showAceEditorModal = false;
},
sendEditsToParent(){
if( this.editor.getReadOnly() === false ){
this.$emit('editedItem', [ {"editedItem": this.editor.getValue() }, {"originalItem":this.oldItem}]);
}
this.showAceEditorModal = false
},
reformatContent(){
let x = this.editor.session.getValue();
this.editor.session.setValue("");
x = vkbeautify.xml( x );
this.editor.session.setValue( x );
}
}
}
</script>
发生这种情况是因为您通过禁用编辑器的虚拟屏幕优化将 maxLines
设置为 Infinity
。 maxLines
适用于小于 window 高度的小片段。
我有一个 Vue/Vuefify 项目,我正在使用 vkbeutify 库格式化 XML,然后在 Ace 编辑器中显示它。编辑器在模态对话框(全屏模式)中打开,当 XML 的数量很少时,一切都运行良好。
我必须解析其中的大约 2.5MB+(在 Notepad++ 中格式化时大约 2,500,000 个字符),然后 Ace 变得无法使用(它最终显示 XML,但需要很长时间)。
我创建了一个带有文本区域和编辑器的简单测试页面,格式化和显示速度非常快。该页面与此完全相同:https://www.webtoolkitonline.com/xml-formatter.html(这使用 Ace 和 vkbeautify 来格式化 xml)
我尝试在将 XML 传递给子对话框之前在文本区域中对其进行预格式化,尝试颠覆 Vue 并通过获取 DOM 在 mounted() 函数中填充编辑器容器内容直接。
独立测试页:
<!DOCTYPE html>
<html lang="en">
<head>
<title>ACE in Action</title>
<style type="text/css" media="screen">#editor {position: absolute;top: 0;right: 0;bottom: 0;left: 0;}</style>
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<script src="https://pagecdn.io/lib/ace/1.4.5/ace.js" integrity="sha256-5Xkhn3k/1rbXB+Q/DX/2RuAtaB4dRRyQvMs83prFjpM=" crossorigin="anonymous"></script>
<script src="https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/vkbeautify/vkbeautify.0.99.00.beta.js"></script>
</head>
<body>
<div style="position: relative; width: 100%; height: 500px;">
<div id="editor">
<tag><inner_tag>sce to aux</inner_tag></tag>
</div>
</div>
<div>
<form>
<textarea id="xml"><?xml version="1.0" encoding="UTF-8"?><tag><inner_tag>hi</inner_tag></tag></textarea>
<fieldset><input type="button" id="format" value="Format"></fieldset>
</form>
</div>
<script>
var editor = ace.edit("editor");
editor.setTheme("ace/theme/cobalt");
editor.session.setMode("ace/mode/xml");
$( function() {
$( "#format").click(
async function() {
var content = document.getElementById("xml").value;
try {
editor.setValue( content );
editor.setValue( vkbeautify.xml( editor.getValue() ) );
} catch( err ) {
alert( "Your document is invalid" );
}
}
);
});
</script>
</body>
</html>
Vue 组件:
<template>
<div>
<b>Open In Editor </b>
<v-btn icon color="transparent" depressed small @click="openInEditor()"><v-icon color="#666666">mdi-pencil</v-icon>
</v-btn>
<v-dialog v-model="showAceEditorModal" fullscreen hide-overlay eager>
<v-card>
<v-toolbar dark color="primary">
<v-btn icon dark @click="closeAceEditor">
<v-icon>mdi-close</v-icon>
</v-btn>
<v-toolbar-title>{{title}}</v-toolbar-title>
<v-card-text v-if="editable===false"> Read Only Mode - you won't be able to edit or save changes</v-card-text>
<v-spacer></v-spacer>
<v-toolbar-items>
<v-btn dark text @click="sendEditsToParent">
{{ closeLabelTxt }}
</v-btn>
</v-toolbar-items>
</v-toolbar>
<div :id=editorIdX >
{{ v }}
</div>
<div id="test"></div>
</v-card>
</v-dialog>
</div>
</template>
<script>
import * as ace from '@/assets/js/ace/src-min-noconflict/ace.js';
import * as v from '@/assets/js/ace/vkbeautify.js';
export default {
name: "AceEditor",
props:['title', 'editable', 'value', 'originalItem', 'editorIdX'],
data(){
return {
v : "",
oldItem : this.originalItem,
showAceEditorModal: false
}
},
computed : {
closeLabelTxt : function (){
return this.editable?"Save":"Close Me";
}
},
mounted(){
this.v = document.getElementById("textArea_0").value
document.getElementById("test").innerText = document.getElementById("textArea_0").value
},
methods:{
openInEditor(){
this.editorId = this.editorIdX;
this.editor = ace.edit( this.editorIdX );
if( this.editable === false ){
this.editor.setReadOnly( true );
}
// deprecation fix
this.editor.$blockScrolling = Infinity;
// ignore doctype warnings
const session = this.editor.getSession();
session.on("changeAnnotation", () => {
const a = session.getAnnotations();
const b = a.slice(0).filter( (item) => item.text.indexOf('DOC') == -1 );
if(a.length > b.length) session.setAnnotations(b);
});
// editor options
this.options = this.options || {};
// opinionated option defaults
this.options.maxLines = this.options.maxLines || Infinity;
this.options.printMargin = this.options.printMargin || false;
this.options.highlightActiveLine = this.options.highlightActiveLine || false;
// hide cursor
if(this.options.cursor === 'none' || this.options.cursor === false){
this.editor.renderer.$cursorLayer.element.style.display = 'none';
delete this.options.cursor;
}
// add missing mode and theme paths
if(this.options.mode && this.options.mode.indexOf('ace/mode/')===-1) {
this.options.mode = `ace/mode/${this.options.mode}`;
}
if(this.options.theme && this.options.theme.indexOf('ace/theme/')===-1) {
this.options.theme = 'ace/theme/${this.options.theme}';
}
this.editor.setOptions(this.options);
this.showAceEditorModal = true;
},
closeAceEditor(){
this.showAceEditorModal = false;
},
sendEditsToParent(){
if( this.editor.getReadOnly() === false ){
this.$emit('editedItem', [ {"editedItem": this.editor.getValue() }, {"originalItem":this.oldItem}]);
}
this.showAceEditorModal = false
},
reformatContent(){
let x = this.editor.session.getValue();
this.editor.session.setValue("");
x = vkbeautify.xml( x );
this.editor.session.setValue( x );
}
}
}
</script>
发生这种情况是因为您通过禁用编辑器的虚拟屏幕优化将 maxLines
设置为 Infinity
。 maxLines
适用于小于 window 高度的小片段。