简体   繁体   中英

javascript find closest element within viewport and scroll to it

带有选项的查看端口在两个选项之间滚动了一半
I have a view-port div which is 48px high and 400px wide. Inside that view-port, I have another div which contains a list of divs. Each of the divs in the list are 48px high and 400px wide. There is obviously an overflow here and the goal is to have it so when the user stops scrolling it will find the closest element to the view-port. My code is below:

javascript, html, and css:

 var i; window.onload = function(){ var timer = null; var optionsScrollTop = 0; var selectLists = document.getElementsByClassName('selectList'); for(i = 0; i != selectLists.length; i++) { var currentElement = i; document.getElementsByClassName('selectList')[currentElement].onmouseover = function() { //alert(currentElement+' mousover'); document.getElementById('contentContainer').style.overflow = 'hidden'; }; document.getElementsByClassName('selectList')[currentElement].onmouseout = function() { //alert(currentElement+' mouseout'); document.getElementById('contentContainer').style.overflow = 'auto'; }; var options = document.getElementsByClassName('selectList')[currentElement].getElementsByClassName('selectListOptions')[0].getElementsByClassName('option'); for(var j = 0; j != options.length; j++) { var oldTitle = ''; options[j].onmouseover = function() { this.parentElement.parentElement.title = this.title; oldTitle = this.title; this.title = ''; }; options[j].onmouseout = function() { this.title = oldTitle; }; } document.getElementsByClassName('selectList')[currentElement].onscroll = function() { if(timer !== null) { clearTimeout(timer); } timer = setTimeout(function(){ var allOptionOffsets = []; var selectViewPortOffset = document.getElementsByClassName('selectList')[currentElement].offsetTop; var options = document.getElementsByClassName('selectList')[currentElement].getElementsByClassName('selectListOptions')[0].getElementsByClassName('option'); for(var i = 0; i != options.length; i++) { allOptionOffsets.push(options[i].offsetTop); //selectViewPortOffset } for(var i = 0; i != allOptionOffsets.length; i++) { alert(allOptionOffsets[i]+' element '+i); alert('viewport offset: '+selectViewPortOffset); if(allOptionOffsets[i] == selectViewPortOffset-24 || allOptionOffsets[i] == selectViewPortOffset+24) { alert(i+' is closest'); } //selectViewPortOffset /*if(allOptionOffsets[i]-selectViewPortOffset > 0) { if(allOptionOffsets[i]-selectViewPortOffset < 48) { document.getElementsByClassName('selectList')[currentElement].scrollTop = allOptionOffsets[i]-selectViewPortOffset; } }*/ //alert(allOptionOffsets[i]); } }, 1000); }; } }; /* var viewPortOffset = document.getElementsByClassName('selectList')[currentElement].offsetTop; var optionsOffset = []; var options = document.getElementsByClassName('selectList')[currentElement].getElementsByClassName('selectListOptions')[0].getElementsByClassName('option'); for(var i = 0; i != options.length; i++) { var optionOffset = document.getElementsByClassName('selectList')[currentElement].getElementsByClassName('selectListOptions')[0].getElementsByClassName('option')[i].offsetTop; optionsOffset.push(optionOffset); } for(var i = 0; i < optionsOffset.length; i++) { alert(optionsOffset[i]); } */ 
 .selectList { width:400px; height:48px; border:2px solid #000; border-radius:5px; overflow:auto; } .selectListOptions { text-align:center; } .selectListOptions .option { font-size:30px; height:48px; text-align:center; border-top:1px solid #000; border-bottom:1px solid #000; -o-box-sizing:border-box; -webkit-box-sizing:border-box; -moz-box-sizing:border-box; -ms-box-sizing:border-box; box-sizing:border-box; } .selectListOptions .label { font-size:30px; height:48px; text-align:center; border-top:1px solid #000; border-bottom:1px solid #000; } 
 <div id="simulatorOfOtherContentThisNormalyWouldn'tBeHere" style="padding:10%"> <div class="selectList" id="incomingMessageSound"> <div class="selectListOptions"> <div class="label option" title='optionDefault'>Incoming Message Sound</div> <div class="option" title='option2'>Sound 1</div> <div class="option" title='option3'>Sound 2</div> <div class="option" title='option4'>Sound 3</div> <div class="option" title='option5'>Sound 4</div> <div class="option" title='option6'>Sound 5</div> </div> </div> </div> 

This should do it if I understood correctly (I used jQuery to save some lines):

function goToClosest(){

    clearTimeout(window.lastTimeout);
    window.lastTimeout = setTimeout(function(){

        var BaseOffset      = $('.selectList').offset().top + 2, // I add 2 because of border top
            ViewrportHeight = $('.selectList').height(),
            ScrollTop       = $('.selectList').scrollTop(),
            distSum         = 0,
            closest,closestDist,closestScrollTop;

        $('.selectListOptions > div').each(function(i,e){

            var e = $(e);
            var distance = Math.abs(e.offset().top - BaseOffset);
            if(!closest || closestDist > distance){
                 closest          = e;
                 closestDist      = distance;
                 closestScrollTop = distSum;
            }

            distSum += e.height() + 2; // Again +2 for border

        });

        $('.selectList').animate({scrollTop:closestScrollTop+'px'},300,'swing');

    },1000);

}

$(document).ready(function(){

    $('.selectList').scroll(goToClosest);

});

Fiddle: https://jsfiddle.net/8d7Ln5mc/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM