Làm thế nào để có được vị trí cột caret (không phải pixel) trong textarea, tính bằng ký tự, từ đầu?


174

Làm thế nào để bạn có được vị trí dấu mũ trong <textarea>việc sử dụng JavaScript?

Ví dụ: This is| a text

Điều này sẽ trở lại 7.

Làm thế nào bạn có thể nhận được nó để trả về các chuỗi xung quanh con trỏ / lựa chọn?

Vd : 'This is', '', ' a text'.

Nếu từ nổi tiếng là nổi bật thì nó sẽ trở lại 'This ', 'is', ' a text'.


Xem câu hỏi này: stackoverflow.com/questions/164147/ và nếu bạn sẽ có dòng mới, cũng lưu ý về điều đó tại đây: stackoverflow.com/questions/235411/
Lỗi

1
Nếu bạn đang sử dụng jQuery, bạn có thể sử dụng jquery caret Plugin $ ( 'textarea') getSelection () bắt đầu.. Plugins.jquery.com/plugin-tags/caret @ ++
redochka

Tìm thấy một giải pháp tốt tại blog.vishalon.net/index.php/ Tôi đã thử nghiệm nó trong firefox và chrome, và nó đã hoạt động trong cả hai. Người viết nói rằng nó cũng hoạt động trong IE + Opera.
pycoder11258

Sử dụng đơn giản textarea.selectionStart, textarea. selectionEnd, textarea.setSelectionRange developer.mozilla.org/en-US/docs/Web/API/HTMLTextAreaElement
EAndreyF

Câu trả lời:


173

Với Firefox, Safari (và các trình duyệt dựa trên Gecko khác), bạn có thể dễ dàng sử dụng textarea.selectionStart, nhưng đối với IE không hoạt động, vì vậy bạn sẽ phải làm một cái gì đó như thế này:

function getCaret(node) {
  if (node.selectionStart) {
    return node.selectionStart;
  } else if (!document.selection) {
    return 0;
  }

  var c = "\001",
      sel = document.selection.createRange(),
      dul = sel.duplicate(),
      len = 0;

  dul.moveToElementText(node);
  sel.text = c;
  len = dul.text.indexOf(c);
  sel.moveStart('character',-1);
  sel.text = "";
  return len;
}

( mã hoàn chỉnh ở đây )

Tôi cũng khuyên bạn nên kiểm tra Plugin jQuery FieldSelection , nó cho phép bạn làm điều đó và hơn thế nữa ...

Chỉnh sửa: Tôi thực sự thực hiện lại mã trên:

function getCaret(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; 
}

Kiểm tra một ví dụ ở đây .


1
Điều này không phân biệt giữa các vị trí caret khi dấu mũ được đặt trên một dòng trống. Xem stackoverflow.com/questions/3053542/ Mạnh
Tim Down

4
Câu trả lời này không giải quyết vấn đề dòng trống.
Tim Down

6
Làm thế nào tôi có thể sử dụng điều này cho div NỘI DUNG?
Muhammet Göktürk Ayan

1
Bạn có thể muốn điều chỉnh lại câu trả lời này một chút, Safari (and other Gecko based browsers)Có vẻ như ngụ ý rằng Safari sử dụng Gecko. Tắc kè là động cơ của Mozilla; Safari sử dụng WebKit.
Mã vô dụng

1
caret ở vị trí 0 sẽ thất bại trong bài kiểm tra if (el.selectionStart) { return el.selectionStart; }...
okm

57

Cập nhật ngày 5 tháng 9 năm 2010

Thấy mọi người dường như được hướng dẫn ở đây về vấn đề này, tôi đang thêm câu trả lời của mình cho một câu hỏi tương tự, trong đó có cùng mã với câu trả lời này nhưng với nền tảng đầy đủ cho những người quan tâm:

Tài liệu của IE.selection.createRange không bao gồm các dòng trống hàng đầu hoặc dấu

Để giải thích cho việc ngắt dòng là khó khăn trong IE và tôi chưa thấy giải pháp nào thực hiện chính xác, bao gồm mọi câu trả lời khác cho câu hỏi này. Tuy nhiên, có thể sử dụng chức năng sau, sẽ trả về cho bạn điểm bắt đầu và kết thúc của lựa chọn (tương tự trong trường hợp dấu mũ) trong một <textarea>hoặc văn bản <input>.

