2009-07-14 34 views

Trả lời

21

Ngoài ra còn có một vấn đề khác.

Giải pháp của Nico Burns hoạt động nếu div contenteditable không chứa các phần tử đa cấp khác.

Ví dụ: nếu div chứa div khác và các div khác chứa nội dung khác bên trong, có thể xảy ra một số sự cố.

Để giải quyết chúng, tôi đã sắp xếp các giải pháp sau đây, đó là một sự cải tiến của 's Nico một:

//Namespace management idea from http://enterprisejquery.com/2010/10/how-good-c-habits-can-encourage-bad-javascript-habits-part-1/ 
(function(cursorManager) { 

    //From: http://www.w3.org/TR/html-markup/syntax.html#syntax-elements 
    var voidNodeTags = ['AREA', 'BASE', 'BR', 'COL', 'EMBED', 'HR', 'IMG', 'INPUT', 'KEYGEN', 'LINK', 'MENUITEM', 'META', 'PARAM', 'SOURCE', 'TRACK', 'WBR', 'BASEFONT', 'BGSOUND', 'FRAME', 'ISINDEX']; 

    //From: https://stackoverflow.com/questions/237104/array-containsobj-in-javascript 
    Array.prototype.contains = function(obj) { 
     var i = this.length; 
     while (i--) { 
      if (this[i] === obj) { 
       return true; 
      } 
     } 
     return false; 
    } 

    //Basic idea from: https://stackoverflow.com/questions/19790442/test-if-an-element-can-contain-text 
    function canContainText(node) { 
     if(node.nodeType == 1) { //is an element node 
      return !voidNodeTags.contains(node.nodeName); 
     } else { //is not an element node 
      return false; 
     } 
    }; 

    function getLastChildElement(el){ 
     var lc = el.lastChild; 
     while(lc && lc.nodeType != 1) { 
      if(lc.previousSibling) 
       lc = lc.previousSibling; 
      else 
       break; 
     } 
     return lc; 
    } 

    //Based on Nico Burns's answer 
    cursorManager.setEndOfContenteditable = function(contentEditableElement) 
    { 

     while(getLastChildElement(contentEditableElement) && 
       canContainText(getLastChildElement(contentEditableElement))) { 
      contentEditableElement = getLastChildElement(contentEditableElement); 
     } 

     var range,selection; 
     if(document.createRange)//Firefox, Chrome, Opera, Safari, IE 9+ 
     {  
      range = document.createRange();//Create a range (a range is a like the selection but invisible) 
      range.selectNodeContents(contentEditableElement);//Select the entire contents of the element with the range 
      range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start 
      selection = window.getSelection();//get the selection object (allows you to change selection) 
      selection.removeAllRanges();//remove any selections already made 
      selection.addRange(range);//make the range you have just created the visible selection 
     } 
     else if(document.selection)//IE 8 and lower 
     { 
      range = document.body.createTextRange();//Create a range (a range is a like the selection but invisible) 
      range.moveToElementText(contentEditableElement);//Select the entire contents of the element with the range 
      range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start 
      range.select();//Select the range (make it the visible selection 
     } 
    } 

}(window.cursorManager = window.cursorManager || {})); 

Cách sử dụng:

var editableDiv = document.getElementById("my_contentEditableDiv"); 
cursorManager.setEndOfContenteditable(editableDiv); 

Bằng cách này, con trỏ chắc chắn được đặt ở cuối phần tử cuối cùng, cuối cùng được lồng vào nhau.

EDIT # 1: Để trở nên chung chung hơn, câu lệnh trong khi cũng nên xem xét tất cả các thẻ khác không thể chứa văn bản. Các phần tử này được đặt tên là các phần tử void và trong this question có một số phương pháp về cách kiểm tra xem một phần tử có bị vô hiệu hay không. Vì vậy, giả định rằng tồn tại một hàm gọi là canContainText trả true nếu đối số không phải là một yếu tố vô hiệu, các dòng mã sau đây:

contentEditableElement.lastChild.tagName.toLowerCase() != 'br' 

nên được thay thế bằng:

canContainText(getLastChildElement(contentEditableElement)) 

