Làm cách nào để tìm ra phần tử DOM nào có trọng tâm?


1309

Tôi muốn tìm hiểu, trong JavaScript, phần tử nào hiện đang tập trung. Tôi đã xem qua DOM và chưa tìm thấy thứ tôi cần. Có cách nào để làm điều này, và làm thế nào?

Lý do tôi đã tìm kiếm điều này:

Tôi đang cố gắng tạo các phím như mũi tên và enterđiều hướng qua một bảng các yếu tố đầu vào. Tab hoạt động ngay bây giờ, nhưng nhập và mũi tên không theo mặc định. Tôi đã thiết lập phần xử lý khóa nhưng bây giờ tôi cần tìm ra cách chuyển trọng tâm trong các chức năng xử lý sự kiện.


2
Đây là một bookmarklet mà console.log phần tử có tiêu điểm: github.com/lingtalfi/where-is-f
ling

Bạn có thể sử dụng find-focused-elementgói: npmjs.com/package/find-focused-element
Maxim Zhukov

Câu trả lời:


1533

Sử dụng document.activeElement, nó được hỗ trợ trong tất cả các trình duyệt chính.

Trước đây, nếu bạn đang cố gắng tìm hiểu trường mẫu nào có trọng tâm, bạn không thể. Để mô phỏng phát hiện trong các trình duyệt cũ hơn, hãy thêm trình xử lý sự kiện "tập trung" vào tất cả các trường và ghi lại trường tập trung cuối cùng vào một biến. Thêm một trình xử lý "làm mờ" để xóa biến khi có sự kiện mờ cho trường tập trung cuối cùng.

Nếu bạn cần loại bỏ, activeElementbạn có thể sử dụng mờ; document.activeElement.blur(). Nó sẽ thay đổi activeElementthành body.

Liên kết liên quan:


53
Không chắc chắn về IE, nhưng FF và Safari đều trả về phần tử BODY.
JW.

10
activeElementthực sự không trả về yếu tố tập trung. Bất kỳ yếu tố có thể có trọng tâm. Nếu một tài liệu có 4 'scrolldivs', 0 hoặc 1 trong số các div đó có thể cuộn bằng các phím mũi tên. Nếu bạn bấm vào một, div đó được tập trung. Nếu bạn nhấp vào bên ngoài tất cả, cơ thể được tập trung. Làm thế nào để bạn tìm ra scrolldiv được tập trung? jsfiddle.net/rudiedirkx/bC5ke/show (kiểm tra bảng điều khiển)
Rudie

18
@Rudie, @Stewart: Tôi đã xây dựng trên fiddle của bạn để tạo ra một sân chơi phức tạp hơn: jsfiddle.net/mkuity/72rTF . Bạn sẽ thấy rằng các chỉ trình duyệt lớn (tính đến cuối năm 2012) mà thực sự có thể tập trung một ví dụ divlà Firefox 17, và chỉ bằng cách tabbing với nó. Các loại phần tử mà TẤT CẢ các trình duyệt chính trả về document.activeElementđược giới hạn ở các phần tử liên quan đến đầu vào . Nếu không có phần tử nào như vậy có trọng tâm, tất cả các trình duyệt chính sẽ trả về bodyphần tử - ngoại trừ IE 9, htmlphần tử trả về phần tử.
mkuity0

10
Không chắc chắn nếu nó giúp, nhưng bạn có thể tạo một yếu tố như div nhận bàn phím tập trung bằng cách bao gồm thuộc tính tabindex = "0"
Marco Luglio

4
Bất kỳ quyền truy cập nào document.activeElementcũng phải được gói gọn trong một try catchsố trường hợp, nó có thể đưa ra một ngoại lệ (không chỉ IE9 AFAIK). Xem bugs.jquery.com/ticket/13393bugs.jqueryui.com/ticket/8443
robocat

127

Như JW đã nói, bạn không thể tìm thấy yếu tố tập trung hiện tại, ít nhất là theo cách độc lập với trình duyệt. Nhưng nếu ứng dụng của bạn chỉ có IE (một số là ...), bạn có thể tìm thấy nó theo cách sau:

document.activeElement

