我有一个相当复杂的 Vue 组件,其中涉及一个 contenteditable
div。我想使用 Rangy 突出显示此 div 中的单词并添加其他标记,即使在编辑文本时也保留此标记。
最初,我打算发布一个问题,因为在某些时候处理额外的标记会使 contenteditable
div 不可编辑,我只是无法删除或添加字符。但是当我尝试设置代码片段时,我收到了另一条错误消息。
编辑 contenteditable
div 时,我预计会发生三件事:
在
storeIndexes
方法中,我为highlights
数组中的每个元素创建并存储范围。该方法称为@beforeinput
。此事件并非在所有浏览器中都可用,我使用的是 Chrome。接下来,我希望更新
contenteditable
div 内的文本。最后,应通过名为
@input
的restoreIndexes
方法恢复范围。
我知道我的代码不应该有任何可见的效果。我的问题是,在尝试编辑文本时出现错误消息: Rangy warning: Module SaveRestore: Marker element has been returned。无法恢复选择。
这里出了什么问题?
new Vue({
el: '#app',
data: {
currentHighlights: [],
highlights: [
{
start: 10,
end: 20
}
],
},
methods: {
// What happens just before an edit is applied
storeIndexes: function(event) {
// Create a new range object
let range = rangy.createRange();
// Get contenteditable element
let container = document.getElementById('text-with-highlights');
// Store all currently highlights and addd DOM markers
this.highlights.forEach(highlight => {
// Move range based on character indexes
range.selectCharacters(container, highlight.start, highlight.end);
// Set DOM markers and store range
this.currentHighlights.push(rangy.saveRange(range))
});
},
// What happens after an edit was made
restoreIndexes: function(event) {
// Create a new range object
let range = rangy.createRange();
// Get range based on character indexes
let container = document.getElementById('text-with-highlights');
this.currentHighlights.forEach(highlight => {
range.selectCharacters(container, highlight.start, highlight.end);
rangy.restoreRange(range);
});
this.currentHighlights = [];
},
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/rangy/1.3.0/rangy-core.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rangy/1.3.0/rangy-selectionsaverestore.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rangy/1.3.0/rangy-textrange.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id='app'>
<div @beforeinput='storeIndexes' @input='restoreIndexes' contenteditable id='text-with-highlights'>
Just some text to show the problem.
</div>
</div>
最佳答案
事实证明,这不是 Vue 问题,而是异步运行的代码之一:当 restoreIndexes
尝试恢复范围时,storeIndexes
尚未完成。
setTimeout
成功了。我不确定是否有比按随机间隔延迟该方法更好的方法,
// What happens after an edit was made
restoreIndexes: function(event) {
setTimeout(() => {
// Create a new range object
let range = rangy.createRange();
// Get range based on character indexes
let container = document.getElementById('text-with-highlights');
this.currentHighlights.forEach(highlight => {
range.selectCharacters(container, highlight.start, highlight.end);
rangy.restoreRange(range);
});
}, 10);
// Restore highlights
this.currentHighlights = [];
},
但是,我可以使用 v-runtime-template 完全摆脱我的 storeIndexes
方法。图书馆。这是 v-html
的替代方案,但也适用于以编程方式插入的元素,例如我的问题中的突出显示。
现在,我的突出显示仅对 $data
中的索引变化使用react,并且在更新 contenteditable
div 时我不需要手动移动它们。
关于javascript - 在 Vue 组件内使用 Rangey 恢复文本范围时出现错误消息 "Marker element has been removed",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57695397/