Lưu ý rằng textarea phải có trọng tâm để chức năng này hoạt động chính xác trong IE. Nếu nghi ngờ, hãy gọi focus()phương thức của textarea trước.

function getInputSelection(el) {
    var start = 0, end = 0, normalizedValue, range,
        textInputRange, len, endRange;

    if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
        start = el.selectionStart;
        end = el.selectionEnd;
    } else {
        range = document.selection.createRange();

        if (range && range.parentElement() == el) {
            len = el.value.length;
            normalizedValue = el.value.replace(/\r\n/g, "\n");

            // Create a working TextRange that lives only in the input
            textInputRange = el.createTextRange();
            textInputRange.moveToBookmark(range.getBookmark());

            // Check if the start and end of the selection are at the very end
            // of the input, since moveStart/moveEnd doesn't return what we want
            // in those cases
            endRange = el.createTextRange();
            endRange.collapse(false);

            if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
                start = end = len;
            } else {
                start = -textInputRange.moveStart("character", -len);
                start += normalizedValue.slice(0, start).split("\n").length - 1;

                if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) {
                    end = len;
                } else {
                    end = -textInputRange.moveEnd("character", -len);
                    end += normalizedValue.slice(0, end).split("\n").length - 1;
                }
            }
        }
    }

    return {
        start: start,
        end: end
    };
}

Xin lỗi, nhưng ' phạm vi && phạm vi.parentEuity () ' nghĩa là gì?
sergzach

Có một vấn đề nếu chúng ta muốn có được vị trí của dấu mũ trong IE (nếu lựa chọn trống). Trong trường hợp này, nó trả về 0 là bắt đầu và độ dài chuỗi là kết thúc (nếu chúng ta sử dụng true thay vì phạm vi && Range.parentEuity () == el ).
sergzach

@sergzach: Có range && range.parentElement() == elđể kiểm tra xem lựa chọn có nằm trong vùng văn bản hay không và có cần thiết không. Không có vấn đề gì với chức năng có được vị trí caret miễn là vùng văn bản có trọng tâm . Nếu không chắc chắn, hãy gọi focus()phương thức của textarea trước khi gọi getInputSelection(). Tôi sẽ thêm một ghi chú cho câu trả lời.
Tim Down

1
@Tim: Khi nhấp vào phần tử div để hiển thị lựa chọn, "bắt đầu" và "kết thúc" luôn giống nhau.
Misha Moroshko

3
@Misha: Đó không phải là lỗi của hàm: đó là những gì thực sự được chọn vào thời điểm hàm thực thi. Bạn có thể nhìn thấy nó một cách trực quan sau khi bỏ hộp cảnh báo. Như tôi đã đề cập trong câu trả lời của mình cho câu hỏi gần đây của bạn, hai cách giải quyết có thể là sử dụng mousedownsự kiện hoặc thêm unselectable="on"vào <div>phần tử.
Tim Down

3

Tôi đã sửa đổi các chức năng trên để giải thích cho lợi nhuận vận chuyển trong IE. Nó chưa được kiểm tra nhưng tôi đã làm một cái gì đó tương tự với nó trong mã của mình để nó có thể hoạt động được.

function getCaret(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); 

    var add_newlines = 0;
    for (var i=0; i<rc.text.length; i++) {
      if (rc.text.substr(i, 2) == '\r\n') {
        add_newlines += 2;
        i++;
      }
    }

    //return rc.text.length + add_newlines;

    //We need to substract the no. of lines
    return rc.text.length - add_newlines; 
  }  
  return 0; 
}

2

Nếu bạn không phải hỗ trợ IE, bạn có thể sử dụng selectionStartselectionEndcác thuộc tính của textarea.

Để có được vị trí caret chỉ cần sử dụng selectionStart:

function getCaretPosition(textarea) {
  return textarea.selectionStart
}

Để có được các chuỗi xung quanh lựa chọn, sử dụng mã sau đây:

function getSurroundingSelection(textarea) {
  return [textarea.value.substring(0, textarea.selectionStart)
         ,textarea.value.substring(textarea.selectionStart, textarea.selectionEnd)
         ,textarea.value.substring(textarea.selectionEnd, textarea.value.length)]
}

Bản trình diễn trên JSFiddle .

Xem thêm tài liệu HTMLTextAreaE bổ sung .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.