选择元素中的文本(类似于用鼠标突出显示)


424

我希望用户单击链接,然后在另一个元素(而不是输入)中选择HTML文本。

“选择”是指您将鼠标拖到文本上方来选择文本的方式。这一直是研究的负担,因为每个人都用其他术语谈论“选择”或“突出显示”。

这可能吗?到目前为止,我的代码:

HTML:

<a href="javascript:" onclick="SelectText('xhtml-code')">Select Code</a>
<code id="xhtml-code">Some Code here </code>

JS:

function SelectText(element) {
    $("#" + element).select();
}

我是否明显遗漏了一些东西?


Answers:


612

纯Javascript

function selectText(node) {
    node = document.getElementById(node);

    if (document.body.createTextRange) {
        const range = document.body.createTextRange();
        range.moveToElementText(node);
        range.select();
    } else if (window.getSelection) {
        const selection = window.getSelection();
        const range = document.createRange();
        range.selectNodeContents(node);
        selection.removeAllRanges();
        selection.addRange(range);
    } else {
        console.warn("Could not select text in node: Unsupported browser.");
    }
}

const clickable = document.querySelector('.click-me');
clickable.addEventListener('click', () => selectText('target'));
<div id="target"><p>Some text goes here!</p><p>Moar text!</p></div>
<p class="click-me">Click me!</p>

这是一个工作示例。对于那些正在寻找jQuery插件的人,我也做了其中之一


jQuery(原始答案)

我已经在此线程中找到了解决方案。我能够修改给定的信息,并将其与一些jQuery混合使用,以创建一个功能强大的函数来选择任何元素中的文本,而与浏览器无关:

function SelectText(element) {
    var text = document.getElementById(element);
    if ($.browser.msie) {
        var range = document.body.createTextRange();
        range.moveToElementText(text);
        range.select();
    } else if ($.browser.mozilla || $.browser.opera) {
        var selection = window.getSelection();
        var range = document.createRange();
        range.selectNodeContents(text);
        selection.removeAllRanges();
        selection.addRange(range);
    } else if ($.browser.safari) {
        var selection = window.getSelection();
        selection.setBaseAndExtent(text, 0, text, 1);
    }
}

jQuery解决方案给了我Uncaught TypeError:无法读取未定义的属性“ msie”
egmfrs,

@egmfrs是的,自从发布此答案以来,jquery已删除其browser嗅探器。
杰森(Jason)

127

这是一个没有浏览器嗅探并且不依赖jQuery的版本:

function selectElementText(el, win) {
    win = win || window;
    var doc = win.document, sel, range;
    if (win.getSelection && doc.createRange) {
        sel = win.getSelection();
        range = doc.createRange();
        range.selectNodeContents(el);
        sel.removeAllRanges();
        sel.addRange(range);
    } else if (doc.body.createTextRange) {
        range = doc.body.createTextRange();
        range.moveToElementText(el);
        range.select();
    }
}

selectElementText(document.getElementById("someElement"));
selectElementText(elementInIframe, iframe.contentWindow);

有什么办法选择一个文本div contentEditable='true'
oldboy

@PrimitiveNom:此代码将在contenteditable元素上工作,但是您必须确保它首先具有焦点。
蒂姆·唐

18

Jason的代码不能用于iframe中的元素(因为范围不同于窗口和文档)。我修复了该问题,并对其进行了修改,以便用作其他任何jQuery插件(可链接):

示例1:只需单击一下,即可选择<code>标记内的所有文本,并添加“ selected”类:

$(function() {
    $("code").click(function() {
        $(this).selText().addClass("selected");
    });
});

示例2:单击按钮时,在iframe中选择一个元素:

$(function() {
    $("button").click(function() {
        $("iframe").contents().find("#selectme").selText();
    });
});

注意:请记住,iframe源应位于同一域中,以防止出现安全错误。

jQuery插件:

