Показать сообщение отдельно
  #1 (permalink)  
Старый 09.06.2012, 19:39
Аватар для bes
bes bes вне форума
Профессор
Отправить личное сообщение для bes Посмотреть профиль Найти все сообщения от bes
 
Регистрация: 22.03.2012
Сообщений: 3,744

Скроллинг клавишами и липкие блоки
Решая на чистом js задачу скроллинга клавишами, а также липких блоков из Перемещение блока при скроллинге столкнулся с рядом проблем.
Основа: набор таблиц, в каждой из которой набор строк, в первой ячейке каждой строки произвольное содержимое, вторая ячейка - контейнер для липкого блока.
Липкие блоки: (см ссылку).
Скроллинг: по нажатию символьных клавиш, которые символизируют "вверх" и "вниз" последовательно перемещаться по ячейкам всей совокупности таблиц.

Взял за основу метод document.elementFromPoint(x, y), с помощью которого получаю блок и далее работаю с ним (либо перемещаю к нужной ячейке при скроллинге, либо контролирую положение соответствующего липкого блока).

По скроллингу: перемещения производятся, но в некоторые моменты document.elementFromPoint(x, y) возвращает не нужный блок, а саму таблицу (даже если не учитывать, что специально прокрутили, чтобы попасть в margin между ячейками, тоже пока не соображу как это обойти), хотя вроде бы чётко смещаю при каждом нажатии клавиши левый верхний угол блока в точку, в которой находился первый блок при загрузке страницы.
По липким блокам: задача вроде бы тоже не сложная, но не получается cформировать условия (совладать с координатами, рисование пока не помогает).
Может быть у кого есть соображения на эту тему по моей логике решения (необходимый, на мой взгляд, функционал я включил в код), или может быть альтернативные подходы к решению этих задач.

<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Скроллинг клавишами и липкие блоки</title>
  </head>

<style>
  .menu {
    position: fixed; 
    left: 0%; 
    top: 0%; 
    background: maroon; 
    width: 100%; 
    height: 10%; 
    z-index: 10;
  }

 #content {
    position: absolute;
    left: 0%;
    top: 10%;
 }

 .table {
    position: relative;
    background: gray;
  }

  .left {
    width: 500px;
    background: lightgray;
    border: 1px solid black;
  }

 .right {
    background: gray;
    border: 1px solid black;
    width: 200px;
    vertical-align: top;
  }

  .sticker {
    position: relative;
    background: whitesmoke; 
    height: 100px;    
  }

</style>

<div class="menu"></div>
<div id="content"></div>


