【问题标题】:Understanding what goes on with textarea selection with JavaScript了解使用 JavaScript 进行文本区域选择的情况
【发布时间】:2010-09-28 22:22:12
【问题描述】:

我正在 textarea 中开发浏览器内编辑器。我已经开始寻找一些有关处理textarea 选择的信息,并发现this jQuery plugin, fieldSelection 可以进行一些简单的操作。

但是,它并没有解释发生了什么。

我想更多地了解 JavaScript 中的文本区域选择,最好是对前 DOM3 和后 DOM30 场景的描述。

【问题讨论】:

    标签: javascript textarea selection


    【解决方案1】:
    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;
    }
    

    【讨论】:

    • 在我为这个问题看到的所有解决方案中,这是唯一一个对我有用的解决方案。
    • 您应该将元素作为参数而不是 ID,这使得它更加灵活。否则辉煌!非常感谢您提供其他人/网站未能提供的见解。
    • 不错的功能;他们很容易适应我的需要。虽然有一个错误会发现 IE 6 和 7。在 set_selection 函数中,您有“e.value[i]”。这应该更改为“e.value.charAt(i)”。见:stackoverflow.com/questions/5943726/string-charatx-or-stringx
    • wrap_selection() 中添加left_str=left_str||'';right_str=right_str||'';,您可以通过传入left_str 的值来执行简单的插入操作 - 例如&lt;br /&gt;&amp;bull; (如果没有这些设置默认值,如果你只为left_str 传递了一个值right_str 的缺失参数会产生“未定义”)
    【解决方案2】:

    从 PPK 的 introduction to ranges 开始。 Mozilla 开发者连接在W3C selections 上有信息。微软有他们的系统documented on MSDN。更多技巧可以在in the answers here 找到。

    除了不兼容的接口之外,您会很高兴知道textarea 节点还有额外的怪异之处。如果我没记错的话,当您在 IE 中选择它们时,它们的行为与任何其他节点一样,但在其他浏览器中,它们具有独立的选择范围,通过节点上的 .selectionEnd.selectionStart 属性公开。

    此外,您真的应该看看.contentEditable 作为实时编辑内容的一种方式。从 Firefox3 版本开始,现在所有浏览器都支持此功能。

    【讨论】:

    • 谢谢博格!我以前从未听说过 contentEditable。我会尽快熟悉它!
    • 请注意名称是.contentEditable 而不是.contentEdiable(我无法编辑的小错字)
    【解决方案3】:

    我刚刚采用了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));
    

    我希望有人觉得它有用!

    【讨论】:

    • 谢谢你!使用了您的代码并对其进行了一些修改以考虑切换包装器等。您希望我包含注释/链接给您吗?
    • 谢谢,但没必要。
    【解决方案4】:

    我唯一可以补充的是,每当您操纵内容时,它似乎(没有实际尝试过)应该一直向上滚动。一个简单的补救方法是换行

    e.value =
    

    用两行来复制和恢复scrollTop,像这样:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-07
      • 1970-01-01
      • 2014-02-09
      • 2015-07-11
      • 1970-01-01
      • 2013-03-03
      相关资源
      最近更新 更多