javascript - 语法荧光笔无法更新文本
问题描述
我正在尝试使用 HTML 制作代码编辑器:
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='UTF-8'>
<meta http-equiv='X-UA-Compatible' content='IE=Edge'>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<link rel='stylesheet' href='style.css'>
</head>
<body>
<pre id='editor'><code contenteditable='true'></code></pre>
<script type='module'>
import { highlight } from './highlighter.js';
import { Caret } from './caret.js';
(() =>
{
const editor = document.querySelector('#editor code');
const caret = new Caret(editor);
highlight(editor);
editor.addEventListener('input', e =>
{
highlight(editor);
e.preventDefault();
});
editor.addEventListener('keydown', e =>
{
const TAB = 9;
const ENTER = 13;
switch (e.keyCode)
{
// ...
}
});
})();
</script>
</body>
</html>
荧光笔.js:
import { Caret } from './caret.js';
export function highlight(editor)
{
// ...
const NORM = '#E6E6FA';
// ...
const Highlighter = {
source: editor.innerText,
start: 0,
curr: 0,
// ...
fin()
{
return this.curr >= this.source.length;
},
advance()
{
return this.source[this.curr++];
},
// ...
scan()
{
let result = '';
this.start = this.curr;
if (this.fin())
{
return null;
}
const char = this.advance();
let color = NORM;
switch (char)
{
// ...
}
return {
color,
text: this.source.substring(this.start, this.curr),
};
},
};
let result = '';
const caret = new Caret(editor);
const save = caret.getPos();
for (;;)
{
const lexeme = Highlighter.scan();
if (lexeme === null)
{
break;
}
const chars = lexeme.text.split('').map(
x => `<span style='color: ${lexeme.color};'>${x}</span>`);
result += chars.join('');
}
editor.innerHTML = result;
caret.setPos(save);
};
基本上,它获取用户代码的文本内容,对其进行扫描以生成带有颜色数据的词位,将这些词位拆分为带有颜色的 <span> 标记中的字符,然后将这些 <span> 附加到一个字符串中编辑器的innerHTML被更新为,最后将用户的光标放回原来的位置;这是在输入时完成的。但是有一个问题:如果用户输入速度太快,他们输入的文本可能会加倍。我尝试使用其他类型的事件侦听器来解决这个问题,并尝试简单地使用 setInterval,但它根本无法正常工作。
解决方案
从你所描述的
如果用户输入太快
highlight()
并看到每次更改input
元素时都会调用计算量大的函数
editor.addEventListener('input', e => {
highlight(editor); // <--
e.preventDefault();
});
我建议取消该调用以突出显示。这是 debouncing 的一个很好的解释器。
尝试这样的事情:
// Vanilla debounce: https://gist.github.com/peduarte/7ee475dd0fae1940f857582ecbb9dc5f
function debounce(func, wait = 100) {
let timeout;
return function(...args) {
clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(this, args);
}, wait);
};
}
// ...
// adjust delay to find a balance between responsiveness and performance
const delay = 500;
const runHighlight = () => highlight(editor);
const debouncedHighlight = debounce(runHighlight, delay);
editor.addEventListener('input', e => {
e.preventDefault();
debouncedHighlight();
});
推荐阅读
- c# - LINQ实体连接,同时使用修剪功能参数
- python - 如何检查列表中的单词是否至少包含一定数量的单个字母
- exception - Nexus OSS v3.12.1-01 groovy 脚本因嵌套 DB TX 而失败
- assembly - ATmega128A - 组装 RET 不返回但重新开始
- endianness - Ada Endianness 浮点数/整数
- java - 如何在字符序列中搜索模式?
- java - Ruby时区字符串到java时区
- .htaccess - Apache htaccess:如果 REQUEST_URI 与 cookie 值不匹配,则拒绝
- jenkins - Jenkins 离线安装插件
- python - 机器学习 + Python:绘制验证曲线