Подтвердить что ты не робот

Обнаружение при появлении вертикальной полосы прокрутки окна

Есть ли простое и надежное решение для обнаружения вертикальной полосы прокрутки окна, которое появляется/исчезает?

window.onresize не запускается, когда страница JavaScript DOM-манипуляции становится достаточно высокой для появления полосы прокрутки.

В этом очень похожем сообщении Обнаружение, если на странице есть вертикальная полоса прокрутки описано решение, как определить, присутствует ли полоса прокрутки или нет, но мне нужно знать, когда именно это появляется.

4b9b3361

Ответ 1

Window.onresize не будет работать, потому что окно не изменяет размер.

body.onresize не будет работать, поскольку resize реализуется только для окон и фреймов.

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

Я думаю, что этот основанный на Jquery подход Rick Strahl - лучшее, что вы можете получить: Мониторинг HTML-элементов CSS-изменения в JavaScript он использует функции просмотра браузера, если они доступны, или таймер, если нет. Последний не очень дружелюбен к ресурсам, но, похоже, нет никакого способа обойти его.

Хороший способ сказать полосу прокрутки, как только проблема resize разрешена, находится в этом вопросе, кстати, только в Если вы не ссылаетесь на этот вопрос в своем вопросе.

Ответ 2

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

Идея состоит в том, чтобы добавить невидимый iframe на 100% ширину невидимой страницы и прослушивать события изменения на внутреннем окне. Эти события будут получать изменения не только по размеру внешнего окна, но также при добавлении или удалении полос прокрутки из внешнего окна.

Он запускает регулярное событие изменения размера окна, поэтому он не требует дополнительного кода, если вы уже слушаете изменение размера окна.

Протестировано в IE9 и последней версии Chrome/Firefox - возможно, может быть сделано для работы в старых IE, но мой проект не поддерживает их, поэтому я не пробовал.

https://gist.github.com/OrganicPanda/8222636

Ответ 3

На основе ответа OrganicPanda появилась эта вещь jquery

$('<iframe id="scrollbar-listener"/>').css({
    'position'      : 'fixed',
'width'         : '100%',
'height'        : 0, 
'bottom'        : 0,
'border'        : 0,
'background-color'  : 'transparent'
}).on('load',function() {
    var vsb     = (document.body.scrollHeight > document.body.clientHeight);
    var timer   = null;
    this.contentWindow.addEventListener('resize', function() {
        clearTimeout(timer);
        timer = setTimeout(function() {
            var vsbnew = (document.body.scrollHeight > document.body.clientHeight);
            if (vsbnew) {
                if (!vsb) {
                    $(top.window).trigger('scrollbar',[true]);
                    vsb=true;
                }
            } else {
                if (vsb) {
                    $(top.window).trigger('scrollbar',[false]);
                    vsb=false;
                }
            }
        }, 100);
    });
}).appendTo('body');

Это вызовет события "полосы прокрутки" в окне, если они появятся/исчезнут

Работает на хроме /mac, по крайней мере. теперь кто-то расширяет это для обнаружения горизонтальных полос прокрутки: -)

Ответ 4

Если вы используете AngularJS, вы можете использовать директиву для определения, когда изменяется ширина (при условии, что появляющаяся/исчезающая полоса прокрутки является вертикальной):

app.directive('verticalScroll', function($rootScope){
    return {
        restrict: 'A',
        link: function (scope, element) {
            scope.$watch(
                function() {
                    return element[0].clientWidth;
                },
                function() {
                    $rootScope.$emit('resize');
                }
            );
        }
    }
});

Это вызывает событие в корневой области, которое могут прослушивать другие директивы или контроллеры.

Часы запускаются в цикле angular digest, поэтому это зависит от angular, загрузив/удалив дополнительный контент, из-за которого ваша полоса прокрутки появлялась/исчезала.

Ответ 5

Scoop

Можно обнаружить изменения в видимости полосы прокрутки, используя ResizeObserver, чтобы проверить изменения размера элемента, который может принимать полосы прокрутки и изменения размера его содержимого.

Обоснование

Я начал внедрять решение с помощью метода <iframe>, но быстро обнаружил, что для полной реализации требуется разграничение проблем среди представлений моего приложения. У меня есть родительское представление, которое должно знать, когда дочернее представление приобретает вертикальную полосу прокрутки. (Я не забочусь о горизонтальной полосе прокрутки.) У меня есть две ситуации, которые могут повлиять на видимость вертикальной полосы прокрутки:

  • Изменяется размер родительского представления. Это находится под прямым контролем пользователя.

  • Содержимое дочернего представления становится больше или меньше. Это находится под косвенным контролем пользователя. Представление child показывает результаты поиска. Количество и тип результатов определяют размер детского вида.

