【问题标题】:Replacing text inside textarea without focus在没有焦点的情况下替换文本区域内的文本
【发布时间】:2010-12-19 19:47:26
【问题描述】:

我想替换选定的文本(如果没有选择,则在光标位置后插入新文本)。 新文本是从另一个文本框输入的。
我希望能够插入新文本而无需先在文本区域中单击(聚焦)。
含义:首先在textarea中选择要替换的文本,然后在文本框中输入新文本并单击按钮。

<textarea id='text' cols="40" rows="20">
</textarea>

<div id="opt">
    <input id="input" type="text" size="35">
    <input type="button" onclick='pasteIntoInput(document.getElementById("input").value)' value="button"/>    
</div>


function pasteIntoInput(text) { 
  el=document.getElementById("text");
  el.focus();    
  if (typeof el.selectionStart == "number"&& typeof el.selectionEnd == "number") { 
    var val = el.value; 
    var selStart = el.selectionStart;
    el.value = val.slice(0, selStart) + text + val.slice(el.selectionEnd);        
    el.selectionEnd = el.selectionStart = selStart + text.length;
  } 
  else if (typeof document.selection != "undefined") {
    var textRange = document.selection.createRange();        
    textRange.text = text;       
    textRange.collapse(false);        
    textRange.select();
  } 
}  

在线示例: link text

【问题讨论】:

  • 抱歉,不确定您要问什么。您的示例似乎符合您的要求,因此请更好地解释您还需要什么。

标签: javascript html textarea selection


【解决方案1】:

因此,当您将注意力移出文本区域并专注于输入标签时,您希望保留选择。

您需要记住选择(文本区域失去焦点时的起点和终点)并强制选择以使其持续存在。

要记住选择,您可以将el.selectionStartel.selectionEnd 存储在一个函数内的两个全局变量中,该函数在textarea 标记的onblur() 事件中调用。

然后在您的pasteIntoInput() 中,您可以考虑替换这两点。

强制选择 - 检查此解决方案 for persisting 选择。然而,这使用 jquery,而不是普通的 javascript。

但是,我不确定该解决方案是否真的有效。我在这里尝试过http://jsfiddle.net/sandeepan_nits/qpZdJ/1/,但它没有按预期工作。

更新

我怀疑焦点消失后是否可以继续选择。可能选择需要关注,我给出的答案链接试图关注然后选择。在这种情况下,这不会解决您的问题。因此,替代方案可能是 -

  • 使用 html div 伪造文本区域。您可以定义一些样式来创建类似选择的效果并应用它onblur() 或使用简单的现成编辑器(如果可用)。

  • 在单独的区域中动态显示选择。检查此demo of jquery fieldSelection plugin。请记住,您已经将选择存储在全局变量中以进行实际替换。您只需向用户显示将被替换的选择。我认为像这个演示一样单独显示选择可以节省您的时间,而且看起来也很酷。

但当然取决于你的要求。

进一步更新

检查http://jsfiddle.net/sandeepan_nits/qpZdJ/2/ 是否有工作“在没有焦点的情况下替换文本区域内的文本”(如您所愿)但没有模糊选择。我仍然不知道是否可以保持选择模糊。

另一个更新(12 月 21 日)

适用于 IE 和其他浏览器的工作解决方案 http://jsfiddle.net/sandeepan_nits/qpZdJ/24/

这是相同的代码:-

html -

<textarea id='text' cols="40" rows="20" onbeforedeactivate="storeSelectionIeCase();" onblur="storeSelectionOthersCase();">
</textarea>

<div id="opt">
    <input id="input" type="text" size="35">
    <input type="button" onclick='pasteIntoInput(document.getElementById("input").value)' value="button"/>

</div>

还有所有的js

var storedSelectionStart = null;
var storedSelectionEnd = null;

function pasteIntoInput(text)
{

    el=document.getElementById("text");

    el.focus();    
    if((storedSelectionStart != null) && (storedSelectionEnd != null))
    {
        start = storedSelectionStart;
        end = storedSelectionEnd;
    }
    else
    {
        start = el.selectionStart;
        end = el.selectionEnd;
    }
    if (typeof start  == "number"&& typeof end == "number")
    {
        var val = el.value;
        var selStart = start;
        var end  = selStart + text.length;
        el.value = val.slice(0, selStart) + text + val.slice(end );        
    }
    else if (typeof document.selection != "undefined")
    {
       var textRange = document.selection.createRange();        
       textRange.text = text;       
       textRange.collapse(false);        
       textRange.select();
    }
}  

function storeSelectionOthersCase()
{
    if(!(isBrowserIE6() || isBrowserIE7()))
    {
        storeSelection();
    }
    else
    {
        return false;
    }
}