EDIT: Dường như IE không có gì sai cả, đây là một phần của dự thảo HTML5 và dường như được hỗ trợ bởi phiên bản mới nhất của Chrome, Safari và Firefox.


5
FF3 cũng vậy. Đây thực sự là một phần của thông số HTML5 xung quanh "quản lý tập trung".
Lưỡi liềm tươi

2
Nó hoạt động trong phiên bản hiện tại của Chrome và Opera (9.62). Không hoạt động trong Safari 3.2.3 trên OS X, nhưng nó hoạt động trong Safari 4 đã được phát hành ngày hôm qua :)
gregers

vẫn như vậy đối với chrome 19: S
Sebas

1
Nó chỉ hoạt động trong chrome (20) / safari (5.1.3) khi bạn sử dụng bàn phím để tab vào phần tử. Nếu bạn nhấp vào nó thì cả bộ chọn jquery: Focus cũng như document.activeEuity đều thành công trong việc trả về những gì bạn đã nhấp vào (trả lại phần tử cơ thể không xác định và phần tử tài liệu tương ứng). PS Tôi không thể tin rằng chủ đề này đã được 2 năm và vẫn còn vấn đề hồi quy trên webkit, cùng với đó là các liên kết bỏ qua không hoạt động, nhưng rất nhiều công việc đang được thực hiện với việc thêm css3 thử nghiệm. Nghĩ rằng tôi có thể quay lại để giới thiệu firefox cho gia đình và bạn bè của tôi.
Bình minh

^^ document.activeEuity vẫn ổn khi bạn nhấp để tập trung vào một vùng văn bản hoặc đầu vào khác. Nếu đó là một liên kết, nó sẽ không tập trung khi nhấp vào (trong trang hoặc rõ ràng là khác).
marksyzm

84

Nếu bạn có thể sử dụng jQuery, giờ đây nó hỗ trợ: tập trung, chỉ cần đảm bảo bạn đang sử dụng phiên bản 1.6+.

Tuyên bố này sẽ giúp bạn có được yếu tố hiện đang tập trung.

$(":focus")

Từ: Cách chọn một phần tử tập trung vào nó với jQuery


4
Điều này là tốt, nhưng jQuery làm điều đó như thế nào? document.activeEuity? Tôi tìm thấy cái này: return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
Harry Pehkonen

46

document.activeElementhiện là một phần của đặc tả dự thảo làm việc HTML5 , nhưng nó có thể chưa được hỗ trợ trong một số trình duyệt không chính / di động / cũ hơn. Bạn có thể quay lại querySelector(nếu điều đó được hỗ trợ). Điều đáng nói là nó document.activeElementsẽ trở lại document.bodynếu không có phần tử nào được tập trung - ngay cả khi cửa sổ trình duyệt không có tiêu điểm.

Các mã sau đây sẽ giải quyết vấn đề này và quay lại querySelectorhỗ trợ tốt hơn một chút.

var focused = document.activeElement;
if (!focused || focused == document.body)
    focused = null;
else if (document.querySelector)
    focused = document.querySelector(":focus");

Một điều bổ sung cần lưu ý là sự khác biệt hiệu suất giữa hai phương pháp này. Truy vấn tài liệu bằng bộ chọn sẽ luôn chậm hơn nhiều so với truy cập thuộc activeElementtính. Xem thử nghiệm jsperf.com này .


21

Chính nó, document.activeElementvẫn có thể trả về một phần tử nếu tài liệu không được tập trung (và do đó không có gì trong tài liệu được tập trung!)

Bạn có thể muốn hành vi đó, hoặc nó có thể không quan trọng (ví dụ trong một keydownsự kiện), nhưng nếu bạn cần biết điều gì đó thực sự tập trung, bạn có thể kiểm tra thêm document.hasFocus().

Sau đây sẽ cung cấp cho bạn các yếu tố tập trung nếu có một, hoặc khác null.

var focused_element = null;
if (
    document.hasFocus() &&
    document.activeElement !== document.body &&
    document.activeElement !== document.documentElement
) {
    focused_element = document.activeElement;
}

Để kiểm tra xem một yếu tố cụ thể có tập trung hay không, nó đơn giản hơn:

var input_focused = document.activeElement === input && document.hasFocus();

