2008-12-30 95 views

回答

10

從PPK的introduction to ranges開始。 Mozilla開發者連接有關於W3C selections的信息。微軟有他們的系統documented on MSDN。一些更多的技巧可以發現in the answers here

除了不兼容的接口之外,您會很高興知道textarea節點還有額外的奇怪之處。如果我沒有記錯的話,當你在IE中選擇它們時,它們的行爲與其他節點相同,但在其他瀏覽器中,它們有一個獨立的選擇範圍,通過節點上的.selectionEnd.selectionStart屬性公開。

此外,你應該真的看看.contentEdiable作爲一種手段來編輯生活的東西。從Firefox3發佈以來,所有瀏覽器都支持這一功能。

+0

謝謝Borgar!我從來沒有聽說過contentEditable之前。我會很快熟悉它! – brad 2009-01-05 19:28:30

29
function get_selection(the_id) 
{ 
    var e = document.getElementById(the_id); 

    //Mozilla and DOM 3.0 
    if('selectionStart' in e) 
    { 
     var l = e.selectionEnd - e.selectionStart; 
     return { start: e.selectionStart, end: e.selectionEnd, length: l, text: e.value.substr(e.selectionStart, l) }; 
    } 
    //IE 
    else if(document.selection) 
    { 
     e.focus(); 
     var r = document.selection.createRange(); 
     var tr = e.createTextRange(); 
     var tr2 = tr.duplicate(); 
     tr2.moveToBookmark(r.getBookmark()); 
     tr.setEndPoint('EndToStart',tr2); 
     if (r == null || tr == null) return { start: e.value.length, end: e.value.length, length: 0, text: '' }; 
     var text_part = r.text.replace(/[\r\n]/g,'.'); //for some reason IE doesn't always count the \n and \r in the length 
     var text_whole = e.value.replace(/[\r\n]/g,'.'); 
     var the_start = text_whole.indexOf(text_part,tr.text.length); 
     return { start: the_start, end: the_start + text_part.length, length: text_part.length, text: r.text }; 
    } 
    //Browser not supported 
    else return { start: e.value.length, end: e.value.length, length: 0, text: '' }; 
} 

function replace_selection(the_id,replace_str) 
{ 
    var e = document.getElementById(the_id); 
    selection = get_selection(the_id); 
    var start_pos = selection.start; 
    var end_pos = start_pos + replace_str.length; 
    e.value = e.value.substr(0, start_pos) + replace_str + e.value.substr(selection.end, e.value.length); 
    set_selection(the_id,start_pos,end_pos); 
    return {start: start_pos, end: end_pos, length: replace_str.length, text: replace_str}; 
} 

function set_selection(the_id,start_pos,end_pos) 
{ 
    var e = document.getElementById(the_id); 

    //Mozilla and DOM 3.0 
    if('selectionStart' in e) 
    { 
     e.focus(); 
     e.selectionStart = start_pos; 
     e.selectionEnd = end_pos; 
    } 
    //IE 
    else if(document.selection) 
    { 
     e.focus(); 
     var tr = e.createTextRange(); 

     //Fix IE from counting the newline characters as two seperate characters 
     var stop_it = start_pos; 
     for (i=0; i < stop_it; i++) if(e.value[i].search(/[\r\n]/) != -1) start_pos = start_pos - .5; 
     stop_it = end_pos; 
     for (i=0; i < stop_it; i++) if(e.value[i].search(/[\r\n]/) != -1) end_pos = end_pos - .5; 

     tr.moveEnd('textedit',-1); 
     tr.moveStart('character',start_pos); 
     tr.moveEnd('character',end_pos - start_pos); 
     tr.select(); 
    } 
    return get_selection(the_id); 
} 

function wrap_selection(the_id, left_str, right_str, sel_offset, sel_length) 
{ 
    var the_sel_text = get_selection(the_id).text; 
    var selection = replace_selection(the_id, left_str + the_sel_text + right_str); 
    if(sel_offset !== undefined && sel_length !== undefined) selection = set_selection(the_id, selection.start + sel_offset, selection.start + sel_offset + sel_length); 
    else if(the_sel_text == '') selection = set_selection(the_id, selection.start + left_str.length, selection.start + left_str.length); 
    return selection; 
} 
+1

