2016-09-26 2 views
3

Есть ли способ остановить прокрутку контента при изменении размера окна?Сохранять место в содержании при изменении размера окна браузера

Я работаю над отзывчивым веб-сайтом с длинным содержанием формы. Когда окно браузера изменяет размер места читателя в переносимом содержимом. Это приводит к плохому пользовательскому опыту, поскольку они снова должны найти свое место в контенте.

Хорошим примером этого является сайт для начальной загрузки. Попробуйте изменить размер окна рядом с доксом, и после изменения размера вы увидите что-то совершенно другое. http://getbootstrap.com/components/#panels

Mozilla ошибка с 1999 года дело с проблемой я столкнулся #retrobug https://bugzilla.mozilla.org/show_bug.cgi?id=19261

ответ

1

Element.scrollIntoView ваш друг здесь. Вы можете выяснить, какой элемент находится в верхней части окна в ваших тормозных точках (с использованием resize event), и вызвать element.scrollIntoView() на этом элементе.

Вы можете определить, какой элемент находится ближе к вершине с помощью функции, как:

function closestToTop() { 
    const top = window.scrollY; 
    return [].reduce.call(
    document.querySelectorAll('h1, h2, h3'), 
    (closest, el) => Math.abs(offsetTop(el) - top) <= Math.abs(offsetTop(closest) - top) 
     ? el 
     : closest, 
    document.body 
); 
} 

, где вы получите offsetTop с:

function offsetTop(el, offset = 0) { 
    if (el === document.body) { 
    return 0; 
    } 

    return offset + el.offsetTop + offsetTop(el.offsetParent); 
} 

Ограничимся себя к <h1>, <h2> и <h3> элементов, чтобы сделать вычисление немного легче.

Что вы хотите сделать, это выяснить, какой элемент находится наверху в начале изменения размера и прокручивать его, только если он не отображается в конце прокрутки. Таким образом, нам нужно применить какой-то из throttle:

{ 
    let throttling = false; 

    function throttledResize() { 
    if (throttling) { 
     return; 
    } 

    throttling = true; 
    window.dispatchEvent(new CustomEvent('resizeStart')); 
    requestAnimationFrame(() => { 
     window.dispatchEvent(new CustomEvent('resizeEnd')); 
     throttling = false; 
    }); 
    }; 

    window.addEventListener('resize', throttledResize); 
} 

Теперь у нас есть 'resizeStart' и 'resizeEnd' события. Обратите внимание: мы помещаем это в область блока ECMAScript2015, чтобы мы не загрязняли глобальную область с помощью переменных throttling и throttleResize. Теперь мы можем закрыть любой элемент вверху при запуске изменения размера (опять же с использованием области блока).

{ 
    let wasAtTop = null; 

    window.addEventListener('resizeEnd',() => { 
    if (!wasAtTop) { 
     return; 
    } 

    wasAtTop.scrollIntoView(); 
    wasAtTop = null; 
    }); 

    window.addEventListener('resizeStart',() => { 
    wasAtTop = closestToTop(); 
    }); 
} 

Примечание: Это очень не оптимизировано. Существуют различные улучшения, которые мы можем добавить к этому. Подобно дросселю в течение более длительного времени, чем до следующего кадра анимации, и никогда не прокручивайте, если элемент не находится за пределами вида window.scrollY < offsetTop(el) && offsetTop(el) < window.scrollY + window.height.

+0

Спасибо. Это то, что мне интересно. Как я могу определить, какой элемент находится в верхней части окна? – IanEdington

+0

Я отредактировал ответ с дальнейшим попыткой добиться этого. –

1

Трудно сохранить вершину на уровне пикселей точно там, где до изменения размера окна (например, в середине div). Но в качестве обходного пути вы можете использовать некоторые div (например, заголовки разделов) как «привязки»: всякий раз, когда пользователь прокручивает, обнаруживает и отслеживает, какой анкер-анкер находится в настоящее время, и привяжите страницу назад к якорю после изменения размера.

Более конкретно, взять ссылку предоставленную вами в качестве примера: http://getbootstrap.com/components/#panels

Допустим, вы хотите, чтобы все <h1> метки как якоря (вы можете использовать h2 вместо или h1 + h2, в зависимости от того, как детальный контроль вы хотите): var anchorDivs = document.getElementsByTagName("h1");

и как место, чтобы начать (без тестирования каждого углового сценария), я соединял эту функцию, чтобы обнаружить первый якорь DIV в настоящее время в виде:

function getAnchorDiv(anchorDivs) { 
    var viewTop = document.body.scrollTop || document.documentElement.scrollTop; // IE 
    var viewBottom = viewTop + window.innerHeight; 
    var anchorDiv; 
    for (var i = 0; i < anchorDivs.length; i++) { 
     var anchorDiv = anchorDivs[i]; 
     // gets the cumulative offset top of current div 
     var anchorDivTop = anchorDiv.offsetTop; 
     var tempDiv = anchorDiv.offsetParent; 
     while (tempDiv) { 
      anchorDivTop += tempDiv.offsetTop 
      tempDiv= tempDiv.offsetParent; 
     } 
     if (anchorDivTop >= viewTop && anchorDivTop < viewBottom) { 
      // this div is the first one in view 
      break; 
     } else if (anchorDivTop >= viewBottom) { 
      // page view doesn't contain any anchor div, so give the one that's just scrolled over (previous anchor div in the array) 
      anchorDiv = anchorDivs[(i-1) >= 0 ? (i-1) : 0]; 
      break; 
     } 
    } 
    return anchorDiv; 
} 

Когда пользователь прокручивает, обновить якорный DIV:

var anchorDiv = anchorDivs[0]; 
document.onscroll = function() { 
    anchorDiv = getAnchorDiv(anchorDivs); 
} 

И, наконец, на изменение размеров, выделите этот якорь DIV как @ Runar Берг предложил:

window.onresize = function() { 
    anchorDiv.scrollIntoView(); 
}; 

Если просто остаться в местах хэш в URL-адресе вы можете сбросить окно.location.href после изменения размера:

window.onresize = function() { 
    window.location.href = "http://getbootstrap.com/components/#panels"; 
}; 
+0

ty @js. Это работает, когда есть только якорь, на который вы хотите держать людей. Как насчет того, если вы находитесь в другом месте на странице? Думаю, вам придется вести запись о том, где находится ваша страница, и ссылаться на этот вопрос. Есть ли способ отслеживать, где вы находитесь на странице (какой идентификатор вы используете)? – IanEdington

+0

@IanEdington Теперь я вижу вашу точку зрения. Просто обновил свой ответ, и я надеюсь, что это будет полезно. –

+0

Это выглядит великолепно. Я попробую это в эти выходные и дам вам знать, как это происходит! – IanEdington

Смежные вопросы