Để kiểm tra xem mọi thứ có tập trung hay không, nó lại phức tạp hơn:

var anything_is_focused = (
    document.hasFocus() &&
    document.activeElement !== null &&
    document.activeElement !== document.body &&
    document.activeElement !== document.documentElement
);

Tính mạnh mẽ Lưu ý : Trong mã nơi kiểm tra document.bodydocument.documentElementđiều này là do một số trình duyệt trả về một trong những trình duyệt này hoặc nullkhi không có gì được tập trung.

Nó không giải thích nếu <body>(hoặc có thể <html>) có tabIndexthuộc tính và do đó thực sự có thể được tập trung . Nếu bạn đang viết một thư viện hoặc một cái gì đó và muốn nó mạnh mẽ, có lẽ bạn nên xử lý bằng cách nào đó.


Dưới đây là một ( nặng airquotes) phiên bản "one-liner" nhận được các yếu tố tập trung, đó là khái niệm phức tạp hơn bởi vì bạn phải biết về ngắn mạch, và cậu biết đấy, nó rõ ràng là không phù hợp trên cùng một dòng, giả sử bạn muốn nó có thể đọc được.
Tôi sẽ không đề nghị cái này. Nhưng nếu bạn là 1337 hax0r, idk ... nó ở đó.
Bạn cũng có thể loại bỏ || nullphần này nếu bạn không bận tâm đến falsemột số trường hợp. (Bạn vẫn có thể nhận được nullnếu document.activeElementnull):

var focused_element = (
    document.hasFocus() &&
    document.activeElement !== document.body &&
    document.activeElement !== document.documentElement &&
    document.activeElement
) || null;

Để kiểm tra xem một yếu tố cụ thể có được tập trung hay không, ngoài ra, bạn có thể sử dụng các sự kiện, nhưng cách này yêu cầu thiết lập (và có khả năng phá vỡ), và quan trọng là, giả sử trạng thái ban đầu :

var input_focused = false;
input.addEventListener("focus", function() {
    input_focused = true;
});
input.addEventListener("blur", function() {
    input_focused = false;
});

Bạn có thể khắc phục giả định trạng thái ban đầu bằng cách sử dụng cách không có sự kiện, nhưng sau đó bạn cũng có thể chỉ sử dụng cách đó.


15

document.activeElementcó thể mặc định cho <body>phần tử nếu không có phần tử có thể lấy nét được lấy nét. Ngoài ra, nếu một phần tử được tập trung và cửa sổ trình duyệt bị mờ, activeElementsẽ tiếp tục giữ phần tử được tập trung.

Nếu một trong hai hành vi này không được mong muốn, hãy xem xét cách tiếp cận dựa trên CSS : document.querySelector( ':focus' ).


Thật tuyệt, có trong trường hợp của tôi cách tiếp cận của bạn có ý nghĩa tuyệt đối. Tôi có thể đặt các yếu tố có thể tập trung của mình bằng 'tabindex = "- 1"', nếu không có phần nào trong số chúng có tiêu điểm (giả sử, một số văn bản hoặc hình ảnh mà tôi không quan tâm) trả về tài liệu.querySelector (': tập trung') vô giá trị.
Manfred

Xem câu trả lời của tôi để tránh sử dụng querySelector: stackoverflow.com/a/40873560/2624876
1j01

10

Tôi thích cách tiếp cận được sử dụng bởi Joel S, nhưng tôi cũng thích sự đơn giản document.activeElement. Tôi đã sử dụng jQuery và kết hợp cả hai. Các trình duyệt cũ hơn không hỗ trợ document.activeElementsẽ sử dụng jQuery.data()để lưu trữ giá trị của 'hasF Focus'. Các trình duyệt mới hơn sẽ sử dụng document.activeElement. Tôi cho rằng document.activeElementsẽ có hiệu suất tốt hơn.

