【问题标题】:Keyboard navigation: how to go to the next and previous element with arrow keys?键盘导航:如何使用箭头键转到下一个和上一个元素?
【发布时间】:2012-02-27 01:30:59
【问题描述】:

我正在尝试构建一个带有键盘导航的网站。我希望用户能够使用左右箭头浏览五或六页的菜单。 无论用户在哪个页面上,我都希望他/她在按下左/右箭头时在菜单中后退/前进。

假设水平菜单是这样构建的:
[首页 / 随机页面 / 某页 / 另一页 / 以此类推]

显然它不起作用。这是我到目前为止所拥有的:

document.onkeyup = KeyCheck;       

var pages = ["index.php", "random-page.php", "some-page.php", "another-page.php", "and-so-on.php"];

function leftarrowpressed() {
    location.href = pages[0]-1;
}

function rightarrowpressed() {
    location.href = pages[0]+1;
    }
} 

function KeyCheck(e)
    {
       var KeyID = (window.event) ? event.keyCode : e.keyCode;

       switch(KeyID)
       {

 // left arrow key
         case 37:
         leftarrowpressed()    
          break;

//  right arrow key
          case 39:
          rightarrowpressed() 
          break;

       }
    }

感谢大家的帮助。

【问题讨论】:

    标签: javascript arrays keyboard navigation


    【解决方案1】:

    pages[0]-1 将评估为"index.php"-1,即NaN。您不想从页面 URL 中减去 1(您基本上不能从字符串中减去)-而是从索引中减去 1 以获得上一页。另外,请注意界限:

    location.href = pages[ Math.max(0, 0 - 1) ];
    

    和:

    location.href = pages[ Math.min(pages.length - 1, 0 + 1) ];
    

    我猜你会自动将0 替换为当前页面的索引。

    其次,您似乎在rightarrowpressed 中有一个无关的}

    【讨论】:

    • 这非常快。你是对的,我忘了说明它给了我一个 NaN 错误。好吧,它似乎有效,但只有一次。如果我第二次按右箭头,它不会做任何事情。
    • "我猜你会自动将 0 替换为当前页面的索引。" >> 我该怎么做?
    • @Macxim:我假设您在每个页面上都有这段代码,在index.php 上,您在random-page.php1 上都有这段代码s 等,以便使用random-page.php 上的左箭头导航到index.php
    • 实际上,我在我调用的外部 script.js 文件和正文的末尾有这段代码。你的代码很轻。我不知道 JKing 的代码还是你的代码更好。你们俩怎么看?
    【解决方案2】:

    好的,我查看了您的网站并稍微修改/扩展了我的代码,以尝试(几乎)实现我认为您想要做的事情。我将不修改另一个答案,因为它显示了这样做可能是更好的方法......这个解决方案相当hack-y,只是说明这个概念的一种方式。

    要查看它,请转到您的任何页面(博客页面除外),然后打开 webkit 检查器(我的代码只能在 WebKit(chrome/safari) 中工作,尽管让它在其中工作真的很容易)任何浏览器)并在 javascript 控制台中输入以下内容:

        document.querySelector("footer").setAttribute("style","position:fixed;bottom:0px;width:100%;");
        document.querySelector("header").setAttribute("style","position:fixed;top:0px;width:100%;");
    
        var pages           =       ["accueil","references","cv","contact","aide","blog"],
        classNames          =       ["accueil","ref","cv","contact","aide","blog"],
        pageUrls            =       ["","references.php","cv.php","contact.php","aide.php","blog/"]
        baseUrl             =       "http://maximelaforet.com/",
        currentPageIndex    =       pageUrls.indexOf(window.location.href.replace(baseUrl,"")),
        pageDivs            =       [1,1,1,1,1,1];
    
        pageDivs[currentPageIndex] = document.querySelector("div.content");
        pageDivs[currentPageIndex].id = pages[currentPageIndex]+"Page";
        pageDivs[currentPageIndex].setAttribute("style","-webkit-transition:all 1s ease-in-out;position:fixed;top:63px;width:100%;height:"+(window.innerHeight - 270)+"px;overflow:scroll;");
    
        for (var i=0; i<pageUrls.length;i++)
        {
            if (i!=currentPageIndex)
            {
                var pageGrabber = new XMLHttpRequest();
                pageGrabber.open("GET","http://maximelaforet.com/" + pageUrls[i], false);
                pageGrabber.send(null);
    
                if (pageGrabber.status==200)
                {
                    var temp = document.createElement("div");
                    temp.innerHTML = pageGrabber.response;
    
                    if (pages[i]!="blog")
                    pageDivs[i] = temp.querySelector("div.content").cloneNode(true);
                    else
                    pageDivs[i] = temp.querySelector("div#page").cloneNode(true);
                }
    
                pageDivs[i].id = pages[i]+"Page";
                pageDivs[i].setAttribute("style","-webkit-transition:-webkit-transform 1s ease-in-out;position:fixed;top:63px;width:100%;height:"+(window.innerHeight - 270)+"px;overflow:scroll;");
                if (i<currentPageIndex)
                pageDivs[i].style.webkitTransform = "translate3d(-100%,0,0)";
                else
                pageDivs[i].style.webkitTransform = "translate3d(100%,0,0)";
    
                document.body.appendChild(pageDivs[i]);
            }
        }
    
        window.addEventListener("keyup", KeyCheck, true);
        function KeyCheck(e)
        {
            e.preventDefault();
            e.stopPropagation();
            var KeyID = (window.event) ? event.keyCode : e.keyCode;
    
            switch(KeyID)
            {
                // left arrow key
                case 37:
                if (currentPageIndex == 0)//we're at the first page, go to the last
                currentPageIndex = pages.length - 1;//-1 to account for first index being "0"
                else//go to the previous page
                pageDivs[currentPageIndex].style.webkitTransform = "translate3d(100%,0,0)";
                pageDivs[currentPageIndex-1].style.webkitTransform = "translate3d(0,0,0)";
                document.querySelector("header").classList.remove(classNames[currentPageIndex]);
                document.querySelector("header").classList.add(classNames[currentPageIndex-1]);
    
                if (classNames[currentPageIndex] == "accueil")
                document.querySelector("li > a[class~='"+classNames[currentPageIndex]+"']").classList.toggle("current_acc");
                else
                document.querySelector("li > a[class~='"+classNames[currentPageIndex]+"']").classList.toggle("current_"+classNames[currentPageIndex]);
                if (classNames[currentPageIndex] == "accueil")
                document.querySelector("li > a[class~='"+classNames[currentPageIndex-1]+"']").classList.toggle("current_acc");
                else
                document.querySelector("li > a[class~='"+classNames[currentPageIndex-1]+"']").classList.toggle("current_"+classNames[currentPageIndex-1]);
    
                currentPageIndex--;
                break;
                //  right arrow key
                case 39:
                if (currentPageIndex == (pages.length - 1))//if we're at the last page, go to the first
                currentPageIndex = 0;
                else//go to the next page
                pageDivs[currentPageIndex].style.webkitTransform = "translate3d(-100%,0,0)";
                pageDivs[currentPageIndex+1].style.webkitTransform = "translate3d(0,0,0)";
    
                document.querySelector("header").classList.remove(classNames[currentPageIndex]);
                document.querySelector("header").classList.add(classNames[currentPageIndex+1]);
    
                if (classNames[currentPageIndex] == "accueil")
                document.querySelector("li > a[class~='"+classNames[currentPageIndex]+"']").classList.toggle("current_acc");
                else
                document.querySelector("li > a[class~='"+classNames[currentPageIndex]+"']").classList.toggle("current_"+classNames[currentPageIndex]);
                if (classNames[currentPageIndex] == "accueil")
                document.querySelector("li > a[class~='"+classNames[currentPageIndex+1]+"']").classList.toggle("current_acc");
                else
                document.querySelector("li > a[class~='"+classNames[currentPageIndex+1]+"']").classList.toggle("current_"+classNames[currentPageIndex+1]);
    
                currentPageIndex++;
                break;
                default:
                var noChange = true;//just so we can ignore the rest if a boring key
            }
    
        }
    

    但请记住,这是一种非常老套的方法,但它应该为您指明正确的方向。如果您还有其他问题,请告诉我。

    【讨论】:

    • 您的解决方案确实令人印象深刻。谢谢!但是,我相信当您查看我的网站时,您在下面看到了@pimvbd 解决方案的结果。你怎么看呢?它是否减少了 HTTP 请求和刷新的数量?每一页都有那段JS不是很糟糕吗?此外,他的解决方案适用于所有浏览器。
    • 他的解决方案将在每次用户切换到新页面时执行 HTTP 请求并刷新页面,并且每个页面上需要(略微)不同的代码。我在此处提供的解决方案将预先执行一些 HTTP 请求,但从不刷新页面,并且可以从每个页面使用相同的代码。理想的解决方案是将所有页面合并为一个,并使用与此类似的解决方案。这样你只需要一个 HTTP 请求,并且永远不需要刷新。 (另外,我的解决方案很容易在每个浏览器中运行。比如,最多 5 到 10 分钟即可使其运行。)
    【解决方案3】:

    嗯,在我看来,您每次都需要知道您当前在哪个页面上才能正常工作。为此,如果(且仅当)A)所有页面都来自同一个域,并且 B)您不需要支持较旧的浏览器,我会推荐 window.localStorage。如果其中任何一个不正确,则此方法将不起作用,您需要执行其他操作,例如解析 URL 字符串。

    我获取了您的代码并对其稍作修改,以展示您如何使用 localStorage。我添加了一些cmets,但它应该是相对不言自明的。这里是:

    //if current index don't exist, make it
    if (!window.localStorage.currentPageIndex)
    {
        window.localStorage.currentPageIndex = 0;//frustratingly, it gets stringified anyway - you have to parseInt later
    }
    
    //set up vars
    var pages        = ["index.php", "random-page.php", "some-page.php", "another-page.php", "and-so-on.php"],
    currentPageIndex = parseInt(window.localStorage.currentPageIndex);//as promised
    
    //set event listener on window
    window.addEventListener("keyup", KeyCheck);
    function KeyCheck(e)
    {
        var KeyID = (window.event) ? event.keyCode : e.keyCode;
    
        switch(KeyID)
        {
                // left arrow key
            case 37:
                if (currentPageIndex == 0)//we're at the first page, go to the last
                    currentPageIndex = pages.length - 1;//-1 to account for first index being "0"
                else//go to the previous page
                    currentPageIndex--;   
                break;
                //  right arrow key
            case 39:
                if (currentPageIndex == (pages.length - 1))//if we're at the last page, go to the first
                    currentPageIndex = 0;
                else//go to the next page
                    currentPageIndex++;
                break;
            default:
                var noChange = true;//just so we can ignore the rest if a boring key
        }
    
        if (!noChange)//haha, I love double negatives
        {
            //now dump the new current page index back into localStorage
            window.localStorage.currentPageIndex = currentPageIndex;
    
            //first, try it in your javascript console to make sure it works (refresh the page!)
            console.log(pages[currentPageIndex],currentPageIndex);
            //then use real urls and uncomment the next line to go to the new current page!
            //location.href = pages[currentPageIndex]
        }
    }
    

    但是 - 我要问 - 你真的想这样做吗?这是大量的 HTTP 请求并刷新页面 - 页面是否足够小,您可以一次将它们全部加载在一起,并且一次只显示一个? (你甚至可以在页面之间做一个很酷的滑动或疯狂的 3d 效果——再一次,假设你只需要支持更新的浏览器......)

    【讨论】:

    • 如果您在我编辑之前发现了这篇文章,很抱歉 - 它现在可以工作了。我没有尽我所能彻底地尝试过......(现在是周末,这几乎是懒惰的借口!)
    • 我的目的是增强可访问性,提供一种在菜单中导航的替代方式。您可以查看结果here。我也想听听你对这个问题的看法。并审查渲染。这样做是不是一个坏主意?
    猜你喜欢
    • 2012-04-07
    • 2012-11-26
    • 2022-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-22
    • 1970-01-01
    相关资源
    最近更新 更多