jQuery.fn.selText = function() {
    var obj = this[0];
    if ($.browser.msie) {
        var range = obj.offsetParent.createTextRange();
        range.moveToElementText(obj);
        range.select();
    } else if ($.browser.mozilla || $.browser.opera) {
        var selection = obj.ownerDocument.defaultView.getSelection();
        var range = obj.ownerDocument.createRange();
        range.selectNodeContents(obj);
        selection.removeAllRanges();
        selection.addRange(range);
    } else if ($.browser.safari) {
        var selection = obj.ownerDocument.defaultView.getSelection();
        selection.setBaseAndExtent(obj, 0, obj, 1);
    }
    return this;
}

我在IE8,Firefox,Opera,Safari,Chrome(当前版本)中对其进行了测试。我不确定它是否适用于较旧的IE版本(因为我不在乎)。


3
$ .browser现在已经废弃/删除-这需要一个重写
詹姆斯·麦科马克

2
@JamesMcCormack:是的。我不确定重写是否值得,因为这里发布了其他解决方案,其中不涉及$ .browser。
lepe

16

这个线程包含非常棒的东西。但是由于“安全错误”,我无法使用FF 3.5b99 + FireBug在此页面上正确执行此操作。

pe!我可以使用此代码选择整个右侧边栏,希望它对您有所帮助:

    var r = document.createRange();
    var w=document.getElementById("sidebar");  
    r.selectNodeContents(w);  
    var sel=window.getSelection(); 
    sel.removeAllRanges(); 
    sel.addRange(r); 

PS:-我无法使用jquery选择器返回的对象,例如

   var w=$("div.welovestackoverflow",$("div.sidebar"));

   //this throws **security exception**

   r.selectNodeContents(w);

2
您在尝试选择jQuery对象时需要从jQuery获取元素:var w = $(“ div.welovestackoverflow”,$(“ div.sidebar”))。get(0);
Blixt

不起作用...我得到一个错误“对象不支持此方法”,它突出显示了第一行。我做了一些挖掘,发现有一个“document.body.createTextRange()”,但随后“selectNodeContents”不工作....这是IE浏览器
贾森-

我阅读了您发现的那个线程...很棒...我能够根据该信息创建一个在所有浏览器上均可使用的功能。非常感谢!我的解决方案已发布
Jason

6

您可以使用以下功能选择任何元素的内容:

jQuery.fn.selectText = function(){
    this.find('input').each(function() {
        if($(this).prev().length == 0 || !$(this).prev().hasClass('p_copy')) { 
            $('<p class="p_copy" style="position: absolute; z-index: -1;"></p>').insertBefore($(this));
        }
        $(this).prev().html($(this).val());
    });
    var doc = document;
    var element = this[0];
    console.log(this, element);
    if (doc.body.createTextRange) {
        var range = document.body.createTextRange();
        range.moveToElementText(element);
        range.select();
    } else if (window.getSelection) {
        var selection = window.getSelection();        
        var range = document.createRange();
        range.selectNodeContents(element);
        selection.removeAllRanges();
        selection.addRange(range);
    }
};

该函数可以如下调用:

$('#selectme').selectText();

5

我在寻找相同的东西,我的解决方案是这样的:

$('#el-id').focus().select();

3
您不能focus()在非输入上使用,这就是这个问题的意思。
杰森

4
但您可以在textarea元素上使用它-这是我用谷歌搜索到的问题。我没有完全阅读问题的错。
奥斯顿

4

除了以下几点,我喜欢lepe的回答:

  1. 浏览器嗅探,jQuery或否不是最佳选择
  2. 干燥
  3. 如果obj的父级不支持createTextRange,则在IE8中不起作用
  4. 应该利用Chrome使用setBaseAndExtent的功能(IMO)
  5. 将不会选择跨多个DOM元素(“ selected”元素中的元素)的文本。换句话说,如果在包含多个span元素的div上调用selText,它将不会选择每个元素的文本。YMMV对我来说真是个大难题。