function storeSelectionIeCase()
{
    if((isBrowserIE6() || isBrowserIE7()))
    {
        storeSelection();
    }
    else
    {
        return false;
    }
}


function storeSelection()
{
    //get selection
    el=document.getElementById("text");

    var el = document.getElementById("text");
    var sel = getInputSelection(el);
    //alert("check"+sel.start + ", " + sel.end);


    storedSelectionStart  = sel.start;
    storedSelectionEnd = sel.end;

   //alert("see"+storedSelectionStart  +" - "+storedSelectionEnd );
}

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

function isBrowserIE6()
{
    var ret = false;
    if(($.browser.msie) && (parseInt($.browser.version) == 6) && (!this.XMLHttpRequest))
    {
        ret = true;
    }
    return ret;
}

function isBrowserIE7()
{
    var ret = false;
    if(($.browser.msie) && ((parseInt($.browser.version) == 7) && (this.XMLHttpRequest)))
    { //Modification because of IE tester IE7 being detected as IE6
        ret = true;
    }
    return ret;
}

之前的小提琴在 IE 中不起作用,因为当 onblur() 事件触发时,选择在 IE 中被破坏。我已经为 IE 6 和 7 应用了一些基于浏览器的条件,但尚未在 IE 8 中进行测试。

感谢Tim Down,他帮助我找出了之前小提琴的问题。

【讨论】:

  • @asker 我怀疑焦点消失后是否可以保留选择。检查我的更新。
  • 我只想选择一些文本,弹出带有文本框的框架,我可以在其中输入新文本并替换所选文本。
  • @asker 我已了解您的要求。当您关注文本区域并关注输入标签(输入新文本)时,您希望保留选择。我的答案还是一样。
  • 我认为这是可能的 - 不一定要保持选中的文本 onblur,但要记住 selectionStart 和 selectionEnd 位置,然后当您输入新文本并单击按钮时,它会关闭弹出窗口并替换指定文本框中这些位置之间的文本。不幸的是,我只休息了 5 分钟,所以没有时间制定解决方案,但这就是我要开始的地方。你知道,从另一个问题,如何获得 selectionStart 和 selectionEnd - 从那里得到解决方案应该不难。
  • @ClarkyBoy - 我认为从用户体验的角度来看,模糊文本选择的持久性是现在的主要要求。记住文本选择和替换很容易。检查我的进一步更新,看看它是否像 OP 想要的那样正确地进行了替换,但是如果没有选择的持久性,它对用户来说感觉不好。是否有可能以某种方式保持选择模糊?
【解决方案2】:

好的,请纠正我的错误。

1) 当文本区域中的文本被选中,然后点击按钮,选中的文本被输入中的文本替换。
2) 当没有选中文本时,无论光标在哪个位置,文本都会自动添加到文本区域的最后。

如果这些是唯一的规定,那么这个 javascript 就足够了,否则我需要更多关于你想要它做什么的信息。

function pasteIntoInput(text) { 
  el=document.getElementById("text");
  el.focus();    
  if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number" && el.selectionStart != el.selectionEnd) { 
    var val = el.value; 
    var selStart = el.selectionStart;
    el.value = val.slice(0, selStart) + text + val.slice(el.selectionEnd);        
    el.selectionEnd = el.selectionStart = selStart + text.length;
  }
  else
    el.value += text;
}

对不起,我不能提供更多帮助,了解该功能的使用会很有帮助,因此我可以提供所需的操作。

【讨论】:

  • 这不是我想要的:在 textarea 中输入 3 行文本。将光标 tp 移动到第二行的末尾。转到文本框输入新文本并单击按钮。结果:文本插入到 textarea 的末尾,而不是光标所在的位置。
  • 另外:选择文本不会被记住。
【解决方案3】:

这是基于上述答案和更多想法的替代解决方案。
仅适用于 IE(其他浏览器默认支持此功能)。

需要更多测试(我只在IE8中测试过)

