开发者

How to lock focus in a specific div using javascript/jquery [duplicate]

开发者 https://www.devze.com 2023-04-13 08:34 出处:网络
This question already has answers here: Keep tabbing within modal pane only (5 answers) Closed 6 years ago.
This question already has answers here: Keep tabbing within modal pane only (5 answers) Closed 6 years ago.

I am developping some kind of modal popup using jQuery and I have some problems with the focus.

What happens right now, is that when I press the tab key, the focus goes to the controls hidden behind the po开发者_高级运维pup.

Is there a way to force the focus to remain only on the controls in the popup window ?


There is. You basically need to listen for when the tab key is pressed, so that you can respond accordingly. Using jQuery, here's the general structure:

$(window).keydown(function(e){
    if(e.which ===9){ //it's the tab key!
        //do whatever you want here.

        e.preventDefault();
    }
});

You put your custom code where I commented do whatever you want here, and finish up by preventing the default action (such as jumping focus to a hidden control) with e.preventDefault;


You could always look into removing the default actions of the tab key, there is a small tutorial on how to do this here.

However, that is for the enter and tab key, but if you also look here, you will see that the tab key is key number 9. So if we alter the code to just remove the default actions of the tab key your line would be something similar to

    if ( key == 9 ) { }

rather than

    if ( key == 3 || key == 9 || key == 13 ) { }

EDIT

Okay, since now you've stated you don't want to prevent the default action of the tab key, but you still wish to stop that key from focusing on elements below the modal window.

The only thing I can think of now is, checking to see if the user is focused on your last field example 1 / example 2 (you would link these to your last input/textarea/checkbox/radio). If so, you could do 1 of 2 things:

1) Use the above code and prevent the default action, thus, stopping the using from focusing on elements below the modal.

OR

2) Focus back on the first field in your modal window, with first_field.focus();

As far as I can see, by sticking with your requirements the second choice is the best option for you.


Finally, I ended up with the following solution:

When the window is opened, I save the tabindexes for all elements not in the popup window inside jQuery.data and I set the focus to the first element of the window.

Then, for all those elements, I set the tabindex to -1 which prevents them from being accessed with the tab key.

When the window is closed, I restore all tabindexes to their previous values.


Try here. Just prevent the user from pressing tab, or you'll have to loop through your fields and set tab indexes on them.


I use a generic on focus event added to all input tags, when the event gets fired I determine the parent div's z-index if it is above a pre-determined threshold (9950 for example) then I allow the focus, if below I prevent focus. To prevent focus I do this by finding a control within the proper div and calling .focus() on that item.

pseudo code below.

$('input').bind('focus', function() 
{ 
 if ($(this).parents('div:first').css('z-index') <  9950) 
 {
    //prevent focus here
    //usually by finding a suitable target and setting focus
   $('input:first', $('.myModalClass')).focus(); 
 }
}); 

ps. Also set the tabindex on the items so that the items within your "modal" window are right after each other in the tab index. just makes things a little cleaner


I had similar problem and created this tiny jQUeryUI plugin. Use it simply (in multiple places on a page if needed) and this will make TAB or shift+TAB iterate only inside of .someGroup wrapper.

$(".someGroup").tabGuard();

More in here and I hope it will help someone:

http://tomaszegiert.seowebsolutions.com.au/tabguard/index.htm


I think I might have a better solution to your problem that doesn't involve disabling tab or having to track/disable other elements. It does require jQueryUI though.

<div id="modalBgCover">
    <div onfocus="$(this).next('div').find(':tabbable').last().focus();" tabindex="0"></div>
    <div id="modal">
        <input id="input1">
        <input id="input2">
    </div>
    <div onfocus="$(this).prev('div').find(':tabbable').first().focus();" tabindex="0"></div>
<div>

What this does is creates two tabbable (but without content, so not visible) divs which take and redirect focus.

Tabbing off the last input and into the bottom div will throw focus back to the first tabbable element inside the modal, and likewise shift+tabbing to the top div will throw focus back to the bottom input in the modal.

The modalBgCover overlays the page with a semitransparent layer, preventing clicks from getting through.


I have implemented mini-framework based on gather knowledge including answers in this post.

It uses JQuery UI.

Improvements are welcome.

Here is framework object:

var TabLim = {};

TabLim.activate = function(el) {
    TabLim.deactivate();

    TabLim._el = el;

    $(window).on('keydown', TabLim._handleTab);

    return TabLim;
};

TabLim.deactivate = function() {
    TabLim._el = null;

    // detach old focus events
    TabLim._detachFocusHandlers();

    TabLim._els = null;
    TabLim._currEl = null;

    $(window).off('keydown', TabLim._handleTab);

    return TabLim;
};

TabLim.setFocus = function(prev) {
    // detach old focus events
    TabLim._detachFocusHandlers();

    // scan for new tabbable elements
    var tabbables = TabLim._el.find(':tabbable');
    TabLim._els = [];

    // wrap elements in jquery
    for ( var i = 0; i < tabbables.length; i++) {
        var el = $(tabbables[i]);
        // set focus listener on each element
        el.on('focusin', TabLim._focusHandler);
        TabLim._els.push(el);
    }

    // determine the index of focused element so we will know who is
    // next/previous to be focused
    var currIdx = 0;
    for ( var i = 0; i < TabLim._els.length; i++) {
        var el = TabLim._els[i];

        // if focus is set already on some element
        if (TabLim._currEl) {
            if (TabLim._currEl === el[0]) {
                currIdx = i;

                prev ? currIdx-- : currIdx++;
                break;
            }

        } else {
            // focus is not set yet.
            // let's set it by attribute "autofocus".
            if (el.attr('autofocus') !== undefined) {
                currIdx = i;
                break;
            }
        }
    }

    if (currIdx < 0) {
        currIdx += TabLim._els.length;
    }
    if (TabLim._els.length) {
        TabLim._els[Math.abs(currIdx % TabLim._els.length)].focus();
    }

    return TabLim;
};

TabLim._handleTab = function(e) {
    if (e.which === 9) {
        e.preventDefault();

        TabLim.setFocus(e.shiftKey);
    }
};

TabLim._focusHandler = function(e) {
    TabLim._currEl = e.currentTarget;
};

TabLim._detachFocusHandlers = function() {
    if (TabLim._els) {
        for ( var i = 0; i < TabLim._els.length; i++) {
            TabLim._els[i].off('focusin', TabLim._focusHandler);
        }
    }
};

How to use it:

1) to activate to limit focus on specific div

TabLim.activate($('.yourDic')).setFocus();

2) to deactivate

TabLim.deactivate();


When you open your modal popup window if your trying to just get the focus on the first input when they initially press the "tab" key then a very simple solution would be to put the focus on the first input in your modal popup window then simply apply a .blur() to that same input. Then when you hit "tab" it will begin the focus on that form.

$("#modalTestInput").focus();
$("#modalTestInput").blur();

If you're trying to remove any ability to focus on the inputs behind the modal popup window then your solution to apply a tabindex = "-1" to the inputs outside of your modal popup is definitely the way to go.

Just thought you may be interested in a simpler solution.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号