Chọn văn bản trong một yếu tố (gần giống với tô sáng bằng chuột của bạn)


424

Tôi muốn người dùng nhấp vào một liên kết, sau đó nó chọn văn bản HTML trong một yếu tố khác ( không phải đầu vào).

Bằng cách "chọn" Tôi có nghĩa giống như cách bạn sẽ chọn văn bản bằng cách kéo chuột trên đó. Điều này đã được một nghiên cứu bởi vì tất cả mọi người nói về "chọn" hoặc "nổi bật" trong các điều khoản khác.

Điều này có thể không? Mã của tôi cho đến nay:

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

Tôi có thiếu một cái gì đó rõ ràng rõ ràng?


Câu trả lời:


611

Javascript đơn giản

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>

Đây là một bản demo làm việc . Đối với những bạn đang tìm kiếm một plugin jQuery, tôi cũng đã tạo một trong số đó .


jQuery (câu trả lời gốc)

Tôi đã tìm thấy một giải pháp cho điều này trong chủ đề này . Tôi đã có thể sửa đổi thông tin được cung cấp và trộn nó với một chút jQuery để tạo ra một chức năng hoàn toàn tuyệt vời để chọn văn bản trong bất kỳ yếu tố nào, bất kể trình duyệt:

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

Giải pháp jQuery mang lại cho tôi Uncaught TypeError: Không thể đọc thuộc tính 'msie' không xác định
egmfrs

@egmfrs yea kể từ khi câu trả lời này được đăng, jquery đã gỡ bỏ browsersniffer của họ .
Jason

127

Đây là phiên bản không có trình duyệt đánh hơi và không phụ thuộc vào 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);

Có cách nào để chọn văn bản của a div contentEditable='true'?
oldboy

@PrimitiveNom: Mã này sẽ hoạt động trên một yếu tố có thể nội dung được nhưng bạn sẽ phải đảm bảo nó có trọng tâm trước.
Tim Down

18

Mã của Jason không thể được sử dụng cho các phần tử bên trong iframe (vì phạm vi khác với cửa sổ và tài liệu). Tôi đã khắc phục vấn đề đó và tôi đã sửa đổi nó để được sử dụng như bất kỳ plugin jQuery nào khác (có thể xâu chuỗi):

Ví dụ 1: Lựa chọn tất cả văn bản bên trong các thẻ <code> chỉ với một cú nhấp chuột và thêm lớp "được chọn":

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

Ví dụ 2: Khi nhấp vào nút, chọn một yếu tố bên trong Iframe:

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

Lưu ý: hãy nhớ rằng nguồn iframe phải nằm trong cùng một miền để tránh lỗi bảo mật.

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

Tôi đã thử nghiệm nó trong IE8, Firefox, Opera, Safari, Chrome (phiên bản hiện tại). Tôi không chắc nếu nó hoạt động trong các phiên bản IE cũ hơn (chân thành tôi không quan tâm).


3
$ .browser hiện không được chấp nhận / bị xóa - điều này cần viết lại
James McCormack

2
@JamesMcCormack: có. Tôi không chắc chắn nếu viết lại nó sẽ có giá trị vì có những giải pháp khác được đăng ở đây không liên quan đến $ .browser.
lepe

16

Đây chủ đề chứa công cụ thực sự tuyệt vời. Nhưng tôi không thể làm điều đó ngay trên trang này bằng FF 3.5b99 + FireBug do "Lỗi bảo mật".

Yipee !! Tôi đã có thể chọn toàn bộ thanh bên tay phải với mã này hy vọng nó sẽ giúp bạn:

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

PS: - Tôi không thể sử dụng các đối tượng được trả về bởi các bộ chọn jquery như

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

   //this throws **security exception**

   r.selectNodeContents(w);

2
Bạn cần lấy phần tử từ jQuery, vì bạn đang cố gắng chọn một đối tượng jQuery: var w = $ ("div.welovestackoverflow", $ ("div.sidebar")). Get (0);
Blixt