Я обнаружил, что если бы я использовал <iframe>, мне пришлось бы гадать с дочерним видом для поддержки родительских потребностей. Я предпочитаю, чтобы ребенок не содержал код для чего-то, что является чисто заботой родителя. С описанным здесь решением необходимо изменить только родительский вид.

Поэтому, пытаясь найти лучшее решение, я нашел этот ответ Даниэлем Херром. Он предлагает использовать ResizeObserver для обнаружения изменений размеров div. ResizeObserver пока недоступен в разных браузерах, но есть надежный ponyfill/polyfill, который я использую для поддержки в тех случаях, когда встроенная поддержка недоступна. (Вот spec для ResizeObserver.)

проверка концепции

Я использую этот polyfill в режиме понижения. Таким образом, глобальная среда остается нетронутой. Эта реализация основывается на window.requestAnimationFrame и будет возвращаться на setTimeout для платформ, которые не поддерживают window.requestAnimationFrame. Глядя на поддержку requestAnimationFrame на "Могу ли я использовать...?", То, что я вижу, меня не беспокоит. YMMV.

У меня есть живой доказательство концепции. Ключ состоит в том, чтобы прослушивать изменения в размере элемента DOM, который может принимать полосы прокрутки (элемент с id container, зеленым цветом) и слушать изменения в размере содержимого, которое может потребоваться для прокрутки (элемент с id content). В доказательстве концепции используется interact.js для управления элементом resizer (с id resizer, синим цветом), который позволяет изменять размер container. Если вы перетащите нижний правый угол resizer, он изменит размер как на resizer, так и на container. Две кнопки позволяют имитировать изменения размера содержимого, отображаемого container.

Я использую этот метод в коде, который в настоящее время находится на этапе предварительного выпуска, то есть он прошел тесты в нескольких браузерах и оценивается заинтересованными сторонами, но пока не находится в производстве.

HTML:

<!DOCTYPE html>
<html>

<head>
  <script data-require="[email protected]*" data-semver="1.0.26" src="//rawgit.com/taye/interact.js/v1.0.26/interact.js"></script>
  <script src="//rawgit.com/que-etc/resize-observer-polyfill/master/dist/ResizeObserver.global.js"></script>
  <link rel="stylesheet" href="style.css" />
</head>

<body>
  <div id="resizer">
    <div id="container">
      <ul id="content">
        <li>Something</li>
      </ul>
    </div>
  </div>
  <button id="add">Add to content</button>
  <button id="remove">Remove from content</button>
  <p>Scroll bar is: <span id="visibility"></span></p>
  <ul id="event-log"></ul>
  <script src="script.js"></script>
</body>

</html>

JavaScript:

var container = document.getElementById("container");
var resizer = document.getElementById("resizer");
interact(resizer)
  .resizable({
    restrict: {
      restriction: {
        left: 0,
        top: 0,
        right: window.innerWidth - 10,
        bottom: window.innerHeight - 10
      }
    }
  })
  .on('resizemove', function(event) {
    var target = resizer;

    var rect = target.getBoundingClientRect();

    var width = rect.width + event.dx;
    var height = rect.height + event.dy;
    target.style.width = width + 'px';
    target.style.height = height + 'px';
  });

var content = document.getElementById("content");
var add = document.getElementById("add");
add.addEventListener("click", function() {
  content.insertAdjacentHTML("beforeend", "<li>Foo</li>");
});

var remove = document.getElementById("remove");
remove.addEventListener("click", function() {
  content.removeChild(content.lastChild);
});

// Here is the code that pertains to the scrollbar visibility

var log = document.getElementById("event-log");
content.addEventListener("scrollbar", function () {
  log.insertAdjacentHTML("beforeend", "<li>Scrollbar changed!</li>");
});

var visiblity = document.getElementById("visibility");
var previouslyVisible;
function refreshVisibility() {
  var visible = container.scrollHeight > container.clientHeight;
  visibility.textContent = visible ? "visible" : "not visible";
  if (visible !== previouslyVisible) {
    content.dispatchEvent(new Event("scrollbar"));
  }
  previouslyVisible = visible;
}
// refreshVisibility();


var ro = new ResizeObserver(refreshVisibility);
ro.observe(container);
ro.observe(content);

CSS:

* {
  box-sizing: border-box;
}

#container {
  position: relative;
  top: 10%;
  left: 10%;
  height: 80%;
  width: 80%;
  background: green;
  overflow: auto;
}

#resizer {
  background: blue;
  height: 200px;
  width: 200px;
}

Ответ 6

Динамическое обнаружение вертикальной полосы прокрутки браузера по Сравнение window.innerWidth с getBoundingClientRect() элемента DIV с использованием Javascript. Протестировано с последними IE FF Chrome. См. Документацию здесь