2015-06-22 21 views
7

Tôi có văn bản tùy chỉnh. Trong ví dụ này, nó làm cho các chữ cái màu đỏ hoặc xanh lá cây, ngẫu nhiên.Hiển thị dấu nháy trong văn bản tùy chỉnh mà không hiển thị văn bản của nó

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>

Có một div đầu ra với một textarea trên nó. Vì vậy, textarea không bao gồm bất kỳ những thứ đầy màu sắc bên dưới nó, màu sắc và nền của nó được thiết lập để minh bạch. Mọi thứ hoạt động ở đây, ngoại trừ dấu mũ (con trỏ nhấp nháy do tác nhân người dùng cung cấp) là trong suốt.

Có cách nào để hiển thị dấu nháy mà không hiển thị văn bản của văn bản không?

Nếu tôi đặt div phía trên vùng văn bản thay thế và đặt nó pointer-events: none, văn bản vẫn hiển thị bên dưới. Sự sắp xếp này cũng làm cho việc cuộn trơn tru trở nên khó khăn, vì vậy nó không hiệu quả với tôi.

Trả lời

3

Chỉ cần chèn dấu mũ của riêng bạn!

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>

tôi có ở đây một <span>#caret đưa vào div mà nhấp nháy mỗi 500ms bởi Toggling thuộc tính ẩn của nó sử dụng JS. Để nhân rộng hành vi của trình duyệt, tôi đã phải phát hiện xem đó là selectionStart hoặc selectionEnd mà dấu mũ thực sự ở đó và làm cho nó vẫn vững chắc trong khi văn bản đã được nhập. Đây là một chút khó khăn hơn để đạt được khi các nhịp không có chiều dài cố định hoặc được lồng nhau, nhưng nó dễ dàng hơn so với không quan trọng với contentEditable với một highlighter phức tạp hơn. Chức năng này sẽ chèn dấu nháy ở vị trí bên phải:

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

sử dụng (nơi i là vị trí để chèn nó):

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

Tại sao không chỉ sử dụng một số <div contenteditable="true"></div> thay vì <textarea></textarea>?. Với điều này bạn không cần thêm textarea. Xem 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); 

Ngoài ra, để di chuyển dấu mũ ở cuối khi bạn đặt các văn bản mới trong div tôi đã sử dụng chức năng đó từ 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 không phải là một yếu tố hình thức và có thể dẫn đến mất dữ liệu từ nội dung của nó không được trình duyệt lưu. Nó cũng khá lộn xộn để làm việc với. – bjb568

+0

Liên quan: http://stackoverflow.com/questions/20728150/unusual-shape-of-a-textarea#comment31094671_20728150 và http://stackoverflow.com/questions/20728150/unusual-shape-of-a-textarea#comment31158616_20728275 – bjb568

+0

Nếu bạn muốn 'textarea' quá, hãy xem [demo mới này] (https://jsfiddle.net/bb5jmw95/1/). Tôi chỉ thêm 'myta.value = text; 'để đặt văn bản trong' textarea'. Sau đó, bạn có thể chỉ cần ẩn 'textarea' bằng' display: none; '. Hy vọng điều này giúp đỡ :) – lmgonzalves

Các vấn đề liên quan