在我看到這個問題的所有解決方案中,這是唯一一個爲我工作的解決方案。 – 2011-08-10 23:15:14

+1

您應該將元素作爲參數而不是ID,這使得它更加靈活。否則輝煌!非常感謝您提供其他人/網站未能提供的見解。 – Sam 2011-09-29 19:06:05

1

我唯一可以補充的是,它似乎(並沒有真正嘗試它),這應該滾動一直向上滾動,只要你處理內容。一個EAY的補救辦法是換行不

e.value = 

行兩行復制和恢復scrollTop的,就像這樣:

var rememberScrollTop = e.scrollTop; 
e.value = .... (same as in user357565 snippet) 
e.scrollTop = rememberScrollTop; 
5

我剛剛通過user357565提出的解決方案,併爲重新編碼jQuery直接使用:

(function ($) { 
    $.fn.get_selection = function() { 
    var e = this.get(0); 
    //Mozilla and DOM 3.0 
    if('selectionStart' in e) { 
     var l = e.selectionEnd - e.selectionStart; 
     return { start: e.selectionStart, end: e.selectionEnd, length: l, text: e.value.substr(e.selectionStart, l) }; 
    } 
    else if(document.selection) { //IE 
     e.focus(); 
     var r = document.selection.createRange(); 
     var tr = e.createTextRange(); 
     var tr2 = tr.duplicate(); 
     tr2.moveToBookmark(r.getBookmark()); 
     tr.setEndPoint('EndToStart',tr2); 
     if (r == null || tr == null) return { start: e.value.length, end: e.value.length, length: 0, text: '' }; 
     var text_part = r.text.replace(/[\r\n]/g,'.'); //for some reason IE doesn't always count the \n and \r in length 
     var text_whole = e.value.replace(/[\r\n]/g,'.'); 
     var the_start = text_whole.indexOf(text_part,tr.text.length); 
     return { start: the_start, end: the_start + text_part.length, length: text_part.length, text: r.text }; 
    } 
    //Browser not supported 
    else return { start: e.value.length, end: e.value.length, length: 0, text: '' }; 
    }; 

    $.fn.set_selection = function (start_pos,end_pos) { 
    var e = this.get(0); 
    //Mozilla and DOM 3.0 
    if('selectionStart' in e) { 
     e.focus(); 
     e.selectionStart = start_pos; 
     e.selectionEnd = end_pos; 
    } 
    else if (document.selection) { //IE 
     e.focus(); 
     var tr = e.createTextRange(); 

     //Fix IE from counting the newline characters as two seperate characters 
     var stop_it = start_pos; 
     for (i=0; i < stop_it; i++) if(e.value[i].search(/[\r\n]/) != -1) start_pos = start_pos - .5; 
     stop_it = end_pos; 
     for (i=0; i < stop_it; i++) if(e.value[i].search(/[\r\n]/) != -1) end_pos = end_pos - .5; 

     tr.moveEnd('textedit',-1); 
     tr.moveStart('character',start_pos); 
     tr.moveEnd('character',end_pos - start_pos); 
     tr.select(); 
    } 
    return this.get_selection(); 
    }; 

    $.fn.replace_selection = function (replace_str) { 
    var e = this.get(0); 
    selection = this.get_selection(); 
    var start_pos = selection.start; 
    var end_pos = start_pos + replace_str.length; 
    e.value = e.value.substr(0, start_pos) + replace_str + e.value.substr(selection.end, e.value.length); 
    this.set_selection(start_pos,end_pos); 
    return {start: start_pos, end: end_pos, length: replace_str.length, text: replace_str}; 
    }; 

    $.fn.wrap_selection = function (left_str, right_str, sel_offset, sel_length) { 
    var the_sel_text = this.get_selection().text; 
    var selection = this.replace_selection(left_str + the_sel_text + right_str); 
    if(sel_offset !== undefined && sel_length !== undefined) 
     selection = this.set_selection(selection.start + sel_offset, selection.start + sel_offset + sel_length); 
    else if(the_sel_text == '') 
     selection = this.set_selection(selection.start + left_str.length, selection.start + left_str.length); 
    return selection; 
    }; 
}(jQuery)); 

我希望有人認爲它有用!