Bir öğede metin seçme (farenizle vurgulamaya benzer)


424

Kullanıcıların bir bağlantıyı tıklatmasını istiyorum, daha sonra başka bir öğedeki (metni değil ) HTML metnini seçer .

"Seç" ile fareyi üzerinde sürükleyerek aynı metni seçersiniz. Bu araştırma yapmak için bir ayı oldu çünkü herkes başka bir şekilde "seç" veya "vurgula" dan bahsediyor.

Mümkün mü? Kodum şu ana kadar:

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

Açıkça görünen bir şeyi özlüyor muyum?


Yanıtlar:


613

Düz 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>

İşte çalışan bir demo . Bir jQuery eklentisi arayanlarınız için ben de bunlardan birini yaptım .


jQuery (orijinal cevap)

Bu iş parçacığında bunun için bir çözüm buldum . Verilen bilgileri değiştirebildim ve tarayıcıdan bağımsız olarak herhangi bir öğedeki metni seçmek için tamamen harika bir işlev oluşturmak için jQuery biraz karıştırın:

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 çözümü bana Uncaught TypeError verir: undefined 'msie' özelliği okunamıyor
egmfrs

@egmfrs yea bu cevabın gönderilmesinden bu yana, jquery browserdinleyicilerini kaldırdı .
Jason

127

İşte tarayıcı kokusu olmayan ve jQuery'ye güvenmeyen bir sürüm:

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

a metnini seçmenin herhangi bir yolu var div contentEditable='true'mı?
oldboy

@PrimitiveNom: Bu kod, içerik düzenlenebilir bir öğe üzerinde çalışır, ancak önce odakta olduğundan emin olmanız gerekir.
Tim Down

18

Jason'ın kodu bir iframe içindeki öğeler için kullanılamaz (kapsam pencere ve belgeden farklı olduğu için). Bu sorunu çözdüm ve başka bir jQuery eklentisi (zincirlenebilir) olarak kullanılmak üzere değiştirdim:

Örnek 1: <kod> etiketlerindeki tüm metnin tek tıklamayla seçilmesi ve "seçilmiş" sınıfının eklenmesi:

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

Örnek 2: Düğme tıklandığında, bir Iframe içinde bir öğe seçin:

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

Not: güvenlik hatalarını önlemek için iframe kaynağının aynı etki alanında bulunması gerektiğini unutmayın.

jQuery Eklentisi:

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'da (mevcut sürümler) test ettim. Eski IE sürümlerinde çalışıp çalışmadığından emin değilim (içtenlikle umursamıyorum).


3
$ .browser artık kullanımdan kaldırıldı / kaldırıldı - bunun yeniden yazılması gerekiyor
James McCormack

2
@ JamesMcCormack: evet. Yeniden yazmanın buna değip değmeyeceğinden emin değilim, burada $ .browser içermeyen başka çözümler var.
lepe

16

Bu konu gerçekten harika şeyler içeriyor. Ancak "Güvenlik Hatası" nedeniyle FF 3.5b99 + FireBug kullanarak bu sayfada doğru şekilde yapamıyorum.

Yaşasın !! Bu kod ile tüm sağ kenar çubuğunu seçebildim umarım size yardımcı olur:

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

Not: - gibi jquery seçiciler tarafından döndürülen nesneleri kullanamadım

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

   //this throws **security exception**

   r.selectNodeContents(w);

2
Bir jQuery nesnesi seçmeye çalışırken öğeyi jQuery'den almanız gerekir: var w = $ ("div.welovestackoverflow", $ ("div.sidebar")). Get (0);
Blixt

çalışmıyor ... "nesne bu yöntemi desteklemiyor" hata alıyorum ve ilk satırı vurgulamaktadır. bazı kazma yaptı ve bir "document.body.createTextRange ()" olduğunu bulundu ama sonra "selectNodeContents" çalışmıyor .... ve bu IE
Jason

bulduğun bu iş parçacığı okumak ... inanılmaz ... tüm tarayıcılarda çalışan bu bilgilerden bir işlev oluşturmak mümkün. Çok teşekkür ederim! Benim çözüm gönderildi
Jason

6

Herhangi bir öğenin içeriğini seçmek için aşağıdaki işlevi kullanabilirsiniz:

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

Bu işlev aşağıdaki gibi çağrılabilir:

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

5

Aynı şeyi arıyordum, benim çözümüm şuydu:

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

3
focus()bu soruya ilişkin giriş olmayan bir öğede kullanamazsınız .
Jason

4
ancak bunu bir textarea öğesinde kullanabilirsiniz - bu, buraya gelmeyi düşündüğüm problemdi. Soruyu baştan sona okumadığım için benim hatam.
Auston

4

Lepe'nin cevabını birkaç şey dışında beğendim:

  1. Tarayıcı koklama, jQuery veya no en uygun değil
  2. KURU
  3. Nesnenin üstü createTextRange'ı desteklemiyorsa IE8'de çalışmaz
  4. Chrome'un setBaseAndExtent kullanma yeteneği gerekir (IMO)
  5. Birden fazla DOM öğesine yayılan metin seçilmez ("seçilen" öğedeki öğeler). Aradığınızda Başka bir deyişle selText birden yayılma unsurları içeren bir div, bir edecektir değil bu unsurların her birinin metni seçin. Bu benim için bir anlaşma kırıcıydı YMMV.

İşte benim ilham kaynağımın yanıtını bulmak için başını sallayan bir şey. Eminim bu belki biraz ağır (ve aslında moreso olabilir ama ben kazıyorum) gibi alay edilecektir. Ancak çalışır ve tarayıcı kokusunu önler ve mesele budur .

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

Bu kadar. Gördüğünüz şeylerden bazıları okunabilirlik ve / veya rahatlık içindir. Mac, Opera, Safari, Chrome, Firefox ve IE'nin en son sürümlerinde test edilmiştir. Ayrıca IE8'de test edilmiştir. Ayrıca tipik olarak sadece kod blokları içinde / gerektiğinde değişkenleri bildiririm ama jslint bunların hepsi üst bildirildi önerdi. Tamam jslint.

Düzenle Bu op koduna bağlamak için nasıl dahil unuttum:

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

Şerefe


Evet, doğru görünse de, bu bana ağır geliyor. Benim asıl setBaseAndExtent()sorunum, standart dışı olmanın, sadece o dalı kaldırabildiğinizde ve her şeyin aynı şekilde ve standartlara dayalı bir şekilde çalıştığında anlamsız görünmesi. Özellik algılama güzel ama her şeyi oldukça hızlı bir şekilde test etmekten yorulurdum.
Tim Down

@TimDown kaldıraç noktası setBaseAndExtentönemli ölçüde daha verimli olmasıdır ve eklenen ifstatemnent ile bile "o dalı kaldırmak" daha çok daha fazladır. "Yoruldum .." yorumunu gerçekten anlamıyorum. Bunu yazın ve unutun, yapmanız gereken tek şey fonksiyonu çağırmak değil, fonksiyonu çağırmaktır. :)
Madbreaks

@Madbreaks Eğer setBaseAndExtentdaha fazla performans gösterse şaşırırdım addRange. Neden olsun ki? Diğer yorumum, tüm DOM etkileşimlerine genişletilmiş özellik testi ethosunuzla ilgiliydi: kullanmadan önce her DOM yöntemini ve özelliğini test etmek için çok fazla kod var. Onaylamıyorum; Çizgiyi çizmekten ve kodumda birkaç varsayım daha yapmaktan mutluluk duyuyorum.
Tim Down

4

Chrome'da çalışan güncellenmiş bir sürüm:

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

Herhangi bir etiket için bu kısa ve basit kodla o etiketin içindeki tüm metinler seçilebilir. Tüm etiket alanını sarı renkle vurgulayacak ve tek bir tıklamayla içindeki metni seçecektir.

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 - Bu benim için harika çalışıyor teşekkürler! Kodunuzu bir eklenti dosyasına koydum, sonra her bir ifadeyle birlikte kullandım, böylece bir sayfada birden fazla ön etiket ve birden fazla "Tümünü seç" bağlantılarına sahip olabilirsiniz ve vurgulamak için doğru ön seçimi yapar:

<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

Seçim nesnesine (Gecko motoru) ve TextRange nesnesine (Trident motoru.) Bir göz atın Bu uygulama için çapraz tarayıcı desteği olan herhangi bir JavaScript çerçevesi hakkında bilmiyorum, ama ben de aramadım, bu yüzden jQuery'de bile olabilir.


0

Tim'in yöntemi benim durumum için mükemmel çalışıyor - aşağıdaki ifadeyi değiştirdikten sonra hem IE hem de FF için div içindeki metni seçerek:

range.moveToElementText(text);

Takip ederek:

range.moveToElementText(el);

Div'deki metin, aşağıdaki jQuery işleviyle tıklatılarak seçilir:

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

0

seçilen metni dize biçiminde almak için başka bir basit çözüm, kodunuza bir div öğesi alt öğesi eklemek için bu dizeyi kolayca kullanabilirsiniz:

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

Bu, vurgulanan metni döndürmek içindir, vurgu oluşturmaz.
MKN Web Solutions

0

Benim özel kullanım durumum, görebildiğim kadarıyla, buradaki cevapların hiçbirinde açıklanmayan, düzenlenebilir bir yayılma elemanı içinde bir metin aralığı seçiyordu.

Temel fark, Range.setStart () belgelerinde açıklandığı gibi Text, Rangenesneye bir tür düğümü iletmeniz gerektiğidir :

StartNode, Text, Comment veya CDATASection türünde bir Düğümse , startOffset , startNode öğesinin başlangıcındaki karakter sayısıdır. Diğer Düğüm türleri için startOffset, startNode öğesinin başlangıcı arasındaki alt düğümlerin sayısıdır.

TextDüğüm yüzden, erişim almak için, bir yayılma elemanının ilk çocuğu düğüm childNodes[0]yayılma elemanının. Gerisi diğer cevapların çoğu ile aynıdır.

İşte bir kod örneği:

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

İlgili diğer belgeler:
Aralık
Seçimi
Document.createRange ()
Window.getSelection ()


-1

Eklenen jQuery.browser.webkit"eğer başka" Chrome için için. Bu, Chrome 23'te çalışamadı.

Bu komut dosyasını, içindeki bir <pre>etiketteki içeriği seçmek için yaptım 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 belgelerine göre select():

Eşleşen her öğenin select olayını tetikleyin. Bu, söz konusu select olayına bağlı olan tüm işlevlerin yürütülmesine neden olur ve eşleşen öğeler için tarayıcının varsayılan seçme eylemini çağırır.

select()Bu durumda jQuery'nin neden çalışmadığına dair açıklamanız var .


4
bir css tarzı ile metni vurgulamak için çalışmıyorum. metnin seçilmesini istiyorum.
Jason
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.