2015-06-22 103 views
7

我有一个自定义textarea。在这个例子中,它会随机地使字母变为红色或绿色。在自定义textarea中显示插入符号而不显示其文本

var mydiv = document.getElementById('mydiv'), 
 
    myta = document.getElementById('myta'); 
 
function updateDiv() { 
 
    var fc; 
 
    while (fc = mydiv.firstChild) mydiv.removeChild(fc); 
 
    for (var i = 0; i < myta.value.length; i++) { 
 
    var span = document.createElement('span'); 
 
    span.className = Math.random() < 0.5 ? 'green' : 'red'; 
 
    span.appendChild(document.createTextNode(myta.value[i])); 
 
    mydiv.appendChild(span); 
 
    } 
 
}; 
 
myta.addEventListener('input', updateDiv);
body { position: relative } 
 
div, textarea { 
 
    -webkit-text-size-adjust: none; 
 
    width: 100%; 
 
    white-space: pre-wrap; 
 
    word-wrap: break-word; 
 
    overflow-wrap: break-word; 
 
    font: 1rem sans-serif; 
 
    padding: 2px; 
 
    margin: 0; 
 
    border-radius: 0; 
 
    border: 1px solid #000; 
 
    resize: none; 
 
} 
 
textarea { 
 
    position: absolute; 
 
    top: 0; 
 
    color: transparent; 
 
    background: transparent; 
 
} 
 