<script>
window.onload = function () {//onload begin
  var content = document.getElementById('content'); 

  //код создания таблиц
  var inner = '';
  var str = '';
  for (var i = 0; i < 3; i++) {
    str += '<table class="table">'
    for (var j = 0; j < 3; j++) {
      str += '<tr><td class="left">';
      for (var k = 0; k < 31; k++) {
        inner += 'таблица ' + i + '; строка ' + j + '<br>'; 
      }
      str += inner + '</td><td class="right"><div class="sticker">sticker' + i + ' - ' + j + '</div></td></tr>';
      inner = '';
    }
    str += '</table>'
  }
  content.innerHTML = str;
 

  //функция получения координат элемента (и не только) относительно документа
   var getCoords = function (element) {//getCoords begin
    var elementRect = element.getBoundingClientRect();
    var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft;
    var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
    var clientLeft = document.documentElement.clientLeft || document.body.clientLeft || 0;
    var clientTop = document.documentElement.clientTop || document.body.clientTop || 0;
    var left = elementRect.left + scrollLeft - clientLeft;
    var top  = elementRect.top +  scrollTop - clientTop;

    var obj = {
      left: Math.round(left), top: Math.round(top), 
       scrollTop: Math.round(scrollTop), scrollLeft: Math.round(scrollLeft),
       clientLeft: Math.round(clientLeft), clientTop: Math.round(clientTop)
    }
    return obj;
  }//getCoords end


  //функция получения номера по элементу, если элемент не в коллекции -1
  var getN = function (element, collection) {//getN begin
    for (var i = 0; i < length; i++) {
      if (element == collection[i]) {
        return i
      } 
    }
    return -1;
  }//getN end


  //функция получения элемента по номеру, если нет такого элемента -1
  var getElement = function (n, collection) {//getElement begin
    for (var i = 0; i < length; i++) {
      if (collection[i] == collection[n]) {
        return collection[i];
      }
    }
    return -1;
  }//getElement end


  //необходимые переменные
  var leftBlocks = content.getElementsByClassName('left'); //колллекция блоков слева
  var rightBlocks = content.getElementsByClassName('right');//коллекция блоков справа
  var stickers = content.getElementsByClassName('sticker');//коллекция липких блоков
  var length = leftBlocks.length; // = rightBlocks.length; //= stickers.length;

   var firstLeft = leftBlocks[0]; //первый элемент слева
  //его координаты - точка отсчёта
   var upperBound = getCoords(leftBlocks[0]).top;//верхняя граница
   var leftBound = getCoords(leftBlocks[0]).left; //левая граница

   var lastLeft = leftBlocks[length - 1]; //последний элемент слева
   var lastLeftCoords = getCoords(lastLeft); //его координаты




//скроллинг клавишами++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
  document.onkeyup = function (e) {//onkeyup begin
    var e = e || window.event; //для IE

    //получаем элемент на верхней границе и его параметры
    var element = document.elementFromPoint(leftBound, upperBound);

   /****************************************************
   вот в этих двух функциях getToUp и getToDown не получается заложить 
   необходиму логику решения***********************************/

   var getToUp = function (element) {//getToUp begin
      var n = getN(element, leftBlocks);
      var coords = getCoords(element); 
      if ( n != -1 ) {//если элемент действительно тот //if begin
        //если элемент пересекает верхнюю границу
        if ( coords.top < coords.scrollTop + upperBound ) {
          return element; //возвращаем сам элемент
        } else if ( n != 0 ) {
          return element = getElement(n - 1, leftBlocks);//возвращаем предыдущий элемент, если он не первый
        } 
      } else {//если элемент не тот //if else
        if ( coords.scrollTop > upperBound) {
          return element = firstLeft;//возвращаем первый элемент
        } else {
          return element = lastLeft;//возвращаем последний элемент
        }
      }//if end
  }//getToUp end


    var getToDown = function (element) {//getToDown begin
      var n = getN(element, leftBlocks);
      var coords = getCoords(element); 
      if ( n != -1 ) { //if begin
        if ( coords.top < coords.scrollTop + upperBound &&  n != length ) {
          return element; //возвращаем последующий элемент, если он не последний
        } else {
          return element;//возвращаем сам элемент
        } 
      } else {//if else
        if ( coords.scrollTop > upperBound) {
          //return element = ;
        } else {
         //return element = ;
        }
      }//if end
  }//getToDown end


    //проверяем клавиши и получаем нужный блок
    switch ( e.keyCode ) {
      case 65: {//нажата клавиша "вверх" (Ф, ф - рус., A, a - eng.)
        getToUp (element);
        break;
      }
      case 83: {//нажата клавиша "вниз" (В, в - рус., S, s - eng.)
        getToDown(element);
       break;   
      }
      default: return; //вышли, если не та клавиша
    }//switch end

    //если дошли, то прокрутили страницу, поместив блок в точку остчёта
    window.scrollTo(getCoords(element).left - leftBound, getCoords(element).top - upperBound);

  }//onkeyup end



//липкие блоки+++++++++++++++++++++++++++++++++++++++++

   window.onscroll = function () {//onscroll begin
    //получаем элемент 
    var element = document.elementFromPoint(leftBound, upperBound); 
    //var rect = element.getBoundingClientRect();
    var n = getN(element, leftBlocks); 
    var elementCoords = getCoords(element);//координаты элемента относительно документа
    var elementHeight = element.clientHeight;//высота элемента

    var sticker = getElement(n, stickers);//текущий липкий блок
    var stickerCoords = getCoords(sticker);//координаты липкого блока относительно документа
    var stickerHeight = sticker.clientHeight;//высота липкого блока

    var scroll = elementCoords.scrollTop;//= stickerCoords.scrollTop //величина прокрутки
    var scrollAndUpperBound = scroll + upperBound; //величина прокуртки с учётом верхней границы
    var displacement = scrollAndUpperBound - elementCoords.top; //величина смещения

     //выравнивание по верхней границе
    if ( stickerCoords.top < scrollAndUpperBound || stickerCoords.top  > scrollAndUpperBound)  {
      sticker.style.top = displacement + 'px'; 
    }

    //получение новых координат
    stickerCoords = getCoords(sticker);
    scrollAndUpperBound = stickerCoords.scrollTop + upperBound;
    elementCoords = getCoords(element);
    displacement = scrollAndUpperBound - elementCoords.top;

    //выравнивание по нижней границе
    if ( stickerCoords.top + stickerHeight >= elementCoords.top + elementHeight )  {
      sticker.style.top = elementHeight - stickerHeight + 'px';
    } else if (stickerCoords.top  > scrollAndUpperBound )  {
      sticker.style.top = displacement + 'px'; 
    } 

    if (element != lastLeft) {
      var nextSticker = getElement(n + 1, stickers);
      nextSticker.style.top = '0 px'; 
    }

    if ( element == firstLeft && displacement  == 0 ) {
      sticker.style.top = '0 px'; 
    }
    


  }//onscroll end


}//onload end


</script>
</body>
</html>

Последний раз редактировалось bes, 12.06.2012 в 22:28.
Ответить с цитированием