在自定义textarea中显示插入符号而不显示其文本 [英] Show a caret in a custom textarea without displaying its text

查看:148
本文介绍了在自定义textarea中显示插入符号而不显示其文本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个自定义的textarea。在这个例子中,它会随机地使用字母红色或绿色。



var mydiv = document.getElementById('mydiv'),myta = document .getElementById('myta');函数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? '绿':'红'; span.appendChild(document.createTextNode(myta.value [I])); mydiv.appendChild(跨度); }}; myta.addEventListener('input',updateDiv);

body {position:relative} div,textarea {-webkit-text-size-adjust:none;宽度:100%;白色空间:预包装;单词包装:分词; overflow-wrap:break-word; font:1rem sans-serif; padding:2px;保证金:0; border-radius:0; border:1px solid#000; resize:none;} textarea {position:absolute; top:0;颜色:透明;背景:transparent;}。red {color:#f00} .green {color:#0f0}

 



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



是否有方法显示插入符号而不使textarea的文本可见?



如果我在textarea上面创建div并给它赋值 pointer-events:none ,textarea是在底下仍然可见。这种安排也使平滑滚动变得困难,所以它不适用于我。

解决方案

p>

   body {position:relative} div,textarea { -webkit-text-size-adjust:none;宽度:100%;白色空间:预包装;单词包装:分词; overflow-wrap:break-word; font:1rem sans-serif; padding:2px;保证金:0; border-radius:0; border:1px solid#000; resize:none;} textarea {position:absolute; top:0;颜色:透明; background:transparent;}。red {color:#f00} .green {color:#0f0} #caret {display:inline-block;位置:绝对;宽度:1px;背景:#000;}#caret [hidden] {display:none}  

 < div id =mydiv>< span id =caret>& nbsp;< / span>< / div>< textarea id =mytaautofocus = >< / textarea>  

$ b

通过使用JS切换其隐藏属性,插入到每500毫秒闪烁的div中的c $ c>< span> #caret 为了复制浏览器行为,我必须检测它是否是插入符号实际位于的 selectionStart selectionEnd 并在输入文本时使其保持稳定。



当跨度不是固定长度或嵌套跨度时,实现起来有点困难,但它比用更复杂的荧光笔摆弄contentEditable。这个函数会将插入符号插入正确的位置:

$ p $ 函数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返回insertNodeAtPosition(node,chNode,pos);





用法(其中<$ c
$ b

  var caret = document.createElement(document.createElement($ c> i 是插入它的位置) '跨度'); 
caret.id ='caret';
caret.appendChild(document.createTextNode('\xA0'));
insertNodeAtPosition(caret,mydiv,i);
clearTimeout(blinkTimeout);
blinkTimeout = setTimeout(blink,500);


I have a custom textarea. In this example, it makes the letters red or green, randomly.

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>

There's an output div with a textarea over it. So the textarea doesn't cover up any of the colorful things below it, its color and background are set to transparent. Everything works here, except that the caret (the flashing cursor provided by the user agent) is transparent.

Is there a way to show the caret without making the textarea's text visible?

If I make the div above the textarea instead and give it pointer-events: none, the textarea is still visible underneath. This arrangements also makes smooth scrolling difficult, so it doesn't work for me.

解决方案

Just insert your own caret!

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>

I have here a <span> #caret inserted into the div which blinks every 500ms by toggling its hidden attribute using JS. To replicate browser behavior, I had to detect whether it was the selectionStart or the selectionEnd which the caret was actually at, and make it remain solid while text was being input.

This is a bit harder to achieve when the spans aren't of fixed length or are nested, but it's easier than fiddling with contentEditable with a more complex highlighter. This function will insert the caret in the right spot:

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);
        }
    }
}

Usage (where i is the position to insert it):

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

这篇关于在自定义textarea中显示插入符号而不显示其文本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