không hoạt động ... tôi gặp lỗi "đối tượng không hỗ trợ phương thức này" và nó làm nổi bật dòng đầu tiên. tôi đã thực hiện một số hoạt động đào và thấy rằng có một "document.body.createTextRange ()" nhưng sau đó "selectNodeContents" không hoạt động .... và đây là trong IE
Jason

Tôi đọc chủ đề mà bạn thấy ... thật tuyệt vời ... tôi đã có thể tạo một chức năng từ thông tin đó hoạt động trên tất cả các trình duyệt. Cảm ơn bạn rất nhiều! Giải pháp của tôi được đăng
Jason

6

Bạn có thể sử dụng chức năng sau để chọn nội dung của bất kỳ yếu tố nào:

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

Hàm này có thể được gọi như sau:

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

5

Tôi đã tìm kiếm điều tương tự, giải pháp của tôi là:

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

3
bạn không thể sử dụng focus()cho mục đích không nhập, đó là câu hỏi này.
Jason

4
nhưng bạn có thể sử dụng nó trên một yếu tố textarea - đó là vấn đề tôi đã tìm đến đây. Lỗi của tôi vì đã không đọc hết câu hỏi.
Auston

4

Tôi thích câu trả lời của lepe ngoại trừ một vài điều:

  1. Trình duyệt đánh hơi, jQuery hoặc không tối ưu
  2. KHÔ
  3. Không hoạt động trong IE8 nếu cha mẹ của obj không hỗ trợ createdTextRange
  4. Khả năng sử dụng setBaseAndExtent của Chrome cần được tận dụng (IMO)
  5. Sẽ không chọn văn bản trải dài trên nhiều phần tử DOM (các phần tử trong phần tử "được chọn"). Nói cách khác, nếu bạn gọi selText trên div chứa nhiều phần tử span, nó sẽ không chọn văn bản của từng phần tử đó. Đó là một công cụ đối phó với tôi, YMMV.

Đây là những gì tôi nghĩ ra, với một cái gật đầu để trả lời cho cảm hứng. Tôi chắc chắn tôi sẽ bị chế giễu vì điều này có lẽ hơi nặng tay (và thực sự có thể là moreso nhưng tôi lạc đề). Nhưng nó hoạt động và tránh trình duyệt đánh hơi và đó là điểm chính .

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

Đó là nó. Một số trong những gì bạn thấy là dễ đọc và / hoặc thuận tiện. Đã thử nghiệm trên Mac trong các phiên bản mới nhất của Opera, Safari, Chrome, Firefox và IE. Cũng được thử nghiệm trong IE8. Ngoài ra, tôi thường chỉ khai báo các biến nếu / khi cần bên trong các khối mã nhưng jslint đề nghị tất cả chúng được khai báo lên trên cùng. Ok jslint.

Chỉnh sửa Tôi quên bao gồm cách gắn mã này vào mã của op:

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

Chúc mừng


Vâng, điều đó có vẻ nặng tay với tôi, mặc dù nó có vẻ đúng. Nắm bắt chính của tôi là việc sử dụng phi tiêu chuẩn setBaseAndExtent()chỉ vì nó tồn tại đối với tôi khi bạn có thể loại bỏ chi nhánh đó và mọi thứ hoạt động tốt và theo cách dựa trên tiêu chuẩn. Phát hiện tính năng là tốt nhưng tôi cảm thấy mệt mỏi khi thử nghiệm mọi thứ một cách triệt để khá nhanh.
Tim Down

Chà @TimDown điểm của đòn bẩy setBaseAndExtentlà nó hiệu quả hơn đáng kể và ngay cả khi có thêm ifstentnent vẫn còn nhiều hơn so với khi bạn "loại bỏ chi nhánh" đó. Tôi thực sự không hiểu nhận xét về "Tôi sẽ mệt mỏi .."? Viết nó và quên nó đi, điều duy nhất bạn phải làm là gọi hàm chứ không phải viết nó. :)
Madbreaks

