43

開始位置と終了位置で示される特定のテキスト範囲を強調表示(cssを適用)したいと思います。テキスト内に無視する必要のある他のタグがある可能性があるため、これは見た目よりも困難です。

例:

<div>abcd<em>efg</em>hij</div>

highlight(2, 6)"cdefタグを削除せずに「」を強調表示する必要があります。

すでにTextRangeオブジェクトを使用しようとしましたが、成功しませんでした。

前もって感謝します!

4

4 に答える 4

69

以下は、特定の要素内の文字オフセットのペアに選択を設定する関数です。<script>これは素朴な実装です: (CSS によって、または要素内にあることによって) 非表示にされる可能性のあるテキストは考慮されず、改行で<style>ブラウザーの不一致 (IE とその他すべて) が発生する可能性があります。折りたたまれた空白の説明はありません (2 つ以上の連続するスペース文字がページ上の 1 つの表示スペースに折りたたまれるなど)。ただし、すべての主要なブラウザーの例では機能します。

他の部分であるハイライトについては、そのために使用することをお勧めしdocument.execCommand()ます。以下の関数を使用して選択を設定し、 を呼び出すことができますdocument.execCommand()。コマンドを機能させるには、IE 以外のブラウザでドキュメントを一時的に編集可能にする必要があります。コードについては、ここで私の回答を参照してください: getSelection & SurroundContents across multiple tags

すべての主要なブラウザーで動作する、すべてを示す jsFiddle の例を次に示します: http://jsfiddle.net/8mdX4/1211/

そして、選択設定コード:

function getTextNodesIn(node) {
    var textNodes = [];
    if (node.nodeType == 3) {
        textNodes.push(node);
    } else {
        var children = node.childNodes;
        for (var i = 0, len = children.length; i < len; ++i) {
            textNodes.push.apply(textNodes, getTextNodesIn(children[i]));
        }
    }
    return textNodes;
}

function setSelectionRange(el, start, end) {
    if (document.createRange && window.getSelection) {
        var range = document.createRange();
        range.selectNodeContents(el);
        var textNodes = getTextNodesIn(el);
        var foundStart = false;
        var charCount = 0, endCharCount;

        for (var i = 0, textNode; textNode = textNodes[i++]; ) {
            endCharCount = charCount + textNode.length;
            if (!foundStart && start >= charCount
                    && (start < endCharCount ||
                    (start == endCharCount && i <= textNodes.length))) {
                range.setStart(textNode, start - charCount);
                foundStart = true;
            }
            if (foundStart && end <= endCharCount) {
                range.setEnd(textNode, end - charCount);
                break;
            }
            charCount = endCharCount;
        }

        var sel = window.getSelection();
        sel.removeAllRanges();
        sel.addRange(range);
    } else if (document.selection && document.body.createTextRange) {
        var textRange = document.body.createTextRange();
        textRange.moveToElementText(el);
        textRange.collapse(true);
        textRange.moveEnd("character", end);
        textRange.moveStart("character", start);
        textRange.select();
    }
}
于 2011-06-05T11:11:08.017 に答える
3

複数の DOM 要素の選択をサポートするこの強力な JavaScript ユーティリティがどのように機能するかを確認できます。

MASHA (Mark & Share の略)を使用すると、Web ページのコンテンツの興味深い部分をマークして共有できます

http://mashajs.com/index_eng.html

GitHub にもありますhttps://github.com/SmartTeleMax/MaSha

Mobile Safari や IE でも動作します。

于 2012-07-06T15:45:23.677 に答える
0

次のソリューションは IE では機能しません。そのためには TextRange オブジェクトなどを適用する必要があります。これは選択を使用してこれを実行するため、通常の場合、HTML を壊すことはありません。次に例を示します。

<div>abcd<span>efg</span>hij</div>

highlight(3,6);

出力:

<div>abc<em>d<span>ef</span></em><span>g</span>hij</div>

スパン外の最初の文字を にラップし、em次に 内の残りの文字spanを新しいものにラップする方法に注意してください。文字 3 で開き、文字 6 で終了する場合、次のような無効なマークアップが表示されます。

<div>abc<em>d<span>ef</em>g</span>hij</div>

コード:

var r = document.createRange();
var s = window.getSelection()

r.selectNode($('div')[0]);
s.removeAllRanges();
s.addRange(r);

// not quite sure why firefox has problems with this
if ($.browser.webkit) {
    s.modify("move", "backward", "documentboundary");
}

function highlight(start,end){
    for(var st=0;st<start;st++){
        s.modify("move", "forward", "character");
    }

    for(var st=0;st<(end-start);st++){
        s.modify("extend", "forward", "character");
    }
}

highlight(2,6);

var ra = s.getRangeAt(0);
var newNode = document.createElement("em");
newNode.appendChild(ra.extractContents()); 
ra.insertNode(newNode);

例: http://jsfiddle.net/niklasvh/4NDb9/

編集少なくとも私のFF4にはいくつかの問題があったようです

s.modify("move", "backward", "documentboundary");

同時に、それがなくても機能するように見えるので、変更しました

if ($.browser.webkit) {
        s.modify("move", "backward", "documentboundary");
}

edit Tim が指摘したように、modify は FF4 以降でのみ利用可能です。そのため、ブラウザーとの互換性をもう少し高めることを期待して、modify メソッドを必要としない選択を取得する別のアプローチを取りました (IE にはまだ独自の解決)。

コード:

var r = document.createRange();
var s = window.getSelection()

var pos = 0;

function dig(el){
    $(el).contents().each(function(i,e){
        if (e.nodeType==1){
            // not a textnode
         dig(e);   
        }else{
            if (pos<start){
               if (pos+e.length>=start){
                range.setStart(e, start-pos);
               }
            }

            if (pos<end){
               if (pos+e.length>=end){
                range.setEnd(e, end-pos);
               }
            }            

            pos = pos+e.length;
        }
    });  
}
var start,end, range;

function highlight(element,st,en){
    range = document.createRange();
    start = st;
    end = en;
    dig(element);
    s.addRange(range);

}
highlight($('div'),3,6);

var ra = s.getRangeAt(0);

var newNode = document.createElement("em");
newNode.appendChild(ra.extractContents()); 
ra.insertNode(newNode);

例: http://jsfiddle.net/niklasvh/4NDb9/

于 2011-06-05T00:43:10.463 に答える