首页 > 解决方案 > 使用 contenteditable 突出显示文本,可更一致地在移动浏览器上运行

问题描述

我目前正在使用 contenteditable 来创建一个输入字段,其中一些单词用颜色突出显示,一些单词被替换为特定符号。它在桌面浏览器和一些移动浏览器上完美运行。但是,它不适用于例如。Firefox Focus,以及某些版本的移动版 Chrome 和 Firefox?有时字母没有被输入,然后突然一堆字母被重复。这很奇怪,仅在使用软件键盘时才会发生,而不是物理键盘。

我目前正在这样做,并尝试了这些功能的大量不同变体,但它并没有真正产生影响。

function handleInput(event: Event) {
    const target = event.target as HTMLInputElement;
    const cursorPos = getCursorPos(target);
    const [highlighted, offset] = highlight(target.textContent);
    target.innerHTML = highlighted;
    setCursorPos(target, cursorPos - offset);
}

function getCursorPos(element: HTMLInputElement): number {
    const shadowRoot = calculatorElement.getRootNode() as ShadowRoot;
    const range = shadow.getRange(shadowRoot);
    //const selection = shadowRoot.getSelection();
    //const range = selection.getRangeAt(0);
    const preCaretRange = range.cloneRange();
    preCaretRange.selectNodeContents(element);
    preCaretRange.setEnd(range.endContainer, range.endOffset);

    return preCaretRange.toString().length;
}

function setCursorPos(element: HTMLElement, indexToSelect: number) {
    const range = document.createRange();
    range.selectNodeContents(element);
    const textNodes = getTextNodesIn(element);

    let nodeEndPos = 0;
    for (const textNode of textNodes) {
        const previousNodeEndPos = nodeEndPos;
        nodeEndPos += textNode.length;

        // If the index that should be selected is
        // less than or equal to the current position (the end of the text node),
        // then the index points to somewhere inside the current text node.
        // This text node along with indexToSelect will then be used when setting the cursor position.
        if (indexToSelect <= nodeEndPos) {
            range.setStart(textNode, indexToSelect - previousNodeEndPos);
            range.setEnd(textNode, indexToSelect - previousNodeEndPos);
            break;
        }
    }

    const selection = window.getSelection();
    selection.removeAllRanges();
    selection.addRange(range);
}

function getTextNodesIn(node: Node): Text[] {
    const textNodes: Text[] = [];

    // If it's text node, add it to the list directly,
    // otherwise go through it recursively and find text nodes within it.
    if (node.nodeType == Node.TEXT_NODE) {
        textNodes.push(node as Text);
    } else {
        for (const child of node.childNodes) {
            textNodes.push(...getTextNodesIn(child));
        }
    }

    return textNodes;
}

实际上是否有可能让它在移动浏览器中一致地工作?我已经注意到其他输入字段的这个问题,我在网上找到了这样的突出显示。

标签: javascripttypescriptcontenteditable

解决方案


推荐阅读