(function($) {
var settings;
$.fn.focusTracker = function(options) {
    settings = $.extend({}, $.focusTracker.defaults, options);

    if (!document.activeElement) {
        this.each(function() {
            var $this = $(this).data('hasFocus', false);

            $this.focus(function(event) {
                $this.data('hasFocus', true);
            });
            $this.blur(function(event) {
                $this.data('hasFocus', false);
            });
        });
    }
    return this;
};

$.fn.hasFocus = function() {
    if (this.length === 0) { return false; }
    if (document.activeElement) {
        return this.get(0) === document.activeElement;
    }
    return this.data('hasFocus');
};

$.focusTracker = {
    defaults: {
        context: 'body'
    },
    focusedElement: function(context) {
        var focused;
        if (!context) { context = settings.context; }
        if (document.activeElement) {
            if ($(document.activeElement).closest(context).length > 0) {
                focused = document.activeElement;
            }
        } else {
            $(':visible:enabled', context).each(function() {
                if ($(this).data('hasFocus')) {
                    focused = this;
                    return false;
                }
            });
        }
        return $(focused);
    }
};
})(jQuery);

3
Điều này có thể được thay thế bởi @William Denniss $("*:focus")không?
Pylinux

Tôi cho rằng nó có thể. Tôi đã viết điều này từ lâu và chưa bao giờ có lý do để xem xét lại một giải pháp tốt hơn bây giờ là 5 năm sau. Hãy thử nó! Tôi có thể làm như vậy. Tôi ít plugin trên trang web của chúng tôi! :)
Jason

10

Một người trợ giúp nhỏ mà tôi đã sử dụng cho các mục đích này trong Mootools:

FocusTracker = {
    startFocusTracking: function() {
       this.store('hasFocus', false);
       this.addEvent('focus', function() { this.store('hasFocus', true); });
       this.addEvent('blur', function() { this.store('hasFocus', false); });
    },

    hasFocus: function() {
       return this.retrieve('hasFocus');
    }
}

Element.implement(FocusTracker);

Bằng cách này, bạn có thể kiểm tra xem phần tử có tập trung với el.hasFocus()điều kiện startFocusTracking()đã được gọi trên phần tử đã cho hay không.


7

JQuery không hỗ trợ lớp :focusgiả như hiện tại. Nếu bạn đang tìm kiếm nó trong tài liệu JQuery, hãy kiểm tra bên dưới "Bộ chọn" nơi nó trỏ bạn đến các tài liệu CSS của W3C . Tôi đã thử nghiệm với Chrome, FF và IE 7+. Lưu ý rằng để nó hoạt động trong IE, <!DOCTYPE...phải tồn tại trên trang html. Dưới đây là một ví dụ giả sử bạn đã gán id cho phần tử có trọng tâm:

$(":focus").each(function() {
  alert($(this).attr("id") + " has focus!");
});

1
Bạn nên (luôn luôn?) Sử dụng this.idthay vì $(this).attr('id')hoặc ít nhất (khi bạn đã có đối tượng jQuery của mình) $(this)[0].id. Javascript bản địa ở cấp độ này là CÁCH nhanh hơn và hiệu quả hơn. Có thể không đáng chú ý trong trường hợp này, nhưng toàn hệ thống bạn sẽ nhận thấy một sự khác biệt.
Martijn

7

Nếu bạn muốn lấy một đối tượng là thể hiện của Element, bạn phải sử dụng document.activeElement, nhưng nếu bạn muốn lấy một đối tượng là thể hiện của Text, bạn phải sử dụng document.getSelection().focusNode.

Tôi hy vọng sẽ giúp.


Tốt hơn theo cách nào?
1j01

Mở trình kiểm tra trình duyệt của bạn, nhấp vào bất kỳ vị trí nào của trang, qua mục này document.getSelection().focusNode.parentElementvà nhấn Enter. Sau đó, quá khứ document.activeElementvà làm điều đó lấy mẫu. ;)
rplaurindo

Với hộp bình luận này được tập trung, document.activeElementđưa ra <textarea>trong khi document.getSelection().focusNodeđưa ra <td>cái chứa <textarea>(và document.getSelection().focusNode.parentElementđưa ra cái <tr>chứa <td>)
1j01

Xin lỗi, tôi xin lỗi. Tôi đã không giải thích nó tốt. Nếu bạn muốn lấy một đối tượng là thể hiện của Element, bạn phải sử dụng document.activeElement, nhưng nếu bạn muốn lấy một đối tượng là thể hiện của Text, bạn phải sử dụng document.getSelection().focusNode. Xin vui lòng, kiểm tra lại. Tôi mong tôi đã giúp đỡ được.
rplaurindo

