繁体   English   中英

如何在跨度中将输入的文本包装在可内容编辑的元素中?

[英]How can I wrap inputted text in a contenteditable elememt in a span?

我有一个将“ contenteditable”设置为true的div。

现在,我希望将任何新输入的文本包装在一个跨度中。 意思是我可以突出显示已编辑的文本。

这是我目前的位置-http://jsfiddle.net/ug4xr9x0/

HTML

<div contenteditable="true" id="myContent">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi suscipit tincidunt leo, non volutpat lectus sodales non. Phasellus id felis ultrices, egestas enim nec, ornare quam. Ut at posuere felis, vitae sodales risus. Suspendisse velit nibh, facilisis et ante et, vehicula facilisis velit.</div>

Java脚本

document.getElementById('myContent').addEventListener('keydown',function(evt){
    var range = window.getSelection().getRangeAt(0);
    if(range.startContainer.parentNode.className!=='highlight'){
        var newElement = document.createElement('span');
        newElement.className = 'highlight';
        newElement.innerHTML = String.fromCharCode(evt.which);
        range.insertNode(newElement);
        range.setStartAfter(newElement);
        evt.preventDefault();
    }
});

CSS

.highlight{
    background-color:yellow;
}

这将跨度环绕在字符周围,但不会将插入号移动到跨度中,从而导致向后键入。 我完全不确定keydown是监听的适当事件,甚至不确定阻止keypress和插入元素是否正确。 范围range.setStartAfter是试图移动插入号的尝试,但无论有没有,其行为都相同。

我还希望所有选定的文本在开始键入时都被删除,而这目前还没有发生。

任何帮助将非常感激。 谢谢。

onkeydown适用于此,尽管oninput会更好,但是并不能在所有浏览器中的contenteditables上触发。 同样,当您要添加元素时, inserNode是执行此操作的适当方法。 尽管也可以使用range.collapse()来完成, setStartAfter仅用于您使用过的任务。

当使用newElement.innerHTML = String.fromCharCode(evt.which);将内容设置为新创建的span时,问题就开始了newElement.innerHTML = String.fromCharCode(evt.which); 插入的文本不一定是用户想要输入的内容。

该代码段仅在您的代码中稍作修改,但显示了用户输入的文本。

document.getElementById('myContent').addEventListener('keydown', function (evt) {
    var range = window.getSelection().getRangeAt(0),
        modifiers = [8, 13, 37, 38, 39, 40, 46], // List of keys, which should not prevent the default action
        newElement, chr;
    if (range.startContainer.parentNode.className !== 'highlight') {
        if (modifiers.indexOf(evt.which) < 0) {
            newElement = document.createElement('span');
            newElement.className = 'highlight';
            range.deleteContents(); // This deletes the content of the selection
            chr = evt.key || evt.char; // Gets the entered real character
            if (chr.length < 2) { // Excludes "modifiers" like SHIFT and CTRL etc.
                newElement.textContent = chr;
            }
            range.insertNode(newElement);
            range.collapse(); // Collapses the range to end
            evt.preventDefault();
        }
    }
});

jsFiddle上的现场演示

这段代码似乎有一个缺点。 除非您真正写入span ,否则每个输入的字符都会创建一个新的span

现在,我已经设法在Chrome和Firefox中进行此操作。 这是修改

document.getElementById('myContent').addEventListener('keypress',function(evt){
    var range = window.getSelection().getRangeAt(0),
        modifiers = [0,8]; // List of keys to ignore (0 is arrows & 8 is delete in firefox)

    if(range.startContainer.parentNode.className!=='highlight' && modifiers.indexOf(evt.which) <  0){
        if(!range.collapsed){
            range.deleteContents();
        }
        var el =  document.createElement('span');
        el.appendChild(document.createTextNode('A'));
        el.className = 'highlight';
        range.insertNode(el);

        var sel = window.getSelection();        
        range.setStartBefore(el.childNodes[0]);
        range.setEndAfter(el.childNodes[0]);
        sel.removeAllRanges();
        sel.addRange(range);
    }
});

和小提琴http://jsfiddle.net/ug4xr9x0/8/

“ keypress”(而不是“ keydown”)可停止箭头键等在chrome中触发,firefox需要忽略0和8处的“ evt.which”属性。

将插入一个跨度,该跨度的textnode包含字母“ A”。 然后,我使用setStartBefore和setEndAfter设置范围以包装该节点,并使用addRange更新窗口选择。 文本节点“ A”被覆盖(无需阻止默认值)。

我敢肯定,有一种更优雅的方法可以实现这一点,但是它对我有用。

谢谢你的帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM