Выделение текста в элементе (сродни выделению мышью)

Я хотел бы, чтобы пользователи нажимали на ссылку, а затем он выбирал 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();
}

Я что-то упускаю явно очевидное?

16 ответов

Решение

Простой 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:

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

Эта тема содержит действительно замечательные вещи. Но я не могу сделать это прямо на этой странице, используя FF 3.5b99 + FireBug из-за "Ошибка безопасности".

Yipee!! Я смог выделить всю правую боковую панель с этим кодом, надеюсь, он вам поможет:

    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.welovestackru",$("div.sidebar"));

   //this throws **security exception**

   r.selectNodeContents(w);

Код Джейсона нельзя использовать для элементов внутри iframe (так как область видимости отличается от окна и документа). Я исправил эту проблему и изменил ее, чтобы использовать ее как любой другой плагин jQuery (цепочка):

Пример 1. Выделение всего текста внутри тегов $(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 (искренне, мне все равно).

Вы можете использовать следующую функцию для выбора содержимого любого элемента:

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();

Я искал то же самое, мое решение было таким:

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

Обновленная версия, которая работает в 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/

Мне понравился ответ Лепе, за исключением нескольких вещей:

  1. Обнюхивание браузера, JQuery или нет не является оптимальным
  2. DRY
  3. Не работает в IE8, если родительский объект obj не поддерживает createTextRange
  4. Способность Chrome использовать setBaseAndExtent должна быть усилена (IMO)
  5. Не будет выделять текст, охватывающий несколько элементов DOM (элементов внутри "выбранного" элемента). Другими словами, если вы вызываете selText для div, содержащего несколько элементов span, он не будет выделять текст каждого из этих элементов. Для меня это было условием сделки, YMMV.

Вот то, что я придумал, с наклоном к ответу Лепе для вдохновения. Я уверен, что меня высмеют, поскольку это, возможно, немного жестко (и на самом деле может быть более, но я отвлекся). Но это работает и избегает перехвата браузера, и в этом суть.

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

ура

Для любого тега можно выбрать весь текст внутри этого тега с помощью этого короткого и простого кода. Он выделит всю область тега желтым цветом и выделит текст внутри него одним щелчком мыши.

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

Лепе - Это прекрасно работает для меня, спасибо! Я поместил ваш код в файл плагина, а затем использовал его вместе с каждым оператором, чтобы вы могли иметь несколько тегов pre и несколько ссылок "Выбрать все" на одной странице, и он выбирает правильный pre для выделения:

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

Взгляните на объект Selection (движок Gecko) и объект TextRange (движок Trident). Я не знаю ни о каких фреймворках JavaScript, в которых реализована кросс-браузерная поддержка, но я никогда не искал его, поэтому Вполне возможно, что даже JQuery есть.

Мой конкретный вариант использования заключался в выборе текстового диапазона внутри редактируемого элемента span, который, насколько я мог видеть, не описан ни в одном из ответов здесь.

Основное отличие состоит в том, что вы должны передать узел типа Text к Range объект, как описано в документации Range.setStart ():

Если startNode является узлом типа Text, Comment или CDATASection, тогда 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 ()

Вот еще одно простое решение, чтобы получить выделенный текст в виде строки, вы можете легко использовать эту строку, чтобы добавить дочерний элемент 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();

Метод Тима отлично подходит для моего случая - выделение текста в div для IE и FF после того, как я заменил следующее утверждение:

range.moveToElementText(text);

со следующим:

range.moveToElementText(el);

Текст в div выбирается щелчком по нему с помощью следующей функции jQuery:

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

Добавленной 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 );
        }
    } );
} );

Согласно документации jQuery select():

Инициируйте событие выбора каждого соответствующего элемента. Это приводит к выполнению всех функций, связанных с этим событием select, и вызывает действие выбора браузера по умолчанию для соответствующих элементов.

Вот ваше объяснение, почему JQuery select() не будет работать в этом случае.

Другие вопросы по тегам