Próbuję naśladować opiekunkę textarea w celu stworzenia bardzo lekkiego, bogatego textarea. Nie chcę używać czegoś takiego jak codemirror lub jakiejkolwiek innej masywnej biblioteki, ponieważ nie będę używać żadnej z jej funkcji.Dotyk Mimicng w textarea
Mam <pre>
umieszczony za tekstem z przezroczystym tłem, dzięki czemu mogę symulować efekt podświetlania w tekście. Jednak chcę też móc zmienić kolor czcionki (aby nie zawsze była taka sama). Więc próbowałem color: transparent
na textarea, który pozwala mi na styl tekstu w dowolny sposób chcę, ponieważ pojawia się tylko na element <pre>
za textarea, ale karetka znika.
Dostałem go do pracy dość dobrze, chociaż nie jest doskonały. Głównym problemem jest to, że kiedy trzymasz klucz i spamujesz tę postać, karetka zawsze pozostaje w tyle za jedną postacią. Co więcej, wydaje się, że jest dość zasobny ...
Jeśli zauważysz w kodzie coś, co wymaga poprawy, możesz to skomentować!
Oto skrzypce z kodem: http://jsfiddle.net/2t5pu/25/
A dla tych, którzy nie chcą, aby odwiedzić jsfiddle z jakiegokolwiek powodu, oto cały kod:
CSS:
textarea, #fake_area {
position: absolute;
margin: 0;
padding: 0;
height: 400px;
width: 600px;
font-size: 16px;
font: 16px "Courier New", Courier, monospace;
white-space: pre;
top: 0;
left: 0;
resize: none;
outline: 0;
border: 1px solid orange;
overflow: hidden;
word-break: break-word;
padding: 5px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
box-sizing: border-box;
}
#fake_area {
/* hide */
opacity: 0;
}
#caret {
width: 1px;
height: 18px;
position: absolute;
background: #f00;
z-index: 100;
}
HTML :
<div id="fake_area"><span></span></div>
<div id="caret"></div>
<textarea id="textarea">test</textarea>
JAVASCRIPT:
var fake_area = document.getElementById("fake_area").firstChild;
var fake_caret = document.getElementById("caret");
var real_area = document.getElementById("textarea");
$("#textarea").on("input keydown keyup propertychange click", function() {
// Fill the clone with textarea content from start to the position of the caret.
// The replace /\n$/ is necessary to get position when cursor is at the beginning of empty new line.
doStuff();
});
var timeout;
function doStuff() {
if(timeout) clearTimeout(timeout);
timeout=setTimeout(function() {
fake_area.innerHTML = real_area.value.substring(0, getCaretPosition(real_area)).replace(/\n$/, '\n\u0001');
setCaretXY(fake_area, real_area, fake_caret, getPos("textarea"));
}, 10);
}
function getCaretPosition(el) {
if (el.selectionStart) return el.selectionStart;
else if (document.selection) {
//el.focus();
var r = document.selection.createRange();
if (r == null) return 0;
var re = el.createTextRange(), rc = re.duplicate();
re.moveToBookmark(r.getBookmark());
rc.setEndPoint('EndToStart', re);
return rc.text.length;
}
return 0;
}
function setCaretXY(elem, real_element, caret, offset) {
var rects = elem.getClientRects();
var lastRect = rects[rects.length - 1];
var x = lastRect.left + lastRect.width - offset[0] + document.body.scrollLeft,
y = lastRect.top - real_element.scrollTop - offset[1] + document.body.scrollTop;
caret.style.cssText = "top: " + y + "px; left: " + x + "px";
//console.log(x, y, offset);
}
function getPos(e) {
e = document.getElementById(e);
var x = 0;
var y = 0;
while (e.offsetParent !== null){
x += e.offsetLeft;
y += e.offsetTop;
e = e.offsetParent;
}
return [x, y];
}
Z góry dziękuję!
Twoja kurtyna pozostaje w tyle z powodu prawdziwej apatii z powodu małej repozycji czasu. Spróbuj wprowadzić kilka linii tekstu, a następnie kliknij i przytrzymaj lewy przycisk myszy w innym rzędzie, a zobaczysz go. Aby temu zaradzić, musisz ustawić przezroczystość pola tekstowego na 0. Ale wtedy będziesz musiał radzić sobie z poprawnym wyświetlaniem tekstu. – twil
czy naprawdę trzeba zaktualizować kursor 100 razy na sekundę? Myślę, że wystarczyłoby 5 lub 10. to dlatego twoja aplikacja działa wolno ... – dandavis
@dandavis: musi być tak responsywny jak domyślny. –