这就是我想出的,点头表示lepe的灵感来源。我敢肯定我会被嘲笑的,因为这也许有点笨拙(实际上可能会更多,但是我离题了)。但这有效并且避免了浏览器嗅探,这就是重点

selectText:function(){

    var range,
        selection,
        obj = this[0],
        type = {
            func:'function',
            obj:'object'
        },
        // Convenience
        is = function(type, o){
            return typeof o === type;
        };

    if(is(type.obj, obj.ownerDocument)
        && is(type.obj, obj.ownerDocument.defaultView)
        && is(type.func, obj.ownerDocument.defaultView.getSelection)){

        selection = obj.ownerDocument.defaultView.getSelection();

        if(is(type.func, selection.setBaseAndExtent)){
            // Chrome, Safari - nice and easy
            selection.setBaseAndExtent(obj, 0, obj, $(obj).contents().size());
        }
        else if(is(type.func, obj.ownerDocument.createRange)){

            range = obj.ownerDocument.createRange();

            if(is(type.func, range.selectNodeContents)
                && is(type.func, selection.removeAllRanges)
                && is(type.func, selection.addRange)){
                // Mozilla
                range.selectNodeContents(obj);
                selection.removeAllRanges();
                selection.addRange(range);
            }
        }
    }
    else if(is(type.obj, document.body) && is(type.obj, document.body.createTextRange)) {

        range = document.body.createTextRange();

        if(is(type.obj, range.moveToElementText) && is(type.obj, range.select)){
            // IE most likely
            range.moveToElementText(obj);
            range.select();
        }
    }

    // Chainable
    return this;
}

而已。您看到的一些内容是为了便于阅读和/或方便。在Mac上以Opera,Safari,Chrome,Firefox和IE的最新版本进行了测试。也在IE8中测试。另外,我通常仅在代码块内需要时声明变量,但jslint建议将它们全部声明为最高变量。好的,jslint。

编辑 我忘了包括如何将其绑定到操作码:

function SelectText(element) {
    $("#" + element).selectText();
}

干杯


是的,尽管看起来很正确,但对我来说似乎很用力。我的主要抱怨是,setBaseAndExtent()仅仅因为删除了该分支就可以使用非标准,这对我来说毫无意义,而一切都可以以基于标准的方式运行。功能检测很好,但是我厌倦了快速测试所有东西。
Tim Down

@TimDown好吧,利用这一点的好处setBaseAndExtent是它的效率要高得多,即使添加了ifstatemnent,也远比“删除该分支”要好得多。我真的不明白“我会累..”的说法吗?编写并忘记它,您唯一要做的就是调用该函数,而不是编写它。:)
Madbreaks

@Madbreaks如果setBaseAndExtent性能明显优于,我会感到惊讶addRange。为什么会这样呢?我的另一条评论与扩展到所有DOM交互的功能测试精神有关:在使用每个DOM方法和属性之前,要测试大量的代码。我不反对 我很高兴在代码中划清界限并做出更多假设。
Tim Down 2014年

4

适用于chrome的更新版本:

function SelectText(element) {
    var doc = document;
    var text = doc.getElementById(element);    
    if (doc.body.createTextRange) { // ms
        var range = doc.body.createTextRange();
        range.moveToElementText(text);
        range.select();
    } else if (window.getSelection) {
        var selection = window.getSelection();
        var range = doc.createRange();
        range.selectNodeContents(text);
        selection.removeAllRanges();
        selection.addRange(range);

    }
}

$(function() {
    $('p').click(function() {
        SelectText("selectme");

    });
});

http://jsfiddle.net/KcX6A/326/


3

对于任何标签,都可以通过此简短代码选择该标签内的所有文本。它将用黄色突出显示整个标签区域,并单击一下即可选择其中的文本。

document.onclick = function(event) {
    var range, selection;
event.target.style.backgroundColor = 'yellow';
        selection = window.getSelection();
        range = document.createRange();
        range.selectNodeContents(event.target);
        selection.removeAllRanges();
        selection.addRange(range);
};