<script type="text/javascript">
    var pos = 0;
    var len = 0;

    function pasteIntoInput(text) {
       var el = document.getElementById("text");

        el.focus();
        if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
            var val = el.value;
            var selStart = el.selectionStart;
            el.value = val.slice(0, selStart) + text + val.slice(el.selectionEnd);
            el.selectionEnd = el.selectionStart = selStart + text.length;
        }
        else if (typeof document.selection != "undefined") {
        //var textRange = document.selection.createRange();
        var textRange  = el.createTextRange();
            //  el.focus();
            if (len > 0) { //something selected, so replace
                textRange.collapse(true);
                textRange.moveEnd('character', pos+len);
                textRange.moveStart('character', pos);
                textRange.select();
                textRange.text = text;

            }
            else {
                textRange.collapse(true);                   
                textRange.moveEnd('character', pos);
                textRange.moveStart('character', pos);                    
                textRange.text = text;
                textRange.select();

            }
            el.focus();
        }
    }


    function GetCaretPosition(txtarea) {

        pos = 0;
        if (document.selection) {

            // get current selection
            var range = document.selection.createRange();
            if (range.text.length>0)
             len=range.text.length;

            // get full range
            var rangeFull = document.body.createTextRange();
            rangeFull.moveToElementText(txtarea);

            var sel_start;
            for (sel_start = 0; rangeFull.compareEndPoints('StartToStart', range) < 0; sel_start++) {
                rangeFull.moveStart('character', 1);
            }                


            pos = sel_start;                


        }  

    }

</script>

【讨论】:

    【解决方案4】:

    一个 jquery 插件,用于在文本区域中获取选择索引的开始和结束。上面的 javascript 代码对 IE7 和 IE8 不起作用,并且给出的结果非常不一致,所以我编写了这个小的 jquery 插件。 允许暂时保存选择的开始和结束索引,并在以后突出显示选择。

    这里有一个工作示例和简要版本: http://jsfiddle.net/hYuzk/3/

    这里有一个带有 cmets 等的更详细的版本: http://jsfiddle.net/hYuzk/4/

            // Cross browser plugins to set or get selection/caret position in textarea, input fields etc for IE7,IE8,IE9, FF, Chrome, Safari etc
            $.fn.extend({
                // Gets or sets a selection or caret position in textarea, input field etc.
                // Usage Example: select text from index 2 to 5 --> $('#myTextArea').caretSelection({start: 2, end: 5});
                //                get selected text or caret position --> $('#myTextArea').caretSelection();
                //                if start and end positions are the same, caret position will be set instead o fmaking a selection
                caretSelection : function(options)
                {
                if(options && !isNaN(options.start) && !isNaN(options.end))
                {
                    this.setCaretSelection(options);
                }
                else
                {
                    return this.getCaretSelection();
                }
                },
                setCaretSelection : function(options)
                {
                var inp = this[0];
                if(inp.createTextRange)
                {
                    var selRange = inp.createTextRange();
                    selRange.collapse(true);
                    selRange.moveStart('character', options.start);
                    selRange.moveEnd('character',options.end - options.start);
                    selRange.select();
                }
                else if(inp.setSelectionRange)
                {
                    inp.focus();
                    inp.setSelectionRange(options.start, options.end);
                }
                },
                getCaretSelection: function()
                {
                var inp = this[0], start = 0, end = 0;
                if(!isNaN(inp.selectionStart))
                {
                    start = inp.selectionStart;
                    end = inp.selectionEnd;
                }
                else if( inp.createTextRange )
                {
                    var inpTxtLen = inp.value.length, jqueryTxtLen = this.val().length;
                    var inpRange = inp.createTextRange(), collapsedRange = inp.createTextRange();
    
                    inpRange.moveToBookmark(document.selection.createRange().getBookmark());
                    collapsedRange.collapse(false);
    
                    start = inpRange.compareEndPoints('StartToEnd', collapsedRange) > -1 ? jqueryTxtLen : inpRange.moveStart('character', -inpTxtLen);
                    end = inpRange.compareEndPoints('EndToEnd', collapsedRange) > -1 ? jqueryTxtLen : inpRange.moveEnd('character', -inpTxtLen);
                }
                return {start: Math.abs(start), end: Math.abs(end)};
    
                },
                // Usage: $('#txtArea').replaceCaretSelection({start: startIndex, end: endIndex, text: 'text to replace with', insPos: 'before|after|select'})
                // Options     start: start index of the text to be replaced
                //               end: end index of the text to be replaced
                //              text: text to replace the selection with
                //            insPos: indicates whether to place the caret 'before' or 'after' the replacement text, 'select' will select the replacement text
    
                replaceCaretSelection: function(options)
                {
                var pos = this.caretSelection();
                this.val( this.val().substring(0,pos.start) + options.text + this.val().substring(pos.end) );
                if(options.insPos == 'before')
                {
                    this.caretSelection({start: pos.start, end: pos.start});
                }
                else if( options.insPos == 'after' )
                {
                    this.caretSelection({start: pos.start + options.text.length, end: pos.start + options.text.length});
                }
                else if( options.insPos == 'select' )
                {
                    this.caretSelection({start: pos.start, end: pos.start + options.text.length});
                }
                }
            });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-10
      • 1970-01-01
      • 2021-08-10
      • 2019-10-24
      • 1970-01-01
      • 2012-08-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多