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

370

Я хотел бы, чтобы пользователи щелкали по ссылке, затем выбирает текст HTML в другом элементе (а не вводе).

Под "select" я подразумеваю то же самое, что вы бы выделили текст, перетащив на него указатель мыши. Это было медведем для исследования, потому что все говорят о "выборе" или "подчеркивании" в других терминах.

Возможно ли это? Мой код:

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 ответов

522
Лучший ответ

Я нашел решение для этого, благодаря этой теме, найденной TheVillageIdiot. Мне удалось изменить предоставленную информацию и смешать ее с немного 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);
    }
}

EDIT (9/28/11):

Прошло некоторое время, так как этот ответ был обновлен, и я многому научился, как разработчик, так как я спросил и ответил на этот вопрос. Он также получил гораздо больше внимания, чем я думал. Я хочу предоставить лучшее решение, чем оригинальное, которое я разместил, которое не полагается на устаревшие методы jQuery или вообще jQuery. Не могли бы вы использовать jQuery, чтобы помочь вам? Конечно, но если вы можете добиться того же результата без jQuery и использовать обнаружение функции вместо того, чтобы обнюхивать браузер, почему бы вам не так? Итак, ниже мой обновленный ответ:

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

document.onclick = function(e) {    
    if (e.target.className === 'click') {
        SelectText('selectme');
    }
};
<div id="selectme"><p>Some text goes here!</p><p>Moar text!</p></div>
<p class="click">Click me!</p>

Вот обновленная рабочая демонстрация. Для тех из вас, кто ищет плагин jQuery, я сделал один из них тоже (обновлено снова).

ОБНОВЛЕНО (1/10/2012) Предложение Per Tim Down setBaseAndExtent() не требуется для webkit.

ОБНОВЛЕНО (9/19/2014) Встроенный фрагмент кода

  • 0
    Старый, но ... ни одной точки с запятой в простой JS ответ
  • 1
    да, кажется, что кто-то недавно редактировал это. фиксированный
109

Здесь версия без браузера, нюхающая и не полагающаяся на 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);
16

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

Пример 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.
12

Этот поток содержит действительно замечательные вещи. Но я не могу сделать это прямо на этой странице, используя 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.welovestackoverflow",$("div.sidebar"));

   //this throws **security exception**

   r.selectNodeContents(w);
  • 2
    Вам нужно получить элемент из jQuery, так как вы пытаетесь выбрать объект jQuery: var w = $ ("div.welovestackoverflow", $ ("div.sidebar")). Get (0);
  • 0
    не работает ... я получаю сообщение об ошибке "объект не поддерживает этот метод" и выделяет первую строку. я немного покопался и обнаружил, что есть «document.body.createTextRange ()», но тогда «selectNodeContents» не работает .... и это в IE
Показать ещё 1 комментарий
5

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

  • Браузер-нюхание, jQuery или нет не оптимально
  • DRY
  • Не работает в IE8, если родительский элемент obj не поддерживает createTextRange
  • Возможность Chrome использовать setBaseAndExtent должна быть использована (IMO)
  • Не будет выбирать текст, охватывающий несколько элементов DOM (элементы в элементе "selected" ). Другими словами, если вы вызываете selText в div, содержащий несколько элементов span, он не будет выбирать текст каждого из этих элементов. Для меня это был развязкой, YMMV.

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

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 предположил, что все они объявлены вверху. Ok jslint.

Edit Я забыл включить, как связать это с op-кодом:

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

Приветствия

  • 0
    Да, это выглядит для меня властно, хотя кажется правильным. Моя главная проблема в том, что использование нестандартного setBaseAndExtent() только потому, что он существует, кажется мне бессмысленным, когда вы можете просто удалить эту ветку, и все работает так же хорошо и на основе стандартов. Функция обнаружения хороша, но я бы устал от тестирования всего этого довольно быстро.
  • 0
    Ну, @TimDown смысл использования setBaseAndExtent том, что он значительно более эффективен, и даже с добавленным, if statemnent все еще намного больше, чем если бы вы «удалили эту ветвь». Я не очень понимаю комментарий "Я бы устал ..."? Напишите это и забудьте это, единственное, что вам нужно сделать, это вызвать функцию, а не написать ее. :)
Показать ещё 1 комментарий
5

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

$('#el-id').focus().select();
  • 3
    Вы не можете использовать focus() для не входных данных, о чем этот вопрос.
  • 4
    но вы можете использовать его на элементе textarea - что я и решил найти здесь. Я виноват в том, что не прочитал вопрос до конца.
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

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

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

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

2

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

1

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

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

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

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

range.moveToElementText(text);

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

range.moveToElementText(el);

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

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

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

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

Если startNode является node типа Текст, Комментарий или CDATASection, то startOffset - это количество символов с начала startNode. Для других типов node startOffset - это число дочерних узлов между началом startNode.

Text node - это первый дочерний элемент node элемента 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);

Другая соответствующая документация:
Range
Selection
Document.createRange()
Window.getSelection()

0

Добавлен jQuery.browser.webkit в "else if" для Chrome. Не удалось заставить это работать в Chrome 23.

Сделал это script ниже для выбора содержимого в теге <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 );
        }
    } );
} );
0

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

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

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

  • 4
    Я не пытаюсь выделить текст в стиле CSS. Я хочу, чтобы текст был выбран.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню