要素内のテキストの選択(マウスでの強調表示に似ています)


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

明らかに明白な何かが欠けていますか?


回答:


613

プレーン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プラグインを探している人のために、私もそれらの1つを作成しました


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 '14 / 11/19

@PrimitiveNom:このコードはcontenteditable要素で機能しますが、最初にフォーカスがあることを確認する必要があります。
Tim Down、

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は非推奨/削除されました-書き換えが必要です
James McCormack

2
@JamesMcCormack:はい。$ .browserを含まない他の解決策がここに投稿されているので、それを書き換える価値があるかどうかはわかりません。
lepe 2013年

16

このスレッドには本当に素晴らしいものが含まれています。しかし、「セキュリティエラー」のため、FF 3.5b99 + FireBugを使用してこのページで正しく実行することはできません。

イピー!このコードを使用して、右側のサイドバー全体を選択できました。

    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 2009年

動作しません...「オブジェクトはこのメソッドをサポートしていません」というエラーが表示され、最初の行が強調表示されます 調べてみたところ、「document.body.createTextRange()」があるのに「selectNodeContents」が機能しません。これはIEにあります
Jason

私はあなたが見つけたそのスレッドを読みました...すごい...すべてのブラウザで動作するその情報から関数を作成することができました。どうもありがとうございます!私のソリューションが投稿されました
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()非入力では使用できません。これがこの質問に関するものです。
Jason

4
しかし、それをtextarea要素で使用できます-これが私がここに到着するのをググった問題でした。質問を最後まで読んでいないのは私のせいです。
Auston、2011

4

私はいくつかのことを除いて、レペの答えが好きでした:

  1. ブラウザのスニッフィング、jQueryまたはnoは最適ではありません
  2. ドライ
  3. objの親がcreateTextRangeをサポートしていない場合、IE8では機能しません
  4. setBaseAndExtentを使用するChromeの機能を活用する必要があります(IMO)
  5. 複数のDOM要素(「選択された」要素内の要素)にまたがるテキストは選択しません。つまり、複数のスパン要素を含む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;
}

それでおしまい。あなたが見るもののいくつかは読みやすさおよび/または利便性のためです。Opera、Safari、Chrome、Firefox、IEの最新バージョンのMacでテスト済み。IE8でもテスト済み。また、私は通常、コードブロック内で必要な場合にのみ変数を宣言しますが、jslintはすべてを上で宣言することを提案しました。OK jslint。

編集する これをopのコードに結び付ける方法を含めるのを忘れていた:

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

乾杯


ええ、それは正しいように見えますが、私には重厚に見えます。私の主な不満は、非標準setBaseAndExtent()が存在するという理由だけで非標準を使用することは、そのブランチを単に削除でき、すべてが標準ベースの方法で同様に機能するときに無意味に思えることです。機能の検出は優れていますが、すべてを非常に迅速にテストすることにうんざりします。
Tim Down

まあ@TimDownを活用するポイントsetBaseAndExtentは、それが大幅に効率的であることであり、追加されたifステートメンテンスを使用しても、「そのブランチを削除する」場合よりもはるかに多くなります。「疲れちゃう」というコメントがよくわかりませんか?それを書いて忘れてください、あなたがしなければならない唯一のことは、それを書くのではなく、関数を呼び出すことです。:)
Madbreaks、2014年

@MadbreaksがにsetBaseAndExtent比べて大幅にパフォーマンスが良かった場合は、驚きaddRangeます。なぜでしょうか?私のもう1つのコメントは、すべてのDOMインタラクションに拡張された機能テストの考え方に関連していました。使用する前にすべてのDOMメソッドとプロパティをテストするのは非常に多くのコードです。不承認にはしません。線を引いて、コードでさらにいくつかの仮定を行うことができてうれしいです。
Tim Down

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-それは私に感謝します!コードをプラグインファイルに入れ、それをeachステートメントと組み合わせて使用​​して、1つのページに複数の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;               
                    });
        });
  });


1

見てSelectionオブジェクト(Geckoエンジン)とTextRangeのオブジェクトのいずれか、私はこの実装のためのクロスブラウザをサポートしている任意のJavaScriptフレームワークのことは知らないが、私はそれを見たことがありません(トライデントエンジン。)ので、 jQueryにもそれがある可能性があります。


0

Timの方法は私の場合に完全に機能します。次のステートメントを置き換えた後、IEとFFの両方のdiv内のテキストを選択します。

range.moveToElementText(text);

次のように:

range.moveToElementText(el);

div内のテキストは、次のjQuery関数でクリックして選択します。

$(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ソリューション2016

0

私の特定のユースケースは、編集可能なスパン要素内のテキスト範囲を選択することでした。これは、私の知る限り、ここでの回答には記載されていません。

主な違いは、タイプのノードを通過しなければならないことであるTextRange記載されているように、オブジェクト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()


-1

jQuery.browser.webkitChromeの「else if」に追加されました。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()この場合、jQuery が機能しない理由について説明します。


4
私は、CSSスタイルでテキストを強調表示しようとはしていません。テキストを選択します。
ジェイソン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.