Menggunakan jQuery untuk menguji apakah input memiliki fokus

561

Di halaman depan situs yang saya bangun, beberapa orang <div>menggunakan CSS :hoverpseudo-class untuk menambahkan batas ketika mouse berada di atasnya. Salah satu dari <div>s mengandung <form>yang, menggunakan jQuery, akan menjaga perbatasan jika input di dalamnya memiliki fokus. Ini berfungsi dengan baik kecuali bahwa IE6 tidak mendukung :hoverelemen apa pun selain <a>s. Jadi, untuk browser ini saja kami menggunakan jQuery untuk meniru CSS :hovermenggunakan $(#element).hover()metode ini. Satu-satunya masalah adalah, sekarang jQuery menangani formulir focus() dan hover() , ketika input memiliki fokus maka pengguna menggerakkan mouse masuk dan keluar, perbatasan hilang.

Saya berpikir kita bisa menggunakan semacam persyaratan untuk menghentikan perilaku ini. Misalnya, jika kami menguji pada mouse out jika ada input yang memiliki fokus, kami dapat menghentikan perbatasan agar tidak hilang. AFAIK, tidak ada :focuspemilih di jQuery, jadi saya tidak yakin bagaimana membuat ini terjadi. Ada ide?

bloudermilk
sumber
1
dapatkah Anda mencoba meringkasnya menjadi beberapa kalimat tentang apa yang diperlukan, dan apa yang saya alami?
mkoryak
Saya pikir Anda perlu melihat dalam menangkap fokus dan mengaburkan acara ( docs.jquery.com/Events/focus dan docs.jquery.com/Events/blur )
Wolfr
Saya mengirim jawaban pada pertanyaan terkait "Apakah ada 'fokus' dalam JavaScript (atau jQuery)?" . Saya telah meningkatkan [pendekatan cletus yang dikutip oleh gnarf] (# 2684561).
luiggitama

Jawaban:

928

jQuery 1.6+

jQuery menambahkan :focuspemilih sehingga kami tidak perlu menambahkannya sendiri. Gunakan saja$("..").is(":focus")

jQuery 1.5 dan di bawah

Sunting: Seiring waktu berubah, kami menemukan metode yang lebih baik untuk menguji fokus, favorit baru adalah inti dari Ben Alman :

jQuery.expr[':'].focus = function( elem ) {
  return elem === document.activeElement && ( elem.type || elem.href );
};

Dikutip dari Mathias Bynens di sini :

Perhatikan bahwa (elem.type || elem.href)tes ditambahkan untuk menyaring positif palsu seperti tubuh. Dengan cara ini, kami memastikan untuk memfilter semua elemen kecuali kontrol bentuk dan hyperlink.

Anda menetapkan pemilih baru. Lihat Plugin / Penulisan . Maka Anda dapat melakukan:

if ($("...").is(":focus")) {
  ...
}

atau:

$("input:focus").doStuff();

JQuery apa saja

Jika Anda hanya ingin mengetahui elemen mana yang memiliki fokus, Anda dapat menggunakannya

$(document.activeElement)

Jika Anda tidak yakin apakah versinya akan 1.6 atau lebih rendah, Anda bisa menambahkan :focuspemilih jika tidak ada:

(function ( $ ) {
    var filters = $.expr[":"];
    if ( !filters.focus ) { 
        filters.focus = function( elem ) {
           return elem === document.activeElement && ( elem.type || elem.href );
        };
    }
})( jQuery );
gnarf
sumber
4
Ini dapat menyebabkan positif palsu. Lihat stackoverflow.com/questions/967096/… untuk informasi lebih lanjut (terima kasih kepada Ben Alman dan Diego Perini).
Mathias Bynens
@Mathias Bynens - Terima kasih atas pembaruannya (Anda lebih dari senang untuk mengedit komunitas ini, jawaban btw!)
gnarf
Bagaimana ketika Anda membutuhkannya untuk bekerja dengan 1,5- dan 1,6? Saya tidak ingin mengganti pemilih fokus jQuery sendiri. Sesuatu seperti if (!jQuery.expr[':'].focus) { /* gist from Ben Alman */ }?
Betamos
@betamos - Tepat sekali ... Saya akan menambahkan sesuatu ke jawaban untuk mencerminkan itu.
gnarf
2
@Alex - Harap berikan pengurangan test case pada jsFiddle yang menunjukkan masalah, karena sejauh yang saya tahu, tidak ada alasan ini seharusnya tidak bekerja pada elemen "dinamis". Saya sebut shenanigans ...
gnarf
46

CSS:

.focus {
    border-color:red;
}

JQuery:

  $(document).ready(function() {

    $('input').blur(function() {
        $('input').removeClass("focus");
      })
      .focus(function() {
        $(this).addClass("focus")
      });
  });
Daniel Moura
sumber
22

Inilah jawaban yang lebih kuat daripada jawaban yang saat ini diterima:

jQuery.expr[':'].focus = function(elem) {
  return elem === document.activeElement && (elem.type || elem.href);
};

Perhatikan bahwa (elem.type || elem.href)tes ditambahkan untuk menyaring seperti positif palsu body. Dengan cara ini, kami memastikan untuk memfilter semua elemen kecuali kontrol bentuk dan hyperlink.

(Diambil dari intisari ini oleh Ben Alman .)

Mathias Bynens
sumber
13

Pembaruan April 2015

Karena pertanyaan ini sudah ada sejak lama, dan beberapa konvensi baru telah ikut bermain, saya merasa bahwa saya harus menyebutkan .livemetode ini telah didepresiasi.

Sebagai gantinya, .onmetode ini sekarang telah diperkenalkan.

Dokumentasi mereka sangat berguna dalam menjelaskan cara kerjanya;

Metode .on () melampirkan penangan acara ke set elemen yang dipilih saat ini di objek jQuery. Pada jQuery 1.7, metode .on () menyediakan semua fungsi yang diperlukan untuk melampirkan penangan acara. Untuk bantuan dalam mengonversi dari metode acara jQuery yang lebih lama, lihat .bind (), .delegate (), dan .live ().

Jadi, agar Anda menargetkan acara 'fokus input', Anda dapat menggunakan ini dalam skrip. Sesuatu seperti:

$('input').on("focus", function(){
   //do some stuff
});

Ini cukup kuat dan bahkan memungkinkan Anda untuk menggunakan kunci TAB juga.

jbutler483
sumber
2

Saya tidak sepenuhnya yakin apa yang Anda cari tetapi ini kedengarannya dapat dicapai dengan menyimpan status elemen input (atau div?) Sebagai variabel:

$('div').each(function(){

    var childInputHasFocus = false;

    $(this).hover(function(){
        if (childInputHasFocus) {
            // do something
        } else { }
    }, function() {
        if (childInputHasFocus) {
            // do something
        } else { }
    });

    $('input', this)
        .focus(function(){
            childInputHasFocus = true;
        })
        .blur(function(){
            childInputHasFocus = false;
        });
});
James
sumber
Inilah yang akhirnya saya lakukan, tetapi saya menggunakan kelas CSS sewenang-wenang daripada variabel javascript global.
bloudermilk
Saya menggunakan variasi ini. Tidak diperlukan plugin jQuery baru. Itu membuatku kemping yang bahagia!
Hari Dennis
1

Alternatif untuk menggunakan kelas untuk menandai keadaan elemen adalah fungsionalitas penyimpanan data internal .

PS: Anda dapat menyimpan boolean dan apa pun yang Anda inginkan menggunakan data()fungsi. Ini bukan hanya tentang string :)

$("...").mouseover(function ()
{
    // store state on element
}).mouseout(function ()
{
    // remove stored state on element
});

Dan kemudian itu hanya masalah mengakses keadaan elemen.

cllpse
sumber
1

Pernahkah Anda berpikir tentang menggunakan mouseOver dan mouseOut untuk mensimulasikan ini. Lihat juga mouseEnter dan mouseLeave

mkoryak
sumber
Pada dasarnya itulah yang saya lakukan dengan hover jQuery. Anda menyediakan dua fungsi, satu untuk mouse masuk dan satu untuk mouse keluar.
bloudermilk
0

Pantau kedua status (melayang, fokus) sebagai bendera benar / salah, dan setiap kali ada perubahan, jalankan fungsi yang menghilangkan batas jika keduanya salah, jika tidak, perlihatkan perbatasan.

Jadi: onfocus set terfokus = benar, set onblur terfokus = salah. set onmouseover hovered = true, set onmouseout hovered = false. Setelah masing-masing peristiwa ini menjalankan fungsi yang menambah / menghilangkan batas.

Blixt
sumber
0

Sejauh yang saya tahu, Anda tidak dapat meminta browser jika ada input di layar yang memiliki fokus, Anda harus mengatur semacam pelacakan fokus.

Saya biasanya memiliki variabel yang disebut "noFocus" dan mengaturnya menjadi true. Lalu saya menambahkan acara fokus ke semua input yang membuat noFocus salah. Lalu saya menambahkan acara blur ke semua input yang mengatur noFocus kembali ke true.

Saya memiliki kelas MooTools yang menangani ini dengan cukup mudah, saya yakin Anda dapat membuat plugin jquery untuk melakukan hal yang sama.

Setelah itu dibuat, Anda bisa melakukan pengecekan noFocus sebelum melakukan pertukaran perbatasan apa pun.

Ryan Florence
sumber
0

Ada plugin untuk memeriksa apakah suatu elemen terfokus: http://plugins.jquery.com/project/focused

$('input').each(function(){
   if ($(this) == $.focused()) {
      $(this).addClass('focused');
   }
})
Murat Çorlu
sumber
1
mengapa menggunakan plugin saat Anda bisa menggunakan jquery inti?
Marcy Sutton
1
Kamu benar. Tapi saya tidak tahu solusi untuk masalah ini pada 2 tahun yang lalu.
Murat Çorlu
0

Saya memiliki acara .live ("fokus") yang diatur untuk memilih () (sorot) isi input teks sehingga pengguna tidak harus memilihnya sebelum mengetik nilai baru.

$ (formObj) .select ();

Karena quirks antara browser yang berbeda, pilih kadang-kadang akan digantikan oleh klik yang menyebabkannya, dan itu akan membatalkan pilihan konten setelah mendukung menempatkan kursor di dalam bidang teks (sebagian besar berfungsi baik di FF tetapi gagal di IE)

Saya pikir saya bisa menyelesaikan ini dengan sedikit menunda pada pilihan ...

setTimeout (function () {$ (formObj) .select ();}, 200);

Ini berfungsi dengan baik dan pilih akan tetap ada, tetapi masalah lucu muncul .. Jika Anda menabrak dari satu bidang ke yang berikutnya, fokus akan beralih ke bidang berikutnya sebelum pemilihan berlangsung. Karena pilih mencuri fokus, fokus kemudian akan kembali dan memicu acara "fokus" baru. Ini berakhir di kaskade input memilih menari di seluruh layar.

Solusi yang bisa diterapkan adalah memeriksa bahwa bidang masih memiliki fokus sebelum mengeksekusi pilih (), tetapi seperti yang disebutkan, tidak ada cara sederhana untuk memeriksa ... Saya akhirnya hanya membuang seluruh sorotan otomatis, daripada membalik apa yang seharusnya pilih jQuery tunggal () panggilan ke fungsi besar yang sarat dengan subrutin ...

Brian
sumber
0

Apa yang akhirnya saya lakukan adalah menciptakan kelas arbitrer yang disebut .elementhasfocus yang ditambahkan dan dihapus dalam fungsi jQuery focus (). Ketika fungsi hover () berjalan saat mouse keluar, ia memeriksa .elementhasfocus:

if(!$("#quotebox").is(".boxhasfocus")) $(this).removeClass("box_border");

Jadi jika tidak memiliki kelas itu (baca: tidak ada elemen dalam div yang memiliki fokus) perbatasan dihapus. Kalau tidak, tidak ada yang terjadi.

bloudermilk
sumber
-2

Sederhana

 <input type="text" /> 



 <script>
     $("input").focusin(function() {

    alert("I am in Focus");

     });
 </script>
Kode Mata-mata
sumber
Itu tidak memberi tahu Anda elemen mana yang saat ini dalam fokus. Disebut ketika elemen baru mendapatkan fokus. Jadi jika suatu elemen sudah memiliki fokus dan Anda ingin tahu apakah 'ini' adalah satu, kode ini tidak berguna.
Alexis Wilke