@Madbreaks Tôi sẽ ngạc nhiên nếu setBaseAndExtenthiệu suất cao hơn đáng kể addRange. Tại sao nó sẽ là? Nhận xét khác của tôi liên quan đến các đặc tính thử nghiệm tính năng của bạn được mở rộng cho tất cả các tương tác DOM: đó là rất nhiều mã để kiểm tra mọi phương thức và thuộc tính DOM duy nhất trước khi sử dụng. Tôi không đồng ý; Tôi chỉ vui khi vẽ đường và đưa ra một vài giả định trong mã của mình.
Tim Down

4

Phiên bản cập nhật hoạt động trong 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

Đối với bất kỳ thẻ nào, người ta có thể chọn tất cả văn bản bên trong thẻ đó bằng mã ngắn và đơn giản này. Nó sẽ làm nổi bật toàn bộ khu vực thẻ với màu vàng và chọn văn bản bên trong nó chỉ với một cú nhấp chuột.

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 - Điều đó làm việc tuyệt vời cho tôi cảm ơn! Tôi đặt mã của bạn vào một tệp plugin, sau đó sử dụng nó cùng với mỗi câu lệnh để bạn có thể có nhiều thẻ trước và nhiều liên kết "Chọn tất cả" trên một trang và chọn ra chính xác để làm nổi bật:

<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

Hãy xem đối tượng Lựa chọn (công cụ Gecko) và đối tượng TextRange (Công cụ Trident.) Tôi không biết về bất kỳ khung JavaScript nào có hỗ trợ trình duyệt chéo cho việc này được triển khai, nhưng tôi cũng chưa bao giờ tìm kiếm nó thậm chí có thể có jQuery.


0

Phương pháp của Tim hoạt động hoàn hảo cho trường hợp của tôi - chọn văn bản trong div cho cả IE và FF sau khi tôi thay thế câu lệnh sau:

range.moveToElementText(text);

với những điều sau đây:

range.moveToElementText(el);

Văn bản trong div được chọn bằng cách nhấp vào nó với chức năng jQuery sau:

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

0

Đây là một giải pháp đơn giản khác để lấy văn bản đã chọn ở dạng chuỗi, bạn có thể dễ dàng sử dụng chuỗi này để nối một phần tử div vào mã của mình:

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

Điều này là để trả lại văn bản được tô sáng, không tạo ra một điểm nổi bật.
Giải pháp web MKN

0

Trường hợp sử dụng cụ thể của tôi là chọn một phạm vi văn bản bên trong một phần tử nhịp có thể chỉnh sửa, theo như tôi có thể thấy, không được mô tả trong bất kỳ câu trả lời nào ở đây.

Sự khác biệt chính là bạn phải truyền một nút loại Textcho Rangeđối tượng, như được mô tả trong tài liệu của Range.setStart () :

Nếu startNode là một loại nút Văn bản, Nhận xét hoặc CDATASection , thì startPackset là số lượng ký tự từ đầu startNode. Đối với các loại Node khác, startPackset là số lượng nút con giữa lúc bắt đầu startNode.

Các Textnút là nút con đầu lòng của một phần tử span, vì vậy để có được nó, truy cập childNodes[0]của phần tử span. Phần còn lại giống như trong hầu hết các câu trả lời khác.

Dưới đây là một ví dụ mã:

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

Tài liệu liên quan khác:
Phạm vi
lựa chọn
Document.createRange ()
Window.getSelection ()


-1

Đã thêm vào jQuery.browser.webkit"if if" cho Chrome. Không thể làm việc này trong Chrome 23.

Tạo tập lệnh này bên dưới để chọn nội dung trong <pre>thẻ có 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

Theo tài liệu jQuery của select():

Kích hoạt sự kiện chọn của từng yếu tố phù hợp. Điều này khiến tất cả các chức năng đã bị ràng buộc với sự kiện chọn đó được thực thi và gọi hành động chọn mặc định của trình duyệt trên (các) phần tử phù hợp.

Có lời giải thích của bạn tại sao jQuery select()sẽ không hoạt động trong trường hợp này.


4
Tôi không cố làm nổi bật văn bản với kiểu css. tôi muốn văn bản được chọn.
Jason
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.