EDIT # 2: Mã ở trên được cập nhật đầy đủ, với mọi thay đổi được mô tả và thảo luận

+0

Thú vị, tôi đã có thể mong đợi trình duyệt tự động xử lý trường hợp này (không phải là tôi ngạc nhiên vì nó không có, các trình duyệt dường như không làm những điều trực quan với nội dung có thể chỉnh sửa được). Bạn có một ví dụ về HTML, nơi giải pháp của bạn hoạt động nhưng tôi không? –

+0

Trong mã của tôi có một lỗi khác. Tôi sửa nó rồi. Bây giờ, bạn có thể xác minh rằng mã của tôi hoạt động trong [trang này] (http://html5demos.com/contenteditable), trong khi mã của bạn không phải là –

+0

Tôi gặp lỗi khi sử dụng hàm của bạn, giao diện điều khiển cho biết 'Lỗi Loại không bắt buộc: Không thể đọc property 'nodeType' của null' và điều này là từ hàm getLastChildElement đang được gọi. Bạn có biết điều gì có thể gây ra vấn đề này không? – Derek

183

Giải pháp của Geowa4 sẽ hoạt động cho vùng văn bản chứ không phải cho phần tử có thể chỉnh sửa được.

Giải pháp này là để di chuyển dấu mũ đến cuối phần tử có thể chỉnh sửa được. Nó sẽ làm việc trong tất cả các trình duyệt hỗ trợ contenteditable.

function setEndOfContenteditable(contentEditableElement) 
{ 
    var range,selection; 
    if(document.createRange)//Firefox, Chrome, Opera, Safari, IE 9+ 
    { 
     range = document.createRange();//Create a range (a range is a like the selection but invisible) 
     range.selectNodeContents(contentEditableElement);//Select the entire contents of the element with the range 
     range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start 
     selection = window.getSelection();//get the selection object (allows you to change selection) 
     selection.removeAllRanges();//remove any selections already made 
     selection.addRange(range);//make the range you have just created the visible selection 
    } 
    else if(document.selection)//IE 8 and lower 
    { 
     range = document.body.createTextRange();//Create a range (a range is a like the selection but invisible) 
     range.moveToElementText(contentEditableElement);//Select the entire contents of the element with the range 
     range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start 
     range.select();//Select the range (make it the visible selection 
    } 
} 

Nó có thể được sử dụng bởi mã tương tự như:

elem = document.getElementById('txt1');//This is the element that you want to move the caret to the end of 
setEndOfContenteditable(elem); 
+0

Bạn có cách nào để thực hiện công việc này bằng chrome không? Giải pháp – Jason

+1

geowa4 sẽ hoạt động đối với textarea trong chrome, nó sẽ không hoạt động đối với các yếu tố có thể chỉnh sửa trong bất kỳ trình duyệt nào. công trình của tôi cho các yếu tố có thể chỉnh sửa, nhưng không phải cho văn bản. –

+4

Đây là câu trả lời đúng cho câu hỏi này, hoàn hảo, cảm ơn Nico. – Rob

1

Có thể đặt con trỏ đến cuối qua phạm vi:

setCaretToEnd(target/*: HTMLDivElement*/) { 
    const range = document.createRange(); 
    const sel = window.getSelection(); 
    range.selectNodeContents(target); 
    range.collapse(false); 
    sel.removeAllRanges(); 
    sel.addRange(range); 
    target.focus(); 
    range.detach(); // optimization 

    // set scroll to the end if multiline 
    target.scrollTop = target.scrollHeight; 
} 
+0

Sử dụng mã ở trên nó thực hiện thủ thuật - nhưng tôi muốn có khả năng di chuyển con trỏ ở bất kỳ đâu trong div có thể chỉnh sửa nội dung và tiếp tục nhập từ điểm đó - ví dụ: người dùng đã nhận ra lỗi đánh máy ... Làm cách nào để sửa đổi mã của bạn ở trên? – Zabs

+1

@Zabs khá dễ dàng: không gọi 'setCaretToEnd()' mỗi lần - chỉ gọi nó khi bạn cần: ví dụ: sau khi Sao chép-Dán, hoặc sau khi hạn chế độ dài tin nhắn. – Andrew

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