Scrolling inner div on key down and up

前端 未结 5 1866
你的背包
你的背包 2021-02-05 20:37

I have build an autocomplete container which displays the first four results and the rest are hidden and can be seen when scrolling the inner div element which holds all the res

相关标签:
5条回答
  • 2021-02-05 20:47

    Two years passed... just in case someone stumbles over this, like me. In addition to the last two lines in Moobs answer (can't do any comments yet...), plain Javascript:

    (Left out: how to get elements in pure JS), then:

    $innerDiv.scrollTop = $hoveredElement.offsetTop - $innerDiv.clientHeight;

    There also seems to be no need to "reset" scrollTop to zero before assigning the new value

    0 讨论(0)
  • 2021-02-05 20:55

    Recently I faced the same problem and solved it by using .emphasized textscrollIntoView(), sample code is below. Example of two function respectively for up arrow key and down arrow key

    moveUp: function(e) {
            if (current > 0) {
                current--;
                var allNOdes = document.getElementById('list').childNodes;
                e.stopPropagation();
                if (allNOdes[current]) {
                    allNOdes[current].scrollIntoView(true);
                }
            }
        },
        moveDown: function(e) {
            if (current <  10) {
                current++;
                var allNOdes = document.getElementById('list').childNodes;
                e.stopPropagation();
                if (allNOdes[current]) {
                    allNOdes[current].scrollIntoView(true);
                }
            }
        }
    

    Initially define current as 0 HTML:

    <div class="wrapper">
     <div class="result" id="list">
       <div>1</div>
       <div>2</div>
       <div>3</div>
       <div>4</div>
     </div>
    </div>
    

    CSS:

    .wrapper{
        position: relative;
        height: 150px;
        width: 100px;
        overflow: hidden;
    }
    
    .result{
        position: absolute;
    }
    
    0 讨论(0)
  • 2021-02-05 20:57

    By using tabIndex="-1" attribute on each of the children of a container, the browser will automatically scroll the container to have the child with the current focus in-view.

    Demo (vanilla javascript):

    var listElm = document.querySelector('ul')
    
    // Mark first list item
    listElm.firstElementChild.focus()
    
    // Event listener
    window.addEventListener('keydown', onKeyDown)
    
    // Event callback
    function onKeyDown(e){
      e.preventDefault()
      
      var selectedElm = document.activeElement,
          goToStart,
          // map actions to event's key
          action = {ArrowUp:"previous", Up:"previous", ArrowDown:"next", Down:"next"}
    
      selectedElm = selectedElm[action[e.key] + "ElementSibling"];
    
      // loop if top/bottom edges reached or "home"/"end" keys clicked
      if( !selectedElm || e.key == 'Home' || e.key == 'End' ){
        goToStart = action[e.key] == "next" || e.key == 'Home'
        selectedElm = listElm.children[goToStart ? 0 : listElm.children.length - 1]
      }
      
      selectedElm.focus()
    }
    ul{ 
      list-style: none; 
      border    : 1px solid silver; 
      max-height: 170px;
      padding   : 0;
      margin    : 0;
      scroll-behavior: smooth; /* nice smooth movement */
      overflow  : hidden;      /* set to hidden by OP's request */
    }
    
    li{ padding:.5em; margin:0; }
    li:focus{ background:LIGHTSALMON; outline:none; }
    <ul>
      <li tabIndex="-1">item 1</li>
      <li tabIndex="-1">item 2</li>
      <li tabIndex="-1">item 3</li>
      <li tabIndex="-1">item 4</li>
      <li tabIndex="-1">item 5</li>
      <li tabIndex="-1">item 6</li>
      <li tabIndex="-1">item 7</li>
      <li tabIndex="-1">item 8</li>
      <li tabIndex="-1">item 9</li>
      <li tabIndex="-1">item 10</li>
      <li tabIndex="-1">item 11</li>
      <li tabIndex="-1">item 12</li>
      <li tabIndex="-1">item 13</li>
      <li tabIndex="-1">item 14</li>
      <li tabIndex="-1">item 15</li>
    </ul>

    To make this list accessible (ARIA) read this

    0 讨论(0)
  • 2021-02-05 20:58

    You can update your script to find the relative position of the selected element and scroll to it:

    $(".someInput").on("keyup", function(e) {
       $(".wrapper").show(); 
        if (e.which == 40) {
            $('.element:not(:last-child).element-hover').removeClass('element-hover').next().addClass('element-hover');
        } else if (e.which == 38) {
            $('.element:not(:first-child).element-hover').removeClass('element-hover').prev().addClass('element-hover');    
        }
        //scroll to element:
        $(".wrapper .inner_div").scrollTop(0);//set to top
        $(".wrapper .inner_div").scrollTop($('.element-hover:first').offset().top-$(".wrapper .inner_div").height());//then set equal to the position of the selected element minus the height of scrolling div
    });
    

    http://jsfiddle.net/kMzR9/3/

    0 讨论(0)
  • 2021-02-05 21:13

    There are several ways to implement it. and the exact solution for you need to consider your context.

    Anyway, one possible solution is to use in the container div 'position: relative' and in the inner div (which hold the content) use 'position: absolute' and 'top: 0px'. When user press on the up/down arrows you changing the top property accordingly.

    CSS:

    .container {
        position: relative;
        height: 50px;
        width: 200px;
        overflow: hidden;
        border: 1px solid blue;
    }
    
    .content {
        position: absolute;
        top: 0px;
    }
    

    JavaScript:

    function moveContent(px) {
        var top = $('.content').position().top;
        $(".content").css("top", top+px);
    }
    
    $(document).keydown(function(e){
        if (e.keyCode == 38) { 
           moveContent(-5);
        }
        if (e.keyCode == 40) { 
           moveContent(5);
        }
    });
    

    HTML:

    <div class="container">
        <div class="content">
            hello 1<br/>
            hello 2<br/>
            hello 3<br/>
            hello 4<br/>
            hello 5<br/>
            hello 6<br/>
        </div>
    </div>
    

    See my example in: http://jsfiddle.net/Kq2Qq/3/

    0 讨论(0)
提交回复
热议问题