首页 > 解决方案 > 无法通过选择 api 在空格后选择刚刚写的单词

问题描述

这是我尝试过的

var div = document.getElementsByTagName("div")[0],
sel = window.getSelection(),
range = document.createRange();

function move() { 
     range.selectNodeContents(div);
     range.collapse(false);
     sel.removeAllRanges();
     sel.addRange(range);
}

div.addEventListener("keyup", function () { 
    if(this.innerHTML.match(/(keyword)[^\>keyword\<]/ig)) { 
        this.innerHTML = this.innerText.replace(/\</ig, "&lt;").replace(/\>/ig, "&gt;").replace(/keyword/ig, function(word) { 
            let x = "<span style='color: crimson'>"+word.toLowerCase()+"</span>";
            return x
        });
        move()
    }
    
})

标签: javascriptselectiontextselection

解决方案


注意事项

  • 新行:每个浏览器都以不同的方式执行此操作。有些换行在 a 中<div>,有些在 a 中<p>,我认为 IE 插入了一个<br>? 关键是,每个浏览器都不同。
  • 如果他们按Backspacekeyword文本内部怎么办?我们要删除突出显示吗?
  • 从技术上讲,插入符号(闪烁的文本插入点)算作大小为 0 的选择。所以当我们 时removeAllRanges,它会移动到文本的开头 --- 这不是我们想要的!
  • 这是一个糟糕的 API。

比赛计划

我对你想要发生的事情有点困惑,但你提到你想要一些类似于 Android / iOS 键盘自动完成建议的东西。所以,我们要做的就是提取插入符号之前的单词

为此,每当他们键入时,我们都需要:

  1. 找到插入符号的位置。
  2. 在文本中找到插入符号位置在内部/之后的单词。

找到插入符号位置

如前所述,插入符号只是开始和结束位置相同的范围。因此,我们可以获取第一个范围,通过检查这些数字是否相同来检查它是否不是选择,然后获取起始偏移量以获取插入符号位置:

let caret = window.getSelection().getRangeAt(0);
    
if (caret.startOffset == caret.endOffset) {
    console.log(caret.startOffset);
}

寻找相关词

如果我们得到插入符号的容器(不是它<div>本身,因为记住带有换行符的文本可能在嵌套元素中,等等),那么我们可以找到它的文本内容。这样,我们就可以找到插入符号所在的字符,然后向后循环,直到找到一个空格或点击元素的开头。这将为我们提供我们需要选择的文本。

let text = caret.startContainer.textContent;
let wordStart = 0;
let wordEnd = caret.startOffset;
for (let i = wordEnd; i >= 0; i--) {
    if (text[i] == " ") {
        wordStart = i;
        break;
    }
}
console.log(text.slice(wordStart, wordEnd));

把它们放在一起

let editor = document.getElementById("editor");
let suggestions = document.getElementById("suggestions");

editor.addEventListener("keyup", function () {
    let caret = window.getSelection().getRangeAt(0);
    
    // Is it only a caret --- e.g. they have no other text selected
    if (caret.startOffset == caret.endOffset) {
        // Find the start point: work backwards from the caret until
        // we find a space character.
        let text = caret.startContainer.textContent;
        let wordStart = 0;
        let wordEnd = caret.startOffset;
        for (let i = wordEnd; i >= 0; i--) {
            if (text[i] == " ") {
                wordStart = i + 1;
                break;
            }
        }
    
    // Display the word
    suggestions.innerHTML = text.slice(wordStart, wordEnd);
    }
    
});
#editor {
  border: solid 1px #000;
  padding: 10px;
}

#suggestions {
  color: crimson;
}
<div id="editor" contenteditable="true"></div>
Current word: <span id="suggestions"></span>


推荐阅读