.red { color: #f00 } 
 
.green { color: #0f0 }
<div id="mydiv"></div> 
 
<textarea id="myta" autofocus=""></textarea>

有一个DIV输出与一个textarea过去。所以textarea不会掩盖它下面的任何丰富多彩的东西,它的颜色和背景设置为透明。除了插入符号(由用户代理提供的闪烁光标)是透明的以外,这里的所有工作都是可用的。

有没有办法显示脱字符而不使textarea的文本可见?

如果我让文本区域上方的div改为pointer-events: none,textarea在底下仍然可见。这种安排也使平滑滚动困难,所以它不适合我。

回答

3

只需插入您自己的脱字符!

function blink() { 
 
    document.getElementById('caret').hidden ^= 1; 
 
    blinkTimeout = setTimeout(blink, 500); 
 
} 
 
var mydiv = document.getElementById('mydiv'), 
 
    myta = document.getElementById('myta'), 
 
    blinkTimeout = setTimeout(blink, 500), 
 
    lastSelectionStart = 0, 
 
    lastSelectionEnd = 0, 
 
    whichSelection = true; 
 
function updateDiv() { 
 
    var fc; 
 
    while (fc = mydiv.firstChild) mydiv.removeChild(fc); 
 
    if (myta.selectionStart != lastSelectionStart) { 
 
    lastSelectionStart = myta.selectionStart; 
 
    whichSelection = false; 
 
    } 
 
    if (myta.selectionEnd != lastSelectionEnd) { 
 
    lastSelectionEnd = myta.selectionEnd; 
 
    whichSelection = true; 
 
    } 
 
    var cursorPos = whichSelection ? myta.selectionEnd : myta.selectionStart; 
 
    for (var i = 0; i < myta.value.length; i++) { 
 
    if (i == cursorPos) { 
 
     var caret = document.createElement('span'); 
 
     caret.id = 'caret'; 
 
     caret.appendChild(document.createTextNode('\xA0')); 
 
     mydiv.appendChild(caret); 
 
     clearTimeout(blinkTimeout); 
 
     blinkTimeout = setTimeout(blink, 500); 
 
    } 
 
    var span = document.createElement('span'); 
 
    span.className = Math.random() < 0.5 ? 'green' : 'red'; 
 
    span.appendChild(document.createTextNode(myta.value[i])); 
 
    mydiv.appendChild(span); 
 
    } 
 
    if (myta.value.length == cursorPos) { 
 
    var caret = document.createElement('span'); 
 
    caret.id = 'caret'; 
 
    caret.appendChild(document.createTextNode('\xA0')); 
 
    mydiv.appendChild(caret); 
 
    clearTimeout(blinkTimeout); 
 
    blinkTimeout = setTimeout(blink, 500); 
 
    } 
 
}; 
 
myta.addEventListener('input', updateDiv); 
 
myta.addEventListener('focus', updateDiv); 
 
myta.addEventListener('mousedown', function() { 
 
    setTimeout(updateDiv, 0); 
 
}); 
 
myta.addEventListener('keydown', function() { 
 
    setTimeout(updateDiv, 0); 
 
}); 
 
myta.addEventListener('blur', function() { 
 
    document.getElementById('caret').hidden = true; 
 
    clearTimeout(blinkTimeout); 
 
});
body { position: relative } 
 
div, textarea { 
 
    -webkit-text-size-adjust: none; 
 
    width: 100%; 
 
    white-space: pre-wrap; 
 
    word-wrap: break-word; 
 
    overflow-wrap: break-word; 
 
    font: 1rem sans-serif; 
 
    padding: 2px; 
 
    margin: 0; 
 
    border-radius: 0; 
 
    border: 1px solid #000; 
 
    resize: none; 
 
} 
 
textarea { 
 
    position: absolute; 
 
    top: 0; 
 
    color: transparent; 
 
    background: transparent; 
 
} 
 
.red { color: #f00 } 
 
.green { color: #0f0 } 
 
#caret { 
 
    display: inline-block; 
 
    position: absolute; 
 
    width: 1px; 
 
    background: #000; 
 
} 
 
#caret[hidden] { display: none }
<div id="mydiv"><span id="caret">&nbsp;</span></div> 
 
<textarea id="myta" autofocus=""></textarea>

我这里有一个<span>#caret插入其中使用JS触发其隐藏属性闪烁每500ms股利。为了复制浏览器行为,我必须检测插入符号实际上是否为selectionStartselectionEnd,并在输入文本时使其保持稳定。

当跨度不是固定长度或嵌套跨度时,实现起来有点困难,但比用更复杂的荧光笔处理contentEditable更容易。此功能将插入插入符在正确的位置:

function insertNodeAtPosition(node, refNode, pos) { 
    if (typeof(refNode.nodeValue) == 'string') refNode.parentNode.insertBefore(node, refNode.splitText(pos)); 
    else { 
     for (var i = 0; i < refNode.childNodes.length; i++) { 
      var chNode = refNode.childNodes[i]; 
      if (chNode.textContent.length <= pos && i != refNode.childNodes.length - 1) pos -= chNode.textContent.length; 
      else return insertNodeAtPosition(node, chNode, pos); 
     } 
    } 
} 

用法(其中i是将其插入的位置):

var caret = document.createElement('span'); 
caret.id = 'caret'; 
caret.appendChild(document.createTextNode('\xA0')); 
insertNodeAtPosition(caret, mydiv, i); 
clearTimeout(blinkTimeout); 
blinkTimeout = setTimeout(blink, 500); 
1

为什么不简单使用<div contenteditable="true"></div>而不是<textarea></textarea>?有了这个,你不需要额外的textarea。看到一个demo here

HTML:

<div id="myta" autofocus="" contenteditable="true"></div> 

的JavaScript:

var myta = document.getElementById('myta'); 
function updateDiv() { 
    var fc; 
    var text = myta.innerText || myta.textContent; 
    while (fc = myta.firstChild) myta.removeChild(fc); 
    for (var i = 0; i < text.length; i++) { 
     var span = document.createElement('span'); 
     span.className = Math.random() < 0.5 ? 'green' : 'red'; 
     span.appendChild(document.createTextNode(text[i])); 
     myta.appendChild(span); 
    } 
    placeCaretAtEnd(myta); 
}; 
myta.addEventListener('input', updateDiv); 

此外,为了在年底移动插入符号,当你把div里面我用这个函数从this answer新文本:

function placeCaretAtEnd(el) { 
    el.focus(); 
    if (typeof window.getSelection != "undefined" 
     && typeof document.createRange != "undefined") { 
     var range = document.createRange(); 
     range.selectNodeContents(el); 
     range.collapse(false); 
     var sel = window.getSelection(); 
     sel.removeAllRanges(); 
     sel.addRange(range); 
    } else if (typeof document.body.createTextRange != "undefined") { 
     var textRange = document.body.createTextRange(); 
     textRange.moveToElementText(el); 
     textRange.collapse(false); 
     textRange.select(); 
    } 
} 
+0

CONTENTEDITABLE不是一个形式元件和由于能够导致数据丢失其内容不会被浏览器保存。合作也很麻烦。 – bjb568

+0

相关:http://stackoverflow.com/questions/20728150/unusual-shape-of-a-textarea#comment31094671_20728150和http://stackoverflow.com/questions/20728150/unusual-shape-of-a-textarea#comment31158616_20728275 – bjb568

+0

如果你也想'textarea',看看[这个新的demo](https://jsfiddle.net/bb5jmw95/1/)。我只加了'myta。value = text;'也可以在'textarea'中设置文本。然后你可以用'display:none;'来隐藏'textarea'。希望这个帮助:) – lmgonzalves

相关问题