2

lepe-很好,谢谢!我将您的代码放在一个插件文件中,然后将其与每个语句结合使用,以便您可以在一个页面上具有多个前置标记和多个“全选”链接,并且它会选择正确的前置突出显示:

<script type="text/javascript" src="../js/jquery.selecttext.js"></script>
<script type="text/javascript">
  $(document).ready(function() { 
        $(".selectText").each(function(indx) {
                $(this).click(function() {                 
                    $('pre').eq(indx).selText().addClass("selected");
                        return false;               
                    });
        });
  });


1

看一看Selection对象(Gecko引擎)和TextRange对象(Trident引擎)。我不知道有实现此功能的跨浏览器支持的任何JavaScript框架,但是我也从没有寻找过,所以甚至jQuery都有可能。


0

Tim的方法非常适合我的情况-在替换以下语句后,为IE和FF选择div中的文本:

range.moveToElementText(text);

具有以下内容:

range.moveToElementText(el);

通过使用以下jQuery函数单击以选择div中的文本:

$(function () {
    $("#divFoo").click(function () {
        selectElementText(document.getElementById("divFoo"));
    })
});

0

这是另一个以字符串形式获取所选文本的简单解决方案,您可以轻松地使用此字符串将div元素子代添加到代码中:

var text = '';

if (window.getSelection) {
    text = window.getSelection();

} else if (document.getSelection) {
    text = document.getSelection();

} else if (document.selection) {
    text = document.selection.createRange().text;
}

text = text.toString();

这是为了返回突出显示的文本,而不是创建突出显示。
MKN Web Solutions

0

我的特殊用例是在一个可编辑的span元素内选择一个文本范围,据我所知,此处的任何答案都未描述。

主要区别在于您必须将类型的节点传递TextRange对象,如Range.setStart()的文档中所述

如果startNode是类型为Text,Comment或CDATASection的Node ,则startOffset是从startNode开始的字符数。对于其他节点类型,startOffset是startNode起始之间的子节点数。

Text节点是span元素的第一个子节点,因此要获取它,需要访问childNodes[0]span元素。其余与大多数其他答案相同。

这里是一个代码示例:

var startIndex = 1;
var endIndex = 5;
var element = document.getElementById("spanId");
var textNode = element.childNodes[0];

var range = document.createRange();
range.setStart(textNode, startIndex);
range.setEnd(textNode, endIndex);

var selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);

其他相关文档:
范围
选择
Document.createRange()
Window.getSelection()


-1

jQuery.browser.webkit在Chrome浏览器中已添加到“否则”。无法在Chrome 23中正常运行。

在下面制作此脚本,以选择带有的<pre>标记中的内容class="code"

jQuery( document ).ready(function() {
    jQuery('pre.code').attr('title', 'Click to select all');
    jQuery( '#divFoo' ).click( function() {
        var refNode = jQuery( this )[0];
        if ( jQuery.browser.msie ) {
            var range = document.body.createTextRange();
            range.moveToElementText( refNode );
            range.select();
        } else if ( jQuery.browser.mozilla || jQuery.browser.opera  || jQuery.browser.webkit ) {
            var selection = refNode.ownerDocument.defaultView.getSelection();
            console.log(selection);
            var range = refNode.ownerDocument.createRange();
            range.selectNodeContents( refNode );
            selection.removeAllRanges();
            selection.addRange( range );
        } else if ( jQuery.browser.safari ) {
            var selection = refNode.ownerDocument.defaultView.getSelection();
            selection.setBaseAndExtent( refNode, 0, refNode, 1 );
        }
    } );
} );

-1

根据jQuery文档select()

触发每个匹配元素的选择事件。这将导致绑定到该select事件的所有功能都被执行,并在匹配的元素上调用浏览器的默认select动作。

有您的解释为什么jQuery select()在这种情况下不起作用。


4
我不是要用CSS样式突出显示文本。我希望选择文本。
杰森(Jason)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.