2
Câu hỏi là hỏi về yếu tố nào hiện đang tập trung. Và focusNodekhông được đảm bảo là một nút văn bản.
1j01

6

Có những vấn đề tiềm ẩn khi sử dụng document.activeEuity. Xem xét:

<div contentEditable="true">
  <div>Some text</div>
  <div>Some text</div>
  <div>Some text</div>
</div>

Nếu người dùng tập trung vào div bên trong, thì document.activeEuity vẫn tham chiếu div bên ngoài. Bạn không thể sử dụng document.activeEuity để xác định div nào bên trong có tiêu điểm.

Hàm sau giải quyết vấn đề này và trả về nút tập trung:

function active_node(){
  return window.getSelection().anchorNode;
}

Nếu bạn muốn có được yếu tố tập trung, hãy sử dụng:

function active_element(){
  var anchor = window.getSelection().anchorNode;
  if(anchor.nodeType == 3){
        return anchor.parentNode;
  }else if(anchor.nodeType == 1){
        return anchor;
  }
}

3
Đó thực sự không phải là vấn đề với document.activeElement: các <div>yếu tố bên trong thực sự không thể nhận được trọng tâm, vì bạn có thể thấy trực quan bằng cách đặt lớp :focusgiả thành thứ gì đó có thể nhìn thấy (ví dụ: jsfiddle.net/4gasa1t2/1 ). Những gì bạn đang nói là cái nào bên trong <div>chứa lựa chọn hoặc dấu mũ, đây là một vấn đề riêng biệt.
Tim Down

6

Tôi đã tìm thấy đoạn mã sau hữu ích khi cố gắng xác định phần tử nào hiện đang tập trung. Sao chép phần sau vào bảng điều khiển của trình duyệt của bạn và mỗi giây nó sẽ in ra các chi tiết của phần tử hiện tại có tiêu điểm.

setInterval(function() { console.log(document.querySelector(":focus")); }, 1000);

Vui lòng sửa đổi console.logđể đăng xuất một cái gì đó khác nhau để giúp bạn xác định chính xác thành phần nếu việc in ra toàn bộ thành phần không giúp bạn xác định chính xác yếu tố đó.


5

Đọc các câu trả lời khác và tự mình thử, dường như nó document.activeElementsẽ cung cấp cho bạn yếu tố bạn cần trong hầu hết các trình duyệt.

Nếu bạn có một trình duyệt không hỗ trợ document.activeEuity nếu bạn có jQuery, bạn sẽ có thể đưa nó vào tất cả các sự kiện tập trung với một thứ rất đơn giản như thế này (chưa được kiểm tra vì tôi không có trình duyệt đáp ứng các tiêu chí đó ):

if (typeof document.activeElement === 'undefined') { // Check browser doesn't do it anyway
  $('*').live('focus', function () { // Attach to all focus events using .live()
    document.activeElement = this; // Set activeElement to the element that has been focussed
  });
}

5

Nếu bạn đang sử dụng jQuery, bạn có thể sử dụng điều này để tìm hiểu xem một phần tử có hoạt động không:

$("input#id").is(":active");


3

Chỉ cần đặt nó ở đây để đưa ra giải pháp cuối cùng tôi đã đưa ra.

Tôi đã tạo một thuộc tính có tên document.activeInputArea và sử dụng addon HotKeys của jQuery để bẫy các sự kiện bàn phím cho các phím mũi tên, tab và nhập và tôi đã tạo một trình xử lý sự kiện để nhấp vào các phần tử đầu vào.

Sau đó, tôi đã điều chỉnh activeInputArea mỗi khi thay đổi tiêu điểm, vì vậy tôi có thể sử dụng thuộc tính đó để tìm ra vị trí của mình.

Mặc dù vậy, thật dễ dàng để khắc phục điều này, bởi vì nếu bạn có một lỗi trong hệ thống và tiêu điểm không phải là nơi bạn nghĩ, thì rất khó để khôi phục lại tiêu